Xonotic
effectinfo.qc
Go to the documentation of this file.
1 #if ENABLE_EFFECTINFO
2 
3 #include "effectinfo.qh"
4 #define EFFECTINFO_PARSER(on, MY) \
5  on(type, MY(type) \
6  ,{ demand(n == 1 && "type"); MY(type) = strzone(argv(1)); \
7  }, sprintf(" %s", (MY(type)) \
8  )) \
9  on(airfriction, MY(airfriction) \
10  ,{ demand(n == 1 && "airfriction"); MY(airfriction) = stof(argv(1)); \
11  }, sprintf(" %s", ftos(MY(airfriction)) \
12  )) \
13  on(alpha, MY(alpha_min) || MY(alpha_max) || MY(alpha_fade) \
14  ,{ demand(n == 3 && "alpha"); MY(alpha_min) = stof(argv(1)); MY(alpha_max) = stof(argv(2)); MY(alpha_fade) = stof(argv(3)); \
15  }, sprintf(" %s %s %s", ftos(MY(alpha_min)), ftos(MY(alpha_max)), ftos(MY(alpha_fade)) \
16  )) \
17  on(blend, MY(blend) \
18  ,{ demand(n == 1 && "blend"); MY(blend) = strzone(argv(1)); \
19  }, sprintf(" %s", (MY(blend)) \
20  )) \
21  on(bounce, MY(bounce) \
22  ,{ demand(n == 1 && "bounce"); MY(bounce) = stof(argv(1)); \
23  }, sprintf(" %s", ftos(MY(bounce)) \
24  )) \
25  on(color, MY(color_min) || MY(color_max) \
26  ,{ demand(n == 2 && "color"); MY(color_min) = strzone(argv(1)); MY(color_max) = strzone(argv(2)); \
27  }, sprintf(" %s %s", (MY(color_min)), (MY(color_max)) \
28  )) \
29  on(countabsolute, MY(countabsolute) \
30  ,{ demand(n == 1 && "countabsolute"); MY(countabsolute) = stof(argv(1)); \
31  }, sprintf(" %s", ftos(MY(countabsolute)) \
32  )) \
33  on(count, MY(count) \
34  ,{ demand(n == 1 && "count"); MY(count) = stof(argv(1)); \
35  }, sprintf(" %s", ftos(MY(count)) \
36  )) \
37  on(gravity, MY(gravity) \
38  ,{ demand(n == 1 && "gravity"); MY(gravity) = stof(argv(1)); \
39  }, sprintf(" %s", ftos(MY(gravity)) \
40  )) \
41  on(lightcolor, MY(lightcolor) \
42  ,{ demand(n == 3 && "lightcolor"); MY(lightcolor) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
43  }, sprintf(" %v", (MY(lightcolor)) \
44  )) \
45  on(lightradiusfade, MY(lightradiusfade) \
46  ,{ demand(n == 1 && "lightradiusfade"); MY(lightradiusfade) = stof(argv(1)); \
47  }, sprintf(" %s", ftos(MY(lightradiusfade)) \
48  )) \
49  on(lightradius, MY(lightradius) \
50  ,{ demand(n == 1 && "lightradius"); MY(lightradius) = stof(argv(1)); \
51  }, sprintf(" %s", ftos(MY(lightradius)) \
52  )) \
53  on(lighttime, MY(lighttime) \
54  ,{ demand(n == 1 && "lighttime"); MY(lighttime) = stof(argv(1)); \
55  }, sprintf(" %s", ftos(MY(lighttime)) \
56  )) \
57  on(liquidfriction, MY(liquidfriction) \
58  ,{ demand(n == 1 && "liquidfriction"); MY(liquidfriction) = stof(argv(1)); \
59  }, sprintf(" %s", ftos(MY(liquidfriction)) \
60  )) \
61  on(notunderwater, MY(notunderwater) \
62  ,{ demand(n == 0 && "notunderwater"); MY(notunderwater) = true; \
63  }, "" \
64  ) \
65  on(orientation, MY(orientation) \
66  ,{ demand(n == 1 && "orientation"); MY(orientation) = strzone(argv(1)); \
67  }, sprintf(" %s", (MY(orientation)) \
68  )) \
69  on(originjitter, MY(originjitter) \
70  ,{ demand(n == 3 && "originjitter"); MY(originjitter) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
71  }, sprintf(" %v", (MY(originjitter)) \
72  )) \
73  on(originoffset, MY(originoffset) \
74  ,{ demand(n == 3 && "originoffset"); MY(originoffset) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
75  }, sprintf(" %v", (MY(originoffset)) \
76  )) \
77  on(relativeoriginoffset, MY(relativeoriginoffset) \
78  ,{ demand(n == 3 && "relativeoriginoffset"); MY(relativeoriginoffset) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
79  }, sprintf(" %v", (MY(relativeoriginoffset)) \
80  )) \
81  on(relativevelocityoffset, MY(relativevelocityoffset) \
82  ,{ demand(n == 3 && "relativevelocityoffset"); MY(relativevelocityoffset) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
83  }, sprintf(" %v", (MY(relativevelocityoffset)) \
84  )) \
85  on(rotate, MY(startangle_min) || MY(startangle_max) || MY(spin_min) || MY(spin_max) \
86  ,{ demand(n == 4 && "rotate"); MY(startangle_min) = stof(argv(1)); MY(startangle_max) = stof(argv(2)); MY(spin_min) = stof(argv(3)); MY(spin_max) = stof(argv(4)); \
87  }, sprintf(" %s %s %s %s", ftos(MY(startangle_min)), ftos(MY(startangle_max)), ftos(MY(spin_min)), ftos(MY(spin_max)) \
88  )) \
89  on(sizeincrease, MY(sizeincrease) \
90  ,{ demand(n == 1 && "sizeincrease"); MY(sizeincrease) = stof(argv(1)); \
91  }, sprintf(" %s", ftos(MY(sizeincrease)) \
92  )) \
93  on(size, MY(size_min) || MY(size_max) \
94  ,{ demand(n == 2 && "size"); MY(size_min) = stof(argv(1)); MY(size_max) = stof(argv(2)); \
95  }, sprintf(" %s %s", ftos(MY(size_min)), ftos(MY(size_max)) \
96  )) \
97  on(staincolor, MY(staincolor_min) || MY(staincolor_max) \
98  ,{ demand(n == 2 && "staincolor"); MY(staincolor_min) = strzone(argv(1)); MY(staincolor_max) = strzone(argv(2)); \
99  }, sprintf(" %s %s", (MY(staincolor_min)), (MY(staincolor_max)) \
100  )) \
101  on(stainsize, MY(stainsize_min) || MY(stainsize_max) \
102  ,{ demand(n == 2 && "stainsize"); MY(stainsize_min) = stof(argv(1)); MY(stainsize_max) = stof(argv(2)); \
103  }, sprintf(" %s %s", ftos(MY(stainsize_min)), ftos(MY(stainsize_max)) \
104  )) \
105  on(staintex, MY(staintex_min) || MY(staintex_max) \
106  ,{ demand(n == 2 && "staintex"); MY(staintex_min) = stof(argv(1)); MY(staintex_max) = stof(argv(2)); \
107  }, sprintf(" %s %s", ftos(MY(staintex_min)), ftos(MY(staintex_max)) \
108  )) \
109  on(stretchfactor, MY(stretchfactor) \
110  ,{ demand(n == 1 && "stretchfactor"); MY(stretchfactor) = stof(argv(1)); \
111  }, sprintf(" %s", ftos(MY(stretchfactor)) \
112  )) \
113  on(tex, MY(tex_min) || MY(tex_max) \
114  ,{ demand(n == 2 && "tex"); MY(tex_min) = stof(argv(1)); MY(tex_max) = stof(argv(2)); \
115  }, sprintf(" %s %s", ftos(MY(tex_min)), ftos(MY(tex_max)) \
116  )) \
117  on(time, MY(time_min) || MY(time_max) \
118  ,{ demand(n == 2 && "time"); MY(time_min) = stof(argv(1)); MY(time_max) = stof(argv(2)); \
119  }, sprintf(" %s %s", ftos(MY(time_min)), ftos(MY(time_max)) \
120  )) \
121  on(trailspacing, MY(trailspacing) \
122  ,{ demand(n == 1 && "trailspacing"); MY(trailspacing) = stof(argv(1)); \
123  }, sprintf(" %s", ftos(MY(trailspacing)) \
124  )) \
125  on(underwater, MY(underwater) \
126  ,{ demand(n == 0 && "underwater"); MY(underwater) = true; \
127  }, "" \
128  ) \
129  on(velocityjitter, MY(velocityjitter) \
130  ,{ demand(n == 3 && "velocityjitter"); MY(velocityjitter) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
131  }, sprintf(" %v", (MY(velocityjitter)) \
132  )) \
133  on(velocitymultiplier, MY(velocitymultiplier) \
134  ,{ demand(n == 1 && "velocitymultiplier"); MY(velocitymultiplier) = stof(argv(1)); \
135  }, sprintf(" %s", ftos(MY(velocitymultiplier)) \
136  )) \
137  on(velocityoffset, MY(velocityoffset) \
138  ,{ demand(n == 3 && "velocityoffset"); MY(velocityoffset) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
139  }, sprintf(" %v", (MY(velocityoffset)) \
140  )) \
141 
142 
143 CLASS(EffectInfo, Object)
144  ATTRIB(EffectInfo, effectinfo_name, string);
145  CONSTRUCTOR(EffectInfo, string s) {
146  CONSTRUCT(EffectInfo);
147  this.effectinfo_name = s;
148  }
149 
150  #define FIELDS(MY) \
151  MY(airfriction, float, 0) \
152  MY(alpha_min, float, 0) \
153  MY(alpha_max, float, 0) \
154  MY(alpha_fade, float, 0) \
155  MY(blend, string, string_null) \
156  MY(bounce, float, 0) \
157  MY(color_min, string, string_null) \
158  MY(color_max, string, string_null) \
159  MY(countabsolute, float, 0) \
160  MY(count, float, 0) \
161  MY(gravity, float, 0) \
162  MY(lightcolor, vector, '0 0 0') \
163  MY(lightradiusfade, float, 0) \
164  MY(lightradius, float, 0) \
165  MY(lighttime, float, 0) \
166  MY(liquidfriction, float, 0) \
167  MY(notunderwater, bool, false) \
168  MY(orientation, string, string_null) \
169  MY(originjitter, vector, '0 0 0') \
170  MY(originoffset, vector, '0 0 0') \
171  MY(relativeoriginoffset, vector, '0 0 0') \
172  MY(relativevelocityoffset, vector, '0 0 0') \
173  MY(startangle_min, float, 0) \
174  MY(startangle_max, float, 0) \
175  MY(spin_min, float, 0) \
176  MY(spin_max, float, 0) \
177  MY(sizeincrease, float, 0) \
178  MY(size_min, float, 0) \
179  MY(size_max, float, 0) \
180  MY(staincolor_min, string, string_null) \
181  MY(staincolor_max, string, string_null) \
182  MY(stainsize_min, float, 0) \
183  MY(stainsize_max, float, 0) \
184  MY(staintex_min, float, 0) \
185  MY(staintex_max, float, 0) \
186  MY(stretchfactor, float, 0) \
187  MY(tex_min, float, 0) \
188  MY(tex_max, float, 0) \
189  MY(time_min, float, 0) \
190  MY(time_max, float, 0) \
191  MY(trailspacing, float, 0) \
192  MY(type, string, string_null) \
193  MY(underwater, bool, false) \
194  MY(velocityjitter, vector, '0 0 0') \
195  MY(velocitymultiplier, float, 0) \
196  MY(velocityoffset, vector, '0 0 0') \
197 
198 
199  #define MY(f, type, val) ATTRIB(EffectInfo, effectinfo_##f, type, val);
200  FIELDS(MY)
201  #undef MY
202 
203  METHOD(EffectInfo, describe, string(EffectInfo this))
204  {
205  TC(EffectInfo, this);
206  string s = sprintf("SUB(%s) {\n", this.effectinfo_name);
207  #define str_bool(it) (it ? "true" : "false")
208  #define str_float(it) ftos(it)
209  #define str_vector(it) vtos(it)
210  #define str_string(it) strcat("\"", it, "\"")
211  #define p(f, type, default) if (this.effectinfo_##f) { s = strcat(s, "\t", "MY("#f") = ", str_##type(this.effectinfo_##f), ";\n"); }
212  FIELDS(p)
213  #undef p
214  return strcat(s, "}\n");
215  }
216 
217  METHOD(EffectInfo, dump, string(EffectInfo this))
218  {
219  TC(EffectInfo, this);
220  string s = sprintf("effect %s\n", this.effectinfo_name);
221  #define MY(f) this.effectinfo_##f
222  #define p(k, isset, parse, unparse) if (isset) { s = strcat(s, "\t", #k, unparse, "\n"); }
223  EFFECTINFO_PARSER(p, MY)
224  #undef p
225  #undef MY
226  return s;
227  }
228 
229  #undef FIELDS
230 ENDCLASS(EffectInfo)
231 
232 CLASS(EffectInfoGroup, Object)
233  ATTRIBARRAY(EffectInfoGroup, children, EffectInfo, 16);
234  ATTRIB(EffectInfoGroup, children_count, int, 0);
235 ENDCLASS(EffectInfoGroup)
236 
237 void effectinfo_read()
238 {
239  int fh = fopen("effectinfo.txt", FILE_READ);
240  EffectInfo info = NULL;
241  for (string line; (line = fgets(fh)); ) {
242  int n = tokenize_console(line);
243  if (n == 0) continue;
244  n--;
245  string k = argv(0);
246  if (k == "effect") {
247  demand(n == 1);
248  info = NEW(EffectInfo, strzone(argv(1)));
249  continue;
250  }
251  demand(info != NULL);
252  switch (k) {
253  #define MY(f) info.effectinfo_##f
254  #define p(k, isset, parse, unparse) case #k: parse break;
255  EFFECTINFO_PARSER(p, MY)
256  #undef p
257  #undef MY
258  default:
259  LOG_WARNF("Unknown property '%s'", k);
260  break;
261  }
262  }
263  fclose(fh);
264 }
265 
266 void effectinfo_dump(int fh, bool alsoprint)
267 {
268  #define WRITE(str) write_String_To_File(fh, str, alsoprint)
269  WRITE(
270  "// ********************************************** //\n"
271  "// ** WARNING - DO NOT MANUALLY EDIT THIS FILE ** //\n"
272  "// ** ** //\n"
273  "// ** This file is automatically generated by ** //\n"
274  "// ** code with the command 'dumpeffectinfo'. ** //\n"
275  "// ** ** //\n"
276  "// ** If you modify an effect, please ** //\n"
277  "// ** regenerate this file with that command. ** //\n"
278  "// ** ** //\n"
279  "// ********************************************** //\n"
280  "\n");
281 
282  for (EffectInfo it = NULL; (it = findfloat(it, instanceOfEffectInfo, true)); ) {
283  if (it.classname == "vtbl") continue;
284  string s = it.dump(it);
285  WRITE(s);
286  }
287  #undef WRITE
288 }
289 
290 #define DEFAULT_FILENAME "effectinfo_dump.txt"
291 // NOTE: dumpeffectinfo, dumpnotifs, dumpturrets and dumpweapons use similar code
292 GENERIC_COMMAND(dumpeffectinfo, "Dump all effectinfo into " DEFAULT_FILENAME, false)
293 {
294  switch (request) {
295  case CMD_REQUEST_COMMAND: {
296  string filename = argv(1);
297  bool alsoprint = false;
298  if (filename == "") {
299  filename = DEFAULT_FILENAME;
300  alsoprint = false;
301  } else if (filename == "-") {
302  filename = DEFAULT_FILENAME;
303  alsoprint = true;
304  }
305  int fh = fopen(filename, FILE_WRITE);
306  if (fh >= 0) {
307  effectinfo_dump(fh, alsoprint);
308  LOG_INFOF("Dumping effectinfo... File located at ^2data/data/%s^7.", filename);
309  LOG_INFOF("Reload with ^2cl_particles_reloadeffects data/%s^7.", filename);
310  fclose(fh);
311  } else {
312  LOG_WARNF("Could not open file '%s'!", filename);
313  }
314  return;
315  }
316  default:
317  case CMD_REQUEST_USAGE: {
318  LOG_HELP("Usage:^3 ", GetProgramCommandPrefix(), " dumpeffectinfo [<filename>]");
319  LOG_HELPF(" Where <filename> is the file to write (default is %s),", DEFAULT_FILENAME);
320  LOG_HELP(" if supplied with '-' output to console as well as default,");
321  LOG_HELP(" if left blank, it will only write to default.");
322  return;
323  }
324  }
325 }
326 #undef DEFAULT_FILENAME
327 
328 
329 REGISTRY(EffectInfos, BITS(9))
330 REGISTER_REGISTRY(EffectInfos)
331 
332 REGISTRY_DEFINE_GET(EffectInfos, NULL)
333 #define EFFECTINFO(name) \
334  ACCUMULATE void effectinfo_##name(EffectInfoGroup parent, EffectInfo this) { } \
335  REGISTER(EffectInfos, EFFECTINFO, name, m_id, NEW(EffectInfoGroup)) { \
336  effectinfo_##name(this, NULL); \
337  }
338 
339 #define MY(f) this.effectinfo_##f
340 #define DEF(name) EFFECTINFO(name)
341 #define SUB(name) \
342  ACCUMULATE void effectinfo_##name(EffectInfoGroup parent, EffectInfo this) { parent = EFFECTINFO_##name; parent.children[parent.children_count++] = this = NEW(EffectInfo, #name); } \
343  ACCUMULATE void effectinfo_##name(EffectInfoGroup parent, EffectInfo this)
344 #include "effectinfo.inc"
345 #undef MY
346 #undef DEF
347 #undef SUB
348 
349 #endif
#define LOG_HELPF(...)
Definition: log.qh:96
#define NEW(cname,...)
Definition: oo.qh:105
CLASS(Object) Object
Definition: oo.qh:318
const int CMD_REQUEST_USAGE
Definition: command.qh:4
#define GENERIC_COMMAND(id, description, menubased)
Definition: reg.qh:12
const float FILE_READ
Definition: csprogsdefs.qc:231
#define METHOD(cname, name, prototype)
Definition: oo.qh:257
#define CONSTRUCT(cname,...)
Definition: oo.qh:111
#define LOG_HELP(...)
Definition: log.qh:95
#define ATTRIB(...)
Definition: oo.qh:136
#define REGISTER_REGISTRY(id)
Definition: registry.qh:212
#define LOG_WARNF(...)
Definition: log.qh:67
#define REGISTRY_DEFINE_GET(id, null)
Definition: registry.qh:40
#define demand(expr,...)
Definition: log.qh:22
#define DEFAULT_FILENAME
Definition: all.qh:164
#define LOG_INFOF(...)
Definition: log.qh:71
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
#define REGISTRY(id, max)
Declare a new registry.
Definition: registry.qh:26
#define NULL
Definition: post.qh:17
const int CMD_REQUEST_COMMAND
Definition: command.qh:3
#define TC(T, sym)
Definition: _all.inc:82
#define tokenize_console
Definition: dpextensions.qh:24
const float FILE_WRITE
Definition: csprogsdefs.qc:233
#define ENDCLASS(cname)
Definition: oo.qh:269
#define ATTRIBARRAY(cname, name, type, cnt)
Definition: oo.qh:254
#define CONSTRUCTOR(cname,...)
Definition: oo.qh:201
#define BITS(n)
Definition: bits.qh:9