1 #include "effectinfo.qh"
2 #define EFFECTINFO_PARSER(on, MY) \
4 ,{ demand(n == 1 && "type"); MY(type) = strzone(argv(1)); \
5 }, sprintf(" %s", (MY(type)) \
7 on(airfriction, MY(airfriction) \
8 ,{ demand(n == 1 && "airfriction"); MY(airfriction) = stof(argv(1)); \
9 }, sprintf(" %s", ftos(MY(airfriction)) \
11 on(alpha, MY(alpha_min) || MY(alpha_max) || MY(alpha_fade) \
12 ,{ demand(n == 3 && "alpha"); MY(alpha_min) = stof(argv(1)); MY(alpha_max) = stof(argv(2)); MY(alpha_fade) = stof(argv(3)); \
13 }, sprintf(" %s %s %s", ftos(MY(alpha_min)), ftos(MY(alpha_max)), ftos(MY(alpha_fade)) \
16 ,{ demand(n == 1 && "blend"); MY(blend) = strzone(argv(1)); \
17 }, sprintf(" %s", (MY(blend)) \
19 on(bounce, MY(bounce) \
20 ,{ demand(n == 1 && "bounce"); MY(bounce) = stof(argv(1)); \
21 }, sprintf(" %s", ftos(MY(bounce)) \
23 on(color, MY(color_min) || MY(color_max) \
24 ,{ demand(n == 2 && "color"); MY(color_min) = strzone(argv(1)); MY(color_max) = strzone(argv(2)); \
25 }, sprintf(" %s %s", (MY(color_min)), (MY(color_max)) \
27 on(countabsolute, MY(countabsolute) \
28 ,{ demand(n == 1 && "countabsolute"); MY(countabsolute) = stof(argv(1)); \
29 }, sprintf(" %s", ftos(MY(countabsolute)) \
32 ,{ demand(n == 1 && "count"); MY(count) = stof(argv(1)); \
33 }, sprintf(" %s", ftos(MY(count)) \
35 on(gravity, MY(gravity) \
36 ,{ demand(n == 1 && "gravity"); MY(gravity) = stof(argv(1)); \
37 }, sprintf(" %s", ftos(MY(gravity)) \
39 on(lightcolor, MY(lightcolor) \
40 ,{ demand(n == 3 && "lightcolor"); MY(lightcolor) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
41 }, sprintf(" %v", (MY(lightcolor)) \
43 on(lightradiusfade, MY(lightradiusfade) \
44 ,{ demand(n == 1 && "lightradiusfade"); MY(lightradiusfade) = stof(argv(1)); \
45 }, sprintf(" %s", ftos(MY(lightradiusfade)) \
47 on(lightradius, MY(lightradius) \
48 ,{ demand(n == 1 && "lightradius"); MY(lightradius) = stof(argv(1)); \
49 }, sprintf(" %s", ftos(MY(lightradius)) \
51 on(lighttime, MY(lighttime) \
52 ,{ demand(n == 1 && "lighttime"); MY(lighttime) = stof(argv(1)); \
53 }, sprintf(" %s", ftos(MY(lighttime)) \
55 on(liquidfriction, MY(liquidfriction) \
56 ,{ demand(n == 1 && "liquidfriction"); MY(liquidfriction) = stof(argv(1)); \
57 }, sprintf(" %s", ftos(MY(liquidfriction)) \
59 on(notunderwater, MY(notunderwater) \
60 ,{ demand(n == 0 && "notunderwater"); MY(notunderwater) = true; \
63 on(orientation, MY(orientation) \
64 ,{ demand(n == 1 && "orientation"); MY(orientation) = strzone(argv(1)); \
65 }, sprintf(" %s", (MY(orientation)) \
67 on(originjitter, MY(originjitter) \
68 ,{ demand(n == 3 && "originjitter"); MY(originjitter) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
69 }, sprintf(" %v", (MY(originjitter)) \
71 on(originoffset, MY(originoffset) \
72 ,{ demand(n == 3 && "originoffset"); MY(originoffset) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
73 }, sprintf(" %v", (MY(originoffset)) \
75 on(relativeoriginoffset, MY(relativeoriginoffset) \
76 ,{ demand(n == 3 && "relativeoriginoffset"); MY(relativeoriginoffset) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
77 }, sprintf(" %v", (MY(relativeoriginoffset)) \
79 on(relativevelocityoffset, MY(relativevelocityoffset) \
80 ,{ demand(n == 3 && "relativevelocityoffset"); MY(relativevelocityoffset) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
81 }, sprintf(" %v", (MY(relativevelocityoffset)) \
83 on(rotate, MY(startangle_min) || MY(startangle_max) || MY(spin_min) || MY(spin_max) \
84 ,{ 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)); \
85 }, sprintf(" %s %s %s %s", ftos(MY(startangle_min)), ftos(MY(startangle_max)), ftos(MY(spin_min)), ftos(MY(spin_max)) \
87 on(sizeincrease, MY(sizeincrease) \
88 ,{ demand(n == 1 && "sizeincrease"); MY(sizeincrease) = stof(argv(1)); \
89 }, sprintf(" %s", ftos(MY(sizeincrease)) \
91 on(size, MY(size_min) || MY(size_max) \
92 ,{ demand(n == 2 && "size"); MY(size_min) = stof(argv(1)); MY(size_max) = stof(argv(2)); \
93 }, sprintf(" %s %s", ftos(MY(size_min)), ftos(MY(size_max)) \
95 on(staincolor, MY(staincolor_min) || MY(staincolor_max) \
96 ,{ demand(n == 2 && "staincolor"); MY(staincolor_min) = strzone(argv(1)); MY(staincolor_max) = strzone(argv(2)); \
97 }, sprintf(" %s %s", (MY(staincolor_min)), (MY(staincolor_max)) \
99 on(stainsize, MY(stainsize_min) || MY(stainsize_max) \
100 ,{ demand(n == 2 && "stainsize"); MY(stainsize_min) = stof(argv(1)); MY(stainsize_max) = stof(argv(2)); \
101 }, sprintf(" %s %s", ftos(MY(stainsize_min)), ftos(MY(stainsize_max)) \
103 on(staintex, MY(staintex_min) || MY(staintex_max) \
104 ,{ demand(n == 2 && "staintex"); MY(staintex_min) = stof(argv(1)); MY(staintex_max) = stof(argv(2)); \
105 }, sprintf(" %s %s", ftos(MY(staintex_min)), ftos(MY(staintex_max)) \
107 on(stretchfactor, MY(stretchfactor) \
108 ,{ demand(n == 1 && "stretchfactor"); MY(stretchfactor) = stof(argv(1)); \
109 }, sprintf(" %s", ftos(MY(stretchfactor)) \
111 on(tex, MY(tex_min) || MY(tex_max) \
112 ,{ demand(n == 2 && "tex"); MY(tex_min) = stof(argv(1)); MY(tex_max) = stof(argv(2)); \
113 }, sprintf(" %s %s", ftos(MY(tex_min)), ftos(MY(tex_max)) \
115 on(time, MY(time_min) || MY(time_max) \
116 ,{ demand(n == 2 && "time"); MY(time_min) = stof(argv(1)); MY(time_max) = stof(argv(2)); \
117 }, sprintf(" %s %s", ftos(MY(time_min)), ftos(MY(time_max)) \
119 on(trailspacing, MY(trailspacing) \
120 ,{ demand(n == 1 && "trailspacing"); MY(trailspacing) = stof(argv(1)); \
121 }, sprintf(" %s", ftos(MY(trailspacing)) \
123 on(underwater, MY(underwater) \
124 ,{ demand(n == 0 && "underwater"); MY(underwater) = true; \
127 on(velocityjitter, MY(velocityjitter) \
128 ,{ demand(n == 3 && "velocityjitter"); MY(velocityjitter) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
129 }, sprintf(" %v", (MY(velocityjitter)) \
131 on(velocitymultiplier, MY(velocitymultiplier) \
132 ,{ demand(n == 1 && "velocitymultiplier"); MY(velocitymultiplier) = stof(argv(1)); \
133 }, sprintf(" %s", ftos(MY(velocitymultiplier)) \
135 on(velocityoffset, MY(velocityoffset) \
136 ,{ demand(n == 3 && "velocityoffset"); MY(velocityoffset) = vec3(stof(argv(1)), stof(argv(2)), stof(argv(3))); \
137 }, sprintf(" %v", (MY(velocityoffset)) \
141 CLASS(EffectInfo, Object)
142 ATTRIB(EffectInfo, effectinfo_name, string);
143 CONSTRUCTOR(EffectInfo, string s) {
144 CONSTRUCT(EffectInfo);
145 this.effectinfo_name = s;
149 MY(airfriction, float, 0) \
150 MY(alpha_min, float, 0) \
151 MY(alpha_max, float, 0) \
152 MY(alpha_fade, float, 0) \
153 MY(blend, string, string_null) \
154 MY(bounce, float, 0) \
155 MY(color_min, string, string_null) \
156 MY(color_max, string, string_null) \
157 MY(countabsolute, float, 0) \
158 MY(count, float, 0) \
159 MY(gravity, float, 0) \
160 MY(lightcolor, vector, '0 0 0') \
161 MY(lightradiusfade, float, 0) \
162 MY(lightradius, float, 0) \
163 MY(lighttime, float, 0) \
164 MY(liquidfriction, float, 0) \
165 MY(notunderwater, bool, false) \
166 MY(orientation, string, string_null) \
167 MY(originjitter, vector, '0 0 0') \
168 MY(originoffset, vector, '0 0 0') \
169 MY(relativeoriginoffset, vector, '0 0 0') \
170 MY(relativevelocityoffset, vector, '0 0 0') \
171 MY(startangle_min, float, 0) \
172 MY(startangle_max, float, 0) \
173 MY(spin_min, float, 0) \
174 MY(spin_max, float, 0) \
175 MY(sizeincrease, float, 0) \
176 MY(size_min, float, 0) \
177 MY(size_max, float, 0) \
178 MY(staincolor_min, string, string_null) \
179 MY(staincolor_max, string, string_null) \
180 MY(stainsize_min, float, 0) \
181 MY(stainsize_max, float, 0) \
182 MY(staintex_min, float, 0) \
183 MY(staintex_max, float, 0) \
184 MY(stretchfactor, float, 0) \
185 MY(tex_min, float, 0) \
186 MY(tex_max, float, 0) \
187 MY(time_min, float, 0) \
188 MY(time_max, float, 0) \
189 MY(trailspacing, float, 0) \
190 MY(type, string, string_null) \
191 MY(underwater, bool, false) \
192 MY(velocityjitter, vector, '0 0 0') \
193 MY(velocitymultiplier, float, 0) \
194 MY(velocityoffset, vector, '0 0 0') \
197 #define MY(f, type, val) ATTRIB(EffectInfo, effectinfo_##f, type, val);
201 METHOD(EffectInfo, describe, string(EffectInfo this))
203 TC(EffectInfo, this);
204 string s = sprintf("SUB(%s) {\n", this.effectinfo_name);
205 #define str_bool(it) (it ? "true" : "false")
206 #define str_float(it) ftos(it)
207 #define str_vector(it) vtos(it)
208 #define str_string(it) strcat("\"", it, "\"")
209 #define p(f, type, default) if (this.effectinfo_##f) { s = strcat(s, "\t", "MY("#f") = ", str_##type(this.effectinfo_##f), ";\n"); }
212 return strcat(s, "}\n");
215 METHOD(EffectInfo, dump, string(EffectInfo this))
217 TC(EffectInfo, this);
218 string s = sprintf("effect %s\n", this.effectinfo_name);
219 #define MY(f) this.effectinfo_##f
220 #define p(k, isset, parse, unparse) if (isset) { s = strcat(s, "\t", #k, unparse, "\n"); }
221 EFFECTINFO_PARSER(p, MY)
230 CLASS(EffectInfoGroup, Object)
231 ATTRIBARRAY(EffectInfoGroup, children, EffectInfo, 16);
232 ATTRIB(EffectInfoGroup, children_count, int, 0);
233 ENDCLASS(EffectInfoGroup)
235 void effectinfo_read()
237 int fh = fopen("effectinfo.txt", FILE_READ);
238 EffectInfo info = NULL;
239 for (string line; (line = fgets(fh)); ) {
240 int n = tokenize_console(line);
241 if (n == 0) continue;
246 info = NEW(EffectInfo, strzone(argv(1)));
249 demand(info != NULL);
251 #define MY(f) info.effectinfo_##f
252 #define p(k, isset, parse, unparse) case #k: parse break;
253 EFFECTINFO_PARSER(p, MY)
257 LOG_WARNF("Unknown property '%s'", k);
264 void effectinfo_dump(int fh, bool alsoprint)
266 #define WRITE(s) MACRO_BEGIN { \
268 if (alsoprint) LOG_INFO(s); \
270 WRITE("// ********************************************** //\n");
271 WRITE("// ** WARNING - DO NOT MANUALLY EDIT THIS FILE ** //\n");
272 WRITE("// ** ** //\n");
273 WRITE("// ** This file is automatically generated by ** //\n");
274 WRITE("// ** code with the command 'dumpeffectinfo'. ** //\n");
275 WRITE("// ** ** //\n");
276 WRITE("// ** If you modify an effect, please ** //\n");
277 WRITE("// ** regenerate this file with that command. ** //\n");
278 WRITE("// ** ** //\n");
279 WRITE("// ********************************************** //\n");
282 for (EffectInfo it = NULL; (it = findfloat(it, instanceOfEffectInfo, true)); ) {
283 if (it.classname == "vtbl") continue;
284 string s = it.dump(it);
290 GENERIC_COMMAND(dumpeffectinfo, "Dump all effectinfo to effectinfo_dump.txt")
293 case CMD_REQUEST_COMMAND: {
294 string filename = argv(1);
295 bool alsoprint = false;
296 if (filename == "") {
297 filename = "effectinfo_dump.txt";
299 } else if (filename == "-") {
300 filename = "effectinfo_dump.txt";
303 int fh = fopen(filename, FILE_WRITE);
305 effectinfo_dump(fh, alsoprint);
306 LOG_INFOF("Dumping effectinfo... File located at ^2data/data/%s^7.\n", filename);
307 LOG_INFOF("Reload with ^2cl_particles_reloadeffects data/%s^7.\n", filename);
310 LOG_WARNF("Could not open file '%s'!", filename);
315 case CMD_REQUEST_USAGE: {
316 LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpeffectinfo [filename]"));
317 LOG_INFO(" Where 'filename' is the file to write (default is effectinfo_dump.txt),\n");
318 LOG_INFO(" if supplied with '-' output to console as well as default,\n");
319 LOG_INFO(" if left blank, it will only write to default.\n");
326 REGISTRY(EffectInfos, BITS(9))
327 #define EffectInfos_from(i) _EffectInfos_from(i, NULL)
328 REGISTER_REGISTRY(EffectInfos)
329 #define EFFECTINFO(name) \
330 [[accumulate]] void effectinfo_##name(EffectInfoGroup parent, EffectInfo this) { } \
331 REGISTER(EffectInfos, EFFECTINFO, name, m_id, NEW(EffectInfoGroup)) { \
332 effectinfo_##name(this, NULL); \
335 #define MY(f) this.effectinfo_##f
336 #define DEF(name) EFFECTINFO(name)
338 [[accumulate]] void effectinfo_##name(EffectInfoGroup parent, EffectInfo this) { parent = EFFECTINFO_##name; parent.children[parent.children_count++] = this = NEW(EffectInfo, #name); } \
339 [[accumulate]] void effectinfo_##name(EffectInfoGroup parent, EffectInfo this)
340 #include "effectinfo.inc"