1 // script binding functionality
2 
3 enum { VAL_NULL = 0, VAL_INT, VAL_FLOAT, VAL_STR, VAL_ANY, VAL_CODE, VAL_MACRO, VAL_IDENT, VAL_CSTR, VAL_CANY, VAL_WORD, VAL_POP, VAL_COND, VAL_MAX };
4 
5 enum
6 {
7     CODE_START = 0,
8     CODE_OFFSET,
9     CODE_NULL, CODE_TRUE, CODE_FALSE, CODE_NOT,
10     CODE_POP,
11     CODE_ENTER, CODE_ENTER_RESULT,
12     CODE_EXIT, CODE_RESULT_ARG,
13     CODE_VAL, CODE_VALI,
14     CODE_DUP,
15     CODE_MACRO,
16     CODE_BOOL,
17     CODE_BLOCK, CODE_EMPTY,
18     CODE_COMPILE, CODE_COND,
19     CODE_FORCE,
20     CODE_RESULT,
21     CODE_IDENT, CODE_IDENTU, CODE_IDENTARG,
22     CODE_COM, CODE_COMD, CODE_COMC, CODE_COMV,
23     CODE_CONC, CODE_CONCW, CODE_CONCM, CODE_DOWN,
24     CODE_SVAR, CODE_SVARM, CODE_SVAR1,
25     CODE_IVAR, CODE_IVAR1, CODE_IVAR2, CODE_IVAR3,
26     CODE_FVAR, CODE_FVAR1,
27     CODE_LOOKUP, CODE_LOOKUPU, CODE_LOOKUPARG,
28     CODE_LOOKUPM, CODE_LOOKUPMU, CODE_LOOKUPMARG,
29     CODE_ALIAS, CODE_ALIASU, CODE_ALIASARG, CODE_CALL, CODE_CALLU, CODE_CALLARG,
30     CODE_PRINT,
31     CODE_LOCAL,
32     CODE_DO, CODE_DOARGS,
33     CODE_JUMP, CODE_JUMP_TRUE, CODE_JUMP_FALSE, CODE_JUMP_RESULT_TRUE, CODE_JUMP_RESULT_FALSE,
34 
35     CODE_OP_MASK = 0x3F,
36     CODE_RET = 6,
37     CODE_RET_MASK = 0xC0,
38 
39     /* return type flags */
40     RET_NULL   = VAL_NULL<<CODE_RET,
41     RET_STR    = VAL_STR<<CODE_RET,
42     RET_INT    = VAL_INT<<CODE_RET,
43     RET_FLOAT  = VAL_FLOAT<<CODE_RET,
44 };
45 
46 enum { ID_VAR = 0, ID_FVAR, ID_SVAR, ID_COMMAND, ID_ALIAS, ID_LOCAL, ID_DO, ID_DOARGS, ID_IF, ID_RESULT, ID_NOT, ID_AND, ID_OR, ID_MAX };
47 
48 #define VAR_MIN INT_MIN+1
49 #define VAR_MAX INT_MAX-1
50 #define FVAR_MIN -1e6f
51 #define FVAR_MAX 1e6f
52 #define FVAR_NONZERO 1e-6f
53 
54 enum
55 {
56     IDF_INIT = 1<<0, IDF_PERSIST = 1<<1, IDF_READONLY = 1<<2, IDF_REWRITE = 1<<3, IDF_WORLD = 1<<4, IDF_COMPLETE = 1<<5,
57     IDF_TEXTURE = 1<<6, IDF_CLIENT = 1<<7, IDF_SERVER = 1<<8, IDF_HEX = 1<<9, IDF_UNKNOWN = 1<<10, IDF_ARG = 1<<11,
58     IDF_PRELOAD = 1<<12, IDF_GAMEPRELOAD = 1<<13, IDF_GAMEMOD = 1<<14, IDF_NAMECOMPLETE = 1<<15
59 };
60 
61 struct ident;
62 struct identval
63 {
64     union
65     {
66         int i;      // ID_VAR, VAL_INT
67         float f;    // ID_FVAR, VAL_FLOAT
68         char *s;    // ID_SVAR, VAL_STR
69         const uint *code; // VAL_CODE
70         ident *id;  // VAL_IDENT
71         const char *cstr; // VAL_CSTR
72     };
73 };
74 
75 struct tagval : identval
76 {
77     int type;
78 
setinttagval79     void setint(int val) { type = VAL_INT; i = val; }
setfloattagval80     void setfloat(float val) { type = VAL_FLOAT; f = val; }
setnumbertagval81     void setnumber(double val) { i = int(val); if(val == i) type = VAL_INT; else { type = VAL_FLOAT; f = val; } }
setstrtagval82     void setstr(char *val) { type = VAL_STR; s = val; }
setnulltagval83     void setnull() { type = VAL_NULL; i = 0; }
setcodetagval84     void setcode(const uint *val) { type = VAL_CODE; code = val; }
setmacrotagval85     void setmacro(const uint *val) { type = VAL_MACRO; code = val; }
setcstrtagval86     void setcstr(const char *val) { type = VAL_CSTR; cstr = val; }
setidenttagval87     void setident(ident *val) { type = VAL_IDENT; id = val; }
88 
89     const char *getstr() const;
90     int getint() const;
91     float getfloat() const;
92     double getnumber() const;
93     bool getbool() const;
94     void getval(tagval &r) const;
95 
96     void cleanup();
97 };
98 
99 struct identstack
100 {
101     identval val;
102     int valtype;
103     identstack *next;
104 };
105 
106 union identvalptr
107 {
108     void *p;  // ID_*VAR
109     int *i;   // ID_VAR
110     float *f; // ID_FVAR
111     char **s; // ID_SVAR
112 };
113 
114 typedef void (__cdecl *identfun)(ident *id);
115 
116 struct ident
117 {
118     uchar type; // one of ID_* above
119     union
120     {
121         uchar valtype; // ID_ALIAS
122         uchar numargs; // ID_COMMAND
123     };
124     int flags, index, level;
125     const char *name;
126     union
127     {
128         struct // ID_VAR, ID_FVAR, ID_SVAR
129         {
130             union
131             {
132                 struct { int minval, maxval; };     // ID_VAR
133                 struct { float minvalf, maxvalf; }; // ID_FVAR
134             };
135             identvalptr storage;
136             identval overrideval;
137             identval def; // declared-default (by *init.cfg)
138             identval bin; // builtin-default (hard coded or version.cfg)
139         };
140         struct // ID_ALIAS
141         {
142             uint *code;
143             identval val;
144             identstack *stack;
145         };
146         struct // ID_COMMAND
147         {
148             const char *args;
149             uint argmask;
150         };
151     };
152     identfun fun; // ID_VAR, ID_FVAR, ID_SVAR, ID_COMMAND
153     char *desc;
154     vector<char *> fields;
155 
identident156     ident() {}
157     // ID_VAR
158     ident(int t, const char *n, int m, int c, int x, int *s, void *f = NULL, int flags = IDF_COMPLETE, int level = 0)
typeident159         : type(t), flags(flags | ((flags&IDF_HEX && uint(x) == 0xFFFFFFFFU ? uint(m) > uint(x) : m > x) ? IDF_READONLY : 0)), level(level), name(n), minval(m), maxval(x), fun((identfun)f), desc(NULL)
160     { fields.shrink(0); def.i = c; bin.i = c; storage.i = s; }
161     // ID_FVAR
162     ident(int t, const char *n, float m, float c, float x, float *s, void *f = NULL, int flags = IDF_COMPLETE, int level = 0)
typeident163         : type(t), flags(flags | ((flags&IDF_HEX && uint(x) == 0xFFFFFFFFU ? uint(m) > uint(x) : m > x) ? IDF_READONLY : 0)), level(level), name(n), minvalf(m), maxvalf(x), fun((identfun)f), desc(NULL)
164     { fields.shrink(0); def.f = c; bin.f = c; storage.f = s; }
165     // ID_SVAR
166     ident(int t, const char *n, char *c, char **s, void *f = NULL, int flags = IDF_COMPLETE, int level = 0)
typeident167         : type(t), flags(flags), level(level), name(n), fun((identfun)f), desc(NULL)
168     { fields.shrink(0); def.s = c; bin.s = newstring(c); storage.s = s; }
169     // ID_ALIAS
identident170     ident(int t, const char *n, char *a, int flags, int level)
171         : type(t), valtype(VAL_STR), flags(flags), level(level), name(n), code(NULL), stack(NULL), desc(NULL)
172     { fields.shrink(0); val.s = a; }
identident173     ident(int t, const char *n, int a, int flags, int level)
174         : type(t), valtype(VAL_INT), flags(flags), level(level), name(n), code(NULL), stack(NULL), desc(NULL)
175     { fields.shrink(0); val.i = a; }
identident176     ident(int t, const char *n, float a, int flags, int level)
177         : type(t), valtype(VAL_FLOAT), flags(flags), level(level), name(n), code(NULL), stack(NULL), desc(NULL)
178     { fields.shrink(0); val.f = a; }
identident179     ident(int t, const char *n, int flags, int level)
180         : type(t), valtype(VAL_NULL), flags(flags), level(level), name(n), code(NULL), stack(NULL), desc(NULL)
181     { fields.shrink(0); }
identident182     ident(int t, const char *n, const tagval &v, int flags, int level)
183         : type(t), valtype(v.type), flags(flags), level(level), name(n), code(NULL), stack(NULL), desc(NULL)
184     { fields.shrink(0); val = v; }
185     // ID_COMMAND
186     ident(int t, const char *n, const char *args, uint argmask, int numargs, void *f = NULL, int flags = IDF_COMPLETE, int level = 0)
typeident187         : type(t), numargs(numargs), flags(flags), level(level), name(n), args(args), argmask(argmask), fun((identfun)f), desc(NULL)
188     { fields.shrink(0); }
189 
changedident190     void changed() { if(fun) fun(this); }
191 
setvalident192     void setval(const tagval &v)
193     {
194         valtype = v.type;
195         val = v;
196     }
197 
setvalident198     void setval(const identstack &v)
199     {
200         valtype = v.valtype;
201         val = v.val;
202     }
203 
forcenullident204     void forcenull()
205     {
206         if(valtype==VAL_STR) delete[] val.s;
207         valtype = VAL_NULL;
208     }
209 
210     float getfloat() const;
211     int getint() const;
212     double getnumber() const;
213     const char *getstr() const;
214     void getval(tagval &r) const;
215     void getcstr(tagval &v) const;
216     void getcval(tagval &v) const;
217 };
218 
219 extern hashnameset<ident> idents;
220 
221 extern void addident(ident *id);
222 
223 extern tagval *commandret;
224 extern const char *intstr(int v);
225 extern const char *intstr(ident *id);
226 extern void intret(int v);
227 extern const char *floatstr(float v);
228 extern void floatret(float v);
229 extern const char *numberstr(double v);
230 extern void numberret(double v);
231 extern void stringret(char *s);
232 extern void result(tagval &v);
233 extern void result(const char *s);
234 extern char *conc(tagval *v, int n, bool space, const char *prefix, int prefixlen);
235 
conc(tagval * v,int n,bool space)236 static inline char *conc(tagval *v, int n, bool space)
237 {
238     return conc(v, n, space, NULL, 0);
239 }
240 
conc(tagval * v,int n,bool space,const char * prefix)241 static inline char *conc(tagval *v, int n, bool space, const char *prefix)
242 {
243     return conc(v, n, space, prefix, strlen(prefix));
244 }
245 
parseint(const char * s)246 static inline int parseint(const char *s)
247 {
248     return int(strtoul(s, NULL, 0));
249 }
250 
251 #define PARSEFLOAT(name, type) \
252     static inline type parse##name(const char *s) \
253     { \
254         /* not all platforms (windows) can parse hexadecimal integers via strtod */ \
255         char *end; \
256         double val = strtod(s, &end); \
257         return val || end==s || (*end!='x' && *end!='X') ? type(val) : type(parseint(s)); \
258     }
PARSEFLOAT(float,float)259 PARSEFLOAT(float, float)
260 PARSEFLOAT(number, double)
261 
262 static inline void intformat(char *buf, int v, int len = 20) { nformatstring(buf, len, "%d", v); }
263 static inline void floatformat(char *buf, float v, int len = 20) { nformatstring(buf, len, v==int(v) ? "%.1f" : "%.7g", v); }
264 static inline void numberformat(char *buf, double v, int len = 20)
265 {
266     int i = int(v);
267     if(v == i) nformatstring(buf, len, "%d", i);
268     else nformatstring(buf, len, "%.7g", v);
269 }
270 
getstr(const identval & v,int type)271 static inline const char *getstr(const identval &v, int type)
272 {
273     switch(type)
274     {
275         case VAL_STR: case VAL_MACRO: case VAL_CSTR: return v.s;
276         case VAL_INT: return intstr(v.i);
277         case VAL_FLOAT: return floatstr(v.f);
278         default: return "";
279     }
280 }
getstr()281 inline const char *tagval::getstr() const { return ::getstr(*this, type); }
getstr()282 inline const char *ident::getstr() const { return ::getstr(val, valtype); }
283 
284 #define GETNUMBER(name, ret) \
285     static inline ret get##name(const identval &v, int type) \
286     { \
287         switch(type) \
288         { \
289             case VAL_FLOAT: return ret(v.f); \
290             case VAL_INT: return ret(v.i); \
291             case VAL_STR: case VAL_MACRO: case VAL_CSTR: return parse##name(v.s); \
292             default: return ret(0); \
293         } \
294     } \
295     inline ret tagval::get##name() const { return ::get##name(*this, type); } \
296     inline ret ident::get##name() const { return ::get##name(val, valtype); }
GETNUMBER(int,int)297 GETNUMBER(int, int)
298 GETNUMBER(float, float)
299 GETNUMBER(number, double)
300 
301 static inline void getval(const identval &v, int type, tagval &r)
302 {
303     switch(type)
304     {
305         case VAL_STR: case VAL_MACRO: case VAL_CSTR: r.setstr(newstring(v.s)); break;
306         case VAL_INT: r.setint(v.i); break;
307         case VAL_FLOAT: r.setfloat(v.f); break;
308         default: r.setnull(); break;
309     }
310 }
311 
getval(tagval & r)312 inline void tagval::getval(tagval &r) const { ::getval(*this, type, r); }
getval(tagval & r)313 inline void ident::getval(tagval &r) const { ::getval(val, valtype, r); }
314 
getcstr(tagval & v)315 inline void ident::getcstr(tagval &v) const
316 {
317     switch(valtype)
318     {
319         case VAL_MACRO: v.setmacro(val.code); break;
320         case VAL_STR: case VAL_CSTR: v.setcstr(val.s); break;
321         case VAL_INT: v.setstr(newstring(intstr(val.i))); break;
322         case VAL_FLOAT: v.setstr(newstring(floatstr(val.f))); break;
323         default: v.setcstr(""); break;
324     }
325 }
326 
getcval(tagval & v)327 inline void ident::getcval(tagval &v) const
328 {
329     switch(valtype)
330     {
331         case VAL_MACRO: v.setmacro(val.code); break;
332         case VAL_STR: case VAL_CSTR: v.setcstr(val.s); break;
333         case VAL_INT: v.setint(val.i); break;
334         case VAL_FLOAT: v.setfloat(val.f); break;
335         default: v.setnull(); break;
336     }
337 }
338 extern int variable(const char *name, int min, int cur, int max, int *storage, identfun fun, int flags, int level = 0);
339 extern float fvariable(const char *name, float min, float cur, float max, float *storage, identfun fun, int flags, int level = 0);
340 extern char *svariable(const char *name, const char *cur, char **storage, identfun fun, int flags, int level = 0);
341 extern void setvar(const char *name, int i, bool dofunc = false, bool def = false, bool force = false);
342 extern void setfvar(const char *name, float f, bool dofunc = false, bool def = false, bool force = false);
343 extern void setsvar(const char *name, const char *str, bool dofunc = false, bool def = false);
344 extern void setvarchecked(ident *id, int val);
345 extern void setfvarchecked(ident *id, float val);
346 extern void setsvarchecked(ident *id, const char *val);
347 extern void touchvar(const char *name);
348 extern int getvar(const char *name);
349 extern int getvarmin(const char *name);
350 extern int getvarmax(const char *name);
351 extern int getvardef(const char *name, bool rb = false);
352 extern float getfvarmin(const char *name);
353 extern float getfvarmax(const char *name);
354 extern bool identexists(const char *name);
355 extern ident *getident(const char *name);
356 extern ident *newident(const char *name, int flags = 0, int level = 0);
357 extern ident *readident(const char *name);
358 extern ident *writeident(const char *name, int flags = 0, int level = 0);
359 extern bool addcommand(const char *name, identfun fun, const char *args, int type = ID_COMMAND, int flags = IDF_COMPLETE, int levle = 0);
360 
361 extern uint *compilecode(const char *p);
362 extern void keepcode(uint *p);
363 extern void freecode(uint *p);
364 extern void executeret(const uint *code, tagval &result = *commandret);
365 extern void executeret(const char *p, tagval &result = *commandret);
366 extern void executeret(ident *id, tagval *args, int numargs, bool lookup = false, tagval &result = *commandret);
367 extern char *executestr(const uint *code);
368 extern char *executestr(const char *p);
369 extern char *executestr(ident *id, tagval *args, int numargs, bool lookup = false);
370 extern char *execidentstr(const char *name, bool lookup = false);
371 extern int execute(const uint *code);
372 extern int execute(const char *p);
373 extern int execute(const char *p, bool nonworld);
374 extern int execute(ident *id, tagval *args, int numargs, bool lookup = false);
375 extern int execident(const char *name, int noid = 0, bool lookup = false);
376 extern float executefloat(const uint *code);
377 extern float executefloat(const char *p);
378 extern float executefloat(ident *id, tagval *args, int numargs, bool lookup = false);
379 extern float execidentfloat(const char *name, float noid = 0, bool lookup = false);
380 extern bool executebool(const uint *code);
381 extern bool executebool(const char *p);
382 extern bool executebool(ident *id, tagval *args, int numargs, bool lookup = false);
383 extern bool execidentbool(const char *name, bool noid = false, bool lookup = false);
384 enum { EXEC_NOWORLD = 1<<0, EXEC_VERSION = 1<<1, EXEC_BUILTIN = 1<<2 };
385 extern bool execfile(const char *cfgfile, bool msg = true, int flags = 0);
386 extern void alias(const char *name, const char *action, bool world = false);
387 extern void alias(const char *name, tagval &v, bool world = false);
388 extern void worldalias(const char *name, const char *action);
389 extern const char *getalias(const char *name);
390 extern const char *escapestring(const char *s);
391 extern const char *escapeid(const char *s);
escapeid(ident & id)392 static inline const char *escapeid(ident &id) { return escapeid(id.name); }
393 extern bool validateblock(const char *s);
394 extern void explodelist(const char *s, vector<char *> &elems, int limit = -1);
395 extern char *parsetext(const char *&p);
396 extern char *indexlist(const char *s, int pos);
397 extern const char *indexlist(const char *s, int pos, int &len);
398 extern int listincludes(const char *list, const char *needl, int needlelen);
399 extern char *shrinklist(const char *list, const char *limit, int failover = 0, bool invert = false);
400 extern int listlen(const char *s);
401 extern void printreadonly(ident *id);
402 extern void printeditonly(ident *id);
403 extern void printvar(ident *id, int n, const char *str = NULL);
404 extern void printfvar(ident *id, float f, const char *str = NULL);
405 extern void printsvar(ident *id, const char *s, const char *str = NULL);
406 extern void printvar(ident *id);
407 extern int clampvar(ident *id, int i, int minval, int maxval, bool msg = true);
408 extern float clampfvar(ident *id, float f, float minval, float maxval, bool msg = true);
409 extern void loopiter(ident *id, identstack &stack, const tagval &v);
410 extern void loopend(ident *id, identstack &stack);
411 
412 #define loopstart(id, stack) if((id)->type != ID_ALIAS) return; identstack stack;
loopiter(ident * id,identstack & stack,int i)413 static inline void loopiter(ident *id, identstack &stack, int i) { tagval v; v.setint(i); loopiter(id, stack, v); }
loopiter(ident * id,identstack & stack,float f)414 static inline void loopiter(ident *id, identstack &stack, float f) { tagval v; v.setfloat(f); loopiter(id, stack, v); }
loopiter(ident * id,identstack & stack,const char * s)415 static inline void loopiter(ident *id, identstack &stack, const char *s) { tagval v; v.setstr(newstring(s)); loopiter(id, stack, v); }
416 
417 extern int identflags;
418 
419 extern void checksleep(int millis);
420 extern void clearsleep(bool clearworlds = true);
421 
422 extern char *logtimeformat, *filetimeformat;
423 extern int filetimelocal;
424 extern const char *gettime(time_t ctime = 0, const char *format = NULL);
425 extern bool hasflag(const char *flags, char f);
426 extern char *limitstring(const char *str, size_t len);
427 
428 // nasty macros for registering script functions, abuses globals to avoid excessive infrastructure
429 #define KEYWORD(flags, name, type) UNUSED static bool __dummy_##type = addcommand(#name, (identfun)NULL, NULL, type, flags|IDF_COMPLETE)
430 #define COMMANDKN(flags, level, name, type, fun, nargs) UNUSED static bool __dummy_##fun = addcommand(#name, (identfun)fun, nargs, type, flags|IDF_COMPLETE, level)
431 #define COMMANDK(flags, name, type, nargs) COMMANDKN(flags, 0, name, type, name, nargs)
432 #define COMMANDN(flags, name, fun, nargs) COMMANDKN(flags, 0, name, ID_COMMAND, fun, nargs)
433 #define COMMAND(flags, name, nargs) COMMANDN(flags, name, name, nargs)
434 
435 // anonymous inline commands, uses nasty template trick with line numbers to keep names unique
436 #define ICOMMANDNAME(name) _icmd_##name
437 #define ICOMMANDSNAME _icmds_
438 #define ICOMMANDKNS(flags, level, name, type, cmdname, nargs, proto, b) template<int N> struct cmdname; template<> struct cmdname<__LINE__> { static bool init; static void run proto; }; bool cmdname<__LINE__>::init = addcommand(name, (identfun)cmdname<__LINE__>::run, nargs, type, flags|IDF_COMPLETE, level); void cmdname<__LINE__>::run proto \
439     { b; }
440 #define ICOMMANDKN(flags, level, name, type, cmdname, nargs, proto, b) ICOMMANDKNS(flags, level, #name, type, cmdname, nargs, proto, b)
441 #define ICOMMANDK(flags, name, type, nargs, proto, b) ICOMMANDKN(flags, 0, name, type, ICOMMANDNAME(name), nargs, proto, b)
442 #define ICOMMANDKS(flags, name, type, nargs, proto, b) ICOMMANDKNS(flags, 0, name, type, ICOMMANDSNAME, nargs, proto, b)
443 #define ICOMMANDNS(flags, name, cmdname, nargs, proto, b) ICOMMANDKNS(flags, 0, name, ID_COMMAND, cmdname, nargs, proto, b)
444 #define ICOMMANDN(flags, name, cmdname, nargs, proto, b) ICOMMANDNS(flags, #name, cmdname, nargs, proto, b)
445 #define ICOMMAND(flags, name, nargs, proto, b) ICOMMANDN(flags, name, ICOMMANDNAME(name), nargs, proto, b)
446 #define ICOMMANDS(flags, name, nargs, proto, b) ICOMMANDNS(flags, name, ICOMMANDSNAME, nargs, proto, b)
447 #define ICOMMANDV(flags, name, b) ICOMMANDN(flags, name, ICOMMANDNAME(name), "N$", (int *numargs, ident *id), \
448 { \
449     if(*numargs > 0) printreadonly(id); \
450     else if(*numargs < 0) intret((b)); \
451     else printvar(id, (b)); \
452 })
453 #define ICOMMANDVF(flags, name, b) ICOMMANDN(flags, name, ICOMMANDNAME(name), "N$", (int *numargs, ident *id), \
454 { \
455     if(*numargs > 0) printreadonly(id); \
456     else if(*numargs < 0) floatret((b)); \
457     else printfvar(id, (b)); \
458 })
459 #define ICOMMANDVS(flags, name, b) ICOMMANDN(flags, name, ICOMMANDNAME(name), "N$", (int *numargs, ident *id), \
460 { \
461     if(*numargs > 0) printreadonly(id); \
462     else if(*numargs < 0) result((b)); \
463     else printsvar(id, (b)); \
464 })
465 
466 #define _VAR(name, global, min, cur, max, flags, level) int global = variable(#name, min, cur, max, &global, NULL, flags|IDF_COMPLETE, level)
467 #define VARN(flags, name, global, min, cur, max) _VAR(name, global, min, cur, max, flags, 0)
468 #define VAR(flags, name, min, cur, max) _VAR(name, name, min, cur, max, flags, 0)
469 #define _VARF(name, global, min, cur, max, body, flags, level)  void var_##name(ident *id); int global = variable(#name, min, cur, max, &global, var_##name, flags|IDF_COMPLETE, level); void var_##name(ident *id) { body; }
470 #define VARFN(flags, name, global, min, cur, max, body) _VARF(name, global, min, cur, max, body, flags, 0)
471 #define VARF(flags, name, min, cur, max, body) _VARF(name, name, min, cur, max, body, flags, 0)
472 
473 #define _FVAR(name, global, min, cur, max, flags, level) float global = fvariable(#name, min, cur, max, &global, NULL, flags|IDF_COMPLETE, level)
474 #define FVARN(flags, name, global, min, cur, max) _FVAR(name, global, min, cur, max, flags, 0)
475 #define FVAR(flags, name, min, cur, max) _FVAR(name, name, min, cur, max, flags, 0)
476 #define _FVARF(name, global, min, cur, max, body, flags, level) void var_##name(ident *id); float global = fvariable(#name, min, cur, max, &global, var_##name, flags|IDF_COMPLETE, level); void var_##name(ident *id) { body; }
477 #define FVARFN(flags, name, global, min, cur, max, body) _FVARF(name, global, min, cur, max, body, flags, 0)
478 #define FVARF(flags, name, min, cur, max, body) _FVARF(name, name, min, cur, max, body, flags, 0)
479 
480 #define _SVAR(name, global, cur, flags, level) char *global = svariable(#name, cur, &global, NULL, flags|IDF_COMPLETE, level)
481 #define SVARN(flags, name, global, cur) _SVAR(name, global, cur, flags, 0)
482 #define SVAR(flags, name, cur) _SVAR(name, name, cur, flags, 0)
483 #define _SVARF(name, global, cur, body, flags, level) void var_##name(ident *id); char *global = svariable(#name, cur, &global, var_##name, flags|IDF_COMPLETE, level); void var_##name(ident *id) { body; }
484 #define SVARFN(flags, name, global, cur, body) _SVARF(name, global, cur, body, flags, 0)
485 #define SVARF(flags, name, cur, body) _SVARF(name, name, cur, body, flags, 0)
486 
487 #define _CVAR(name, cur, init, body, flags, level) bvec name = bvec::fromcolor(cur); _VARF(name, _##name, 0, cur, 0xFFFFFF, { init; name = bvec::fromcolor(_##name); body; }, IDF_HEX|flags, level)
488 #define CVARF(flags, name, cur, body) _CVAR(name, cur, , body, flags, 0)
489 #define CVAR(flags, name, cur) _CVAR(name, cur, , , flags, 0)
490 #define CVAR0F(flags, name, cur, body) _CVAR(name, cur, { if(!_##name) _##name = cur; }, body, flags, 0)
491 #define CVAR1F(flags, name, cur, body) _CVAR(name, cur, { if(_##name <= 255) _##name |= (_##name<<8) | (_##name<<16); }, body, flags, 0)
492 #define CVAR0(flags, name, cur) CVAR0F(flags, name, cur, )
493 #define CVAR1(flags, name, cur) CVAR1F(flags, name, cur, )
494 
495 // game world controlling stuff
496 #define WITHWORLD(body) { int _oldflags = identflags; identflags |= IDF_WORLD; body; identflags = _oldflags; }
497 #define RUNWORLD(n) { ident *wid = idents.access(n); if(wid && wid->type==ID_ALIAS && wid->flags&IDF_WORLD) { WITHWORLD(execute(wid->getstr())); } }
498 
499 #if defined(CPP_GAME_MAIN)
500 #define IDF_GAME (IDF_CLIENT|IDF_REWRITE)
501 #define G(name) (name)
502 #define PHYS(name) (G(name)*G(name##scale))
503 #define GICOMMAND(flags, level, name, nargs, proto, svbody, ccbody) ICOMMANDKNS(flags|IDF_GAME, level, #name, ID_COMMAND, ICOMMANDNAME(name), nargs, proto, ccbody)
504 #define GVARN(flags, level, name, global, min, cur, max) _VAR(name, global, min, cur, max, flags|IDF_GAME, level)
505 #define GVAR(flags, level, name, min, cur, max) _VAR(name, name, min, cur, max, flags|IDF_GAME, level)
506 #define GVARF(flags, level, name, min, cur, max, svbody, ccbody) _VARF(name, name, min, cur, max, ccbody, flags|IDF_GAME, level)
507 #define GFVARN(flags, level, name, global, min, cur, max) _FVAR(name, global, min, cur, max, flags|IDF_GAME, level)
508 #define GFVAR(flags, level, name, min, cur, max) _FVAR(name, name, min, cur, max, flags|IDF_GAME, level)
509 #define GFVARF(flags, level, name, min, cur, max, svbody, ccbody) _FVARF(name, name, min, cur, max, ccbody, flags|IDF_GAME, level)
510 #define GSVARN(flags, level, name, global, cur) _SVAR(name, global, cur, flags|IDF_GAME, level)
511 #define GSVAR(flags, level, name, cur) _SVAR(name, name, cur, flags|IDF_GAME, level)
512 #define GSVARF(flags, level, name, cur, svbody, ccbody) _SVARF(name, name, cur, ccbody, flags|IDF_GAME, level)
513 #elif defined(CPP_GAME_SERVER)
514 #define G(name) (sv_##name)
515 #define IDF_GAME (IDF_SERVER|IDF_REWRITE)
516 #define GICOMMAND(flags, level, name, nargs, proto, svbody, ccbody) ICOMMANDKNS(flags|(IDF_GAME&~IDF_REWRITE), level, "sv_" #name, ID_COMMAND, ICOMMANDNAME(sv_##name), nargs, proto, svbody)
517 #define GVARN(flags, level, name, global, min, cur, max) _VAR(sv_##name, global, min, cur, max, flags|IDF_GAME, level)
518 #define GVAR(flags, level, name, min, cur, max) _VAR(sv_##name, sv_##name, min, cur, max, flags|IDF_GAME, level)
519 #define GVARF(flags, level, name, min, cur, max, svbody, ccbody) _VARF(sv_##name, sv_##name, min, cur, max, svbody, flags|IDF_GAME, level)
520 #define GFVARN(flags, level, name, global, min, cur, max) _FVAR(sv_##name, global, min, cur, max, flags|IDF_GAME, level)
521 #define GFVAR(flags, level, name, min, cur, max) _FVAR(sv_##name, sv_##name, min, cur, max, flags|IDF_GAME, level)
522 #define GFVARF(flags, level, name, min, cur, max, svbody, ccbody) _FVARF(sv_##name, sv_##name, min, cur, max, svbody, flags|IDF_GAME, level)
523 #define GSVARN(flags, level, name, global, cur) _SVAR(sv_##name, global, cur, flags|IDF_GAME, level)
524 #define GSVAR(flags, level, name, cur) _SVAR(sv_##name, sv_##name, cur, flags|IDF_GAME, level)
525 #define GSVARF(flags, level, name, cur, svbody, ccbody) _SVARF(sv_##name, sv_##name, cur, svbody, flags|IDF_GAME, level)
526 #else
527 #define G(name) (name)
528 #define PHYS(name) (G(name)*G(name##scale))
529 #define GICOMMAND(flags, level, n, g, proto, svbody, ccbody)
530 #define GVARN(flags, level, name, global, min, cur, max) extern int name
531 #define GVAR(flags, level, name, min, cur, max) extern int name
532 #define GVARF(flags, level, name, min, cur, max, svbody, ccbody) extern int name
533 #define GVARN(flags, level, name, global, min, cur, max) extern int name
534 #define GVAR(flags, level, name, min, cur, max) extern int name
535 #define GVARF(flags, level, name, min, cur, max, svbody, ccbody) extern int name
536 #define GFVARN(flags, level, name, global, min, cur, max) extern float name
537 #define GFVAR(flags, level, name, min, cur, max) extern float name
538 #define GFVARF(flags, level, name, min, cur, max, svbody, ccbody) extern float name
539 #define GSVARN(flags, level, name, global, cur) extern char *name
540 #define GSVAR(flags, level, name, cur) extern char *name
541 #define GSVARF(flags, level, name, cur, svbody, ccbody) extern char *name
542 #endif
543 
544 #ifdef CPP_ENGINE_COMMAND
545 SVAR(IDF_READONLY, validxname, "null int float str any code macro ident cstr cany word pop cond");
546 VAR(IDF_READONLY, validxnull, 0, VAL_NULL, -1);
547 SVAR(IDF_READONLY, valnamenull, "Null");
548 VAR(IDF_READONLY, validxint, 0, VAL_INT, -1);
549 SVAR(IDF_READONLY, valnameint, "Integer");
550 VAR(IDF_READONLY, validxfloat, 0, VAL_FLOAT, -1);
551 SVAR(IDF_READONLY, valnamefloat, "Float");
552 VAR(IDF_READONLY, validxstr, 0, VAL_STR, -1);
553 SVAR(IDF_READONLY, valnamestr, "String");
554 VAR(IDF_READONLY, validxany, 0, VAL_ANY, -1);
555 SVAR(IDF_READONLY, valnameany, "Any");
556 VAR(IDF_READONLY, validxcode, 0, VAL_CODE, -1);
557 SVAR(IDF_READONLY, valnamecode, "Code");
558 VAR(IDF_READONLY, validxmacro, 0, VAL_MACRO, -1);
559 SVAR(IDF_READONLY, valnamemacro, "Macro");
560 VAR(IDF_READONLY, validxident, 0, VAL_IDENT, -1);
561 SVAR(IDF_READONLY, valnameident, "Identifier");
562 VAR(IDF_READONLY, validxcstr, 0, VAL_CSTR, -1);
563 SVAR(IDF_READONLY, valnamecstr, "Constant-string");
564 VAR(IDF_READONLY, validxcany, 0, VAL_CANY, -1);
565 SVAR(IDF_READONLY, valnamecany, "Constant-any");
566 VAR(IDF_READONLY, validxword, 0, VAL_WORD, -1);
567 SVAR(IDF_READONLY, valnameworld, "Word");
568 VAR(IDF_READONLY, validxpop, 0, VAL_POP, -1);
569 SVAR(IDF_READONLY, valnamepop, "Pop");
570 VAR(IDF_READONLY, validxcond, 0, VAL_COND, -1);
571 SVAR(IDF_READONLY, valnamecond, "Conditional");
572 VAR(IDF_READONLY, validxmax, 0, VAL_MAX, -1);
573 SVAR(IDF_READONLY, ididxname, "var fvar svar command alias local do doargs if result not and or");
574 VAR(IDF_READONLY, ididxvar, 0, ID_VAR, -1);
575 SVAR(IDF_READONLY, idnamevar, "Integer-variable");
576 VAR(IDF_READONLY, ididxfvar, 0, ID_FVAR, -1);
577 SVAR(IDF_READONLY, idnamefvar, "Float-variable");
578 VAR(IDF_READONLY, ididxsvar, 0, ID_SVAR, -1);
579 SVAR(IDF_READONLY, idnamesvar, "String-variable");
580 VAR(IDF_READONLY, ididxcommand, 0, ID_COMMAND, -1);
581 SVAR(IDF_READONLY, idnamecommand, "Command");
582 VAR(IDF_READONLY, ididxalias, 0, ID_ALIAS, -1);
583 SVAR(IDF_READONLY, idnamealias, "Alias");
584 VAR(IDF_READONLY, ididxlocal, 0, ID_LOCAL, -1);
585 SVAR(IDF_READONLY, idnamelocal, "Local");
586 VAR(IDF_READONLY, ididxdo, 0, ID_DO, -1);
587 SVAR(IDF_READONLY, idnamedo, "Do");
588 VAR(IDF_READONLY, ididxdoargs, 0, ID_DOARGS, -1);
589 SVAR(IDF_READONLY, idnamedoargs, "Do-arguments");
590 VAR(IDF_READONLY, ididxif, 0, ID_IF, -1);
591 SVAR(IDF_READONLY, idnameif, "If-condition");
592 VAR(IDF_READONLY, ididxresult, 0, ID_RESULT, -1);
593 SVAR(IDF_READONLY, idnameresult, "Result");
594 VAR(IDF_READONLY, ididxnot, 0, ID_NOT, -1);
595 SVAR(IDF_READONLY, idnamenot, "Not-condition");
596 VAR(IDF_READONLY, ididxand, 0, ID_AND, -1);
597 SVAR(IDF_READONLY, idnameand, "And-condition");
598 VAR(IDF_READONLY, ididxor, 0, ID_OR, -1);
599 SVAR(IDF_READONLY, idnameor, "Or-condition");
600 VAR(IDF_READONLY, ididxmax, 0, ID_MAX, -1);
601 SVAR(IDF_READONLY, idfidxname, "init persist readonly rewrite world complete texture client server hex unknown arg preload gamepreload gamemod namecomplete");
602 VAR(IDF_READONLY, idfbitinit, 0, IDF_INIT, -1);
603 SVAR(IDF_READONLY, idfnameinit, "Initialiser");
604 VAR(IDF_READONLY, idfbitpersist, 0, IDF_PERSIST, -1);
605 SVAR(IDF_READONLY, idfnamepersist, "Persistent");
606 VAR(IDF_READONLY, idfbitreadonly, 0, IDF_READONLY, -1);
607 SVAR(IDF_READONLY, idfnamereadonly, "Read-only");
608 VAR(IDF_READONLY, idfbitrewrite, 0, IDF_REWRITE, -1);
609 SVAR(IDF_READONLY, idfnamerewrite, "Rewrite");
610 VAR(IDF_READONLY, idfbitworld, 0, IDF_WORLD, -1);
611 SVAR(IDF_READONLY, idfnameworld, "World");
612 VAR(IDF_READONLY, idfbitcomplete, 0, IDF_COMPLETE, -1);
613 SVAR(IDF_READONLY, idfnamecomplete, "Complete");
614 VAR(IDF_READONLY, idfbittexture, 0, IDF_TEXTURE, -1);
615 SVAR(IDF_READONLY, idfnametexture, "Texture");
616 VAR(IDF_READONLY, idfbitclient, 0, IDF_CLIENT, -1);
617 SVAR(IDF_READONLY, idfnameclient, "Client");
618 VAR(IDF_READONLY, idfbitserver, 0, IDF_SERVER, -1);
619 SVAR(IDF_READONLY, idfnameserver, "Server");
620 VAR(IDF_READONLY, idfbithex, 0, IDF_HEX, -1);
621 SVAR(IDF_READONLY, idfnamehex, "Hexadecimal");
622 VAR(IDF_READONLY, idfbitunknown, 0, IDF_UNKNOWN, -1);
623 SVAR(IDF_READONLY, idfnameunknown, "Unknown");
624 VAR(IDF_READONLY, idfbitarg, 0, IDF_ARG, -1);
625 SVAR(IDF_READONLY, idfnamearg, "Argument");
626 VAR(IDF_READONLY, idfbitpreload, 0, IDF_PRELOAD, -1);
627 SVAR(IDF_READONLY, idfnamepreload, "Preload");
628 VAR(IDF_READONLY, idfbitgamepreload, 0, IDF_GAMEPRELOAD, -1);
629 SVAR(IDF_READONLY, idfnamegamepreload, "Game-preload");
630 VAR(IDF_READONLY, idfbitgamemod, 0, IDF_GAMEMOD, -1);
631 SVAR(IDF_READONLY, idfnamegamemod, "Game-modifier");
632 VAR(IDF_READONLY, idfbitnamecomplete, 0, IDF_NAMECOMPLETE, -1);
633 SVAR(IDF_READONLY, idfnamenamecomplete, "Name-complete");
634 VAR(IDF_READONLY, varidxmax, 0, VAR_MAX, -1);
635 VAR(IDF_READONLY, varidxmin, 0, VAR_MIN, -1);
636 FVAR(IDF_READONLY, fvaridxmax, 0, FVAR_MAX, -1);
637 FVAR(IDF_READONLY, fvaridxmin, 0, FVAR_MIN, -1);
638 FVAR(IDF_READONLY, fvaridxnonzero, 0, FVAR_NONZERO, -1);
639 #endif // CPP_ENGINE_COMMAND
640