X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Flib%2Fspawnfunc.qh;h=c9bfebabd415c4414eea269638f686fbd4a94f6b;hb=40b838075e618d6075fdaa25f2f00b223be3712e;hp=f1eb477a00195188c942ca3f7d5ce6b889343d1a;hpb=2dbcd3c5a4a458b9e83f3b037ca1d951f73755c3;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/lib/spawnfunc.qh b/qcsrc/lib/spawnfunc.qh index f1eb477a0..c9bfebabd 100644 --- a/qcsrc/lib/spawnfunc.qh +++ b/qcsrc/lib/spawnfunc.qh @@ -1,8 +1,14 @@ #pragma once +// remove this ifdef when client or menu will actually make use of this stuff +#ifdef SVQC + /** If this global exists, only functions with spawnfunc_ name prefix qualify as spawn functions */ noref bool require_spawnfunc_prefix; .bool spawnfunc_checked; +/** Not for production use, provides access to a dump of the entity's fields when it is parsed from map data */ +noref string __fullspawndata; +.string fullspawndata; // Optional type checking; increases compile time too much to be enabled by default #if 0 @@ -19,13 +25,13 @@ noref bool require_spawnfunc_prefix; } #define _spawnfunc_checktypes(fld) \ - if (fieldname == #fld) \ - if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted", fieldname); + if (s == #fld) \ + if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted", s); #else #define _spawnfunc_checktypes(fld) #endif #define _spawnfunc_check(fld) \ - if (fieldname == #fld) continue; + if (s == #fld) continue; noref int __spawnfunc_expecting; noref entity __spawnfunc_expect; @@ -36,6 +42,10 @@ noref bool require_spawnfunc_prefix; #define SPAWNFUNC_INTERNAL_FIELDS(X) \ X(string, classname, "spawnfunc") \ + X(string, target, string_null) \ + X(string, target2, string_null) \ + X(string, target3, string_null) \ + X(string, target4, string_null) \ X(string, targetname, string_null) \ /**/ @@ -77,58 +87,6 @@ noref bool require_spawnfunc_prefix; e.__spawnfunc_constructor(e); } - noref bool __spawnfunc_first; - - #define spawnfunc_1(id) spawnfunc_2(id, FIELDS_UNION) - #define spawnfunc_2(id, whitelist) \ - void __spawnfunc_##id(entity this); \ - [[accumulate]] void spawnfunc_##id(entity this) \ - { \ - if (!__spawnfunc_first) { \ - __spawnfunc_first = true; \ - static_init_early(); \ - } \ - bool dospawn = true; \ - if (__spawnfunc_expecting > 1) { __spawnfunc_expecting = false; } \ - else if (__spawnfunc_expecting) { \ - /* engine call */ \ - if (!g_spawn_queue) { g_spawn_queue = IL_NEW(); } \ - __spawnfunc_expecting = false; \ - this = __spawnfunc_expect; \ - __spawnfunc_expect = NULL; \ - dospawn = false; \ - } else { \ - /* userland call */ \ - assert(this); \ - } \ - if (!this.sourceLoc) { \ - this.sourceLoc = __FILE__ ":" STR(__LINE__); \ - } \ - if (!this.spawnfunc_checked) { \ - for (int i = 0, n = numentityfields(); i < n; ++i) { \ - string value = getentityfieldstring(i, this); \ - string fieldname = entityfieldname(i); \ - whitelist(_spawnfunc_checktypes) \ - if (value == "") continue; \ - if (fieldname == "") continue; \ - FIELDS_COMMON(_spawnfunc_check) \ - whitelist(_spawnfunc_check) \ - LOG_WARNF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue."), #id, fieldname, value); \ - } \ - this.spawnfunc_checked = true; \ - if (this) { \ - /* not worldspawn, delay spawn */ \ - __spawnfunc_defer(this, __spawnfunc_##id); \ - } else { \ - /* world might not be "worldspawn" */ \ - this.__spawnfunc_constructor = __spawnfunc_##id; \ - } \ - } \ - if (dospawn) { __spawnfunc_##id(this); } \ - if (__spawnfunc_unreachable_workaround) return; \ - } \ - void __spawnfunc_##id(entity this) - #define FIELD_SCALAR(fld, n) \ fld(n) #define FIELD_VEC(fld, n) \ @@ -152,12 +110,14 @@ noref bool require_spawnfunc_prefix; FIELD_SCALAR(fld, ammo_cells) \ FIELD_SCALAR(fld, ammo_nails) \ FIELD_SCALAR(fld, ammo_rockets) \ + FIELD_SCALAR(fld, antiwall_flag) \ FIELD_SCALAR(fld, armorvalue) \ FIELD_SCALAR(fld, atten) \ FIELD_SCALAR(fld, bgmscriptdecay) \ FIELD_SCALAR(fld, bgmscriptsustain) \ FIELD_SCALAR(fld, bgmscript) \ FIELD_SCALAR(fld, button0) \ + FIELD_SCALAR(fld, chmap) \ FIELD_SCALAR(fld, cnt) \ FIELD_SCALAR(fld, colormap) \ FIELD_SCALAR(fld, count) \ @@ -165,6 +125,8 @@ noref bool require_spawnfunc_prefix; FIELD_SCALAR(fld, cvarfilter) \ FIELD_SCALAR(fld, debrisdamageforcescale) \ FIELD_SCALAR(fld, debrisfadetime) \ + FIELD_SCALAR(fld, debrismovetype) \ + FIELD_SCALAR(fld, debrisskin) \ FIELD_SCALAR(fld, debristimejitter) \ FIELD_SCALAR(fld, debristime) \ FIELD_SCALAR(fld, debris) \ @@ -175,24 +137,31 @@ noref bool require_spawnfunc_prefix; FIELD_SCALAR(fld, dmg_force) \ FIELD_SCALAR(fld, dmg_radius) \ FIELD_SCALAR(fld, effects) \ + FIELD_SCALAR(fld, falloff) \ FIELD_SCALAR(fld, flags) \ FIELD_SCALAR(fld, fog) \ FIELD_SCALAR(fld, frags) \ FIELD_SCALAR(fld, frame) \ + FIELD_SCALAR(fld, gametype) \ FIELD_SCALAR(fld, gametypefilter) \ FIELD_SCALAR(fld, geomtype) \ FIELD_SCALAR(fld, gravity) \ FIELD_SCALAR(fld, health) \ FIELD_SCALAR(fld, height) \ FIELD_SCALAR(fld, impulse) \ + FIELD_SCALAR(fld, invincible_finished) \ + FIELD_SCALAR(fld, invisibility_finished) \ + FIELD_SCALAR(fld, item_pickupsound) \ FIELD_SCALAR(fld, killtarget) \ FIELD_SCALAR(fld, lerpfrac) \ FIELD_SCALAR(fld, light_lev) \ FIELD_SCALAR(fld, lip) \ FIELD_SCALAR(fld, loddistance1) \ FIELD_SCALAR(fld, lodmodel1) \ + FIELD_SCALAR(fld, lodmodel2) \ FIELD_SCALAR(fld, ltime) \ FIELD_SCALAR(fld, map) \ + FIELD_SCALAR(fld, max_health) \ FIELD_SCALAR(fld, mdl) \ FIELD_SCALAR(fld, message2) \ FIELD_SCALAR(fld, message) \ @@ -204,15 +173,25 @@ noref bool require_spawnfunc_prefix; FIELD_SCALAR(fld, monster_name) \ FIELD_SCALAR(fld, movetype) \ FIELD_SCALAR(fld, move_movetype) \ + FIELD_SCALAR(fld, music) \ FIELD_SCALAR(fld, netname) \ FIELD_SCALAR(fld, nextthink) \ FIELD_SCALAR(fld, noalign) \ FIELD_SCALAR(fld, noise1) \ FIELD_SCALAR(fld, noise2) \ + FIELD_SCALAR(fld, noise3) \ FIELD_SCALAR(fld, noise) \ + FIELD_SCALAR(fld, notcpm) \ + FIELD_SCALAR(fld, notfree) \ + FIELD_SCALAR(fld, notsingle) \ + FIELD_SCALAR(fld, notta) \ + FIELD_SCALAR(fld, notteam) \ + FIELD_SCALAR(fld, notvq3) \ FIELD_SCALAR(fld, phase) \ FIELD_SCALAR(fld, platmovetype) \ FIELD_SCALAR(fld, race_place) \ + FIELD_SCALAR(fld, speed_finished) \ + FIELD_SCALAR(fld, strength_finished) \ FIELD_SCALAR(fld, radius) \ FIELD_SCALAR(fld, respawntimestart) \ FIELD_SCALAR(fld, respawntimejitter) \ @@ -236,8 +215,13 @@ noref bool require_spawnfunc_prefix; FIELD_SCALAR(fld, target_random) \ FIELD_SCALAR(fld, target_range) \ FIELD_SCALAR(fld, team) \ + FIELD_SCALAR(fld, trigger_reverse) \ + FIELD_SCALAR(fld, turret_scale_aim) \ + FIELD_SCALAR(fld, turret_scale_ammo) \ + FIELD_SCALAR(fld, turret_scale_damage) \ FIELD_SCALAR(fld, turret_scale_health) \ FIELD_SCALAR(fld, turret_scale_range) \ + FIELD_SCALAR(fld, turret_scale_refire) \ FIELD_SCALAR(fld, turret_scale_respawn) \ FIELD_SCALAR(fld, volume) \ FIELD_SCALAR(fld, wait) \ @@ -249,14 +233,87 @@ noref bool require_spawnfunc_prefix; FIELD_VEC(fld, absmin) \ FIELD_VEC(fld, angles) \ FIELD_VEC(fld, avelocity) \ + FIELD_VEC(fld, beam_color)\ + FIELD_VEC(fld, debrisavelocityjitter) \ + FIELD_VEC(fld, debrisvelocity) \ + FIELD_VEC(fld, debrisvelocityjitter) \ FIELD_VEC(fld, color) \ FIELD_VEC(fld, mangle) \ FIELD_VEC(fld, maxs) \ - FIELD_VEC(fld, maxs) \ FIELD_VEC(fld, mins) \ FIELD_VEC(fld, modelscale_vec) \ FIELD_VEC(fld, velocity) \ /**/ - #define spawnfunc(...) EVAL_spawnfunc(OVERLOAD(spawnfunc, __VA_ARGS__)) - #define EVAL_spawnfunc(...) __VA_ARGS__ +ERASEABLE +void _checkWhitelisted(entity this, string id) +{ + for (int i = 0, n = numentityfields(); i < n; ++i) + { + string value = getentityfieldstring(i, this); + string s = entityfieldname(i); + FIELDS_UNION(_spawnfunc_checktypes) + if (value == "") continue; + if (s == "") continue; + FIELDS_COMMON(_spawnfunc_check) + FIELDS_UNION(_spawnfunc_check) + LOG_WARNF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue."), id, s, value); + } +} + +// this function simply avoids expanding IL_NEW during compilation +// for each spawning entity +void g_spawn_queue_spawn() { g_spawn_queue = IL_NEW(); } + +noref bool __spawnfunc_first; + +#define spawnfunc(id) \ + void __spawnfunc_##id(entity this); \ + ACCUMULATE void spawnfunc_##id(entity this) \ + { \ + if (!__spawnfunc_first) { \ + __spawnfunc_first = true; \ + static_init_early(); \ + } \ + bool dospawn = true; \ + if (__spawnfunc_expecting > 1) { __spawnfunc_expecting = 0; } \ + else if (__spawnfunc_expecting) { \ + /* engine call */ \ + if (!g_spawn_queue) g_spawn_queue_spawn(); \ + __spawnfunc_expecting = 0; \ + this = __spawnfunc_expect; \ + __spawnfunc_expect = NULL; \ + dospawn = false; \ + } else { \ + /* userland call */ \ + assert(this); \ + } \ + if (!this.sourceLoc) { \ + this.sourceLoc = __FILE__":"STR(__LINE__); \ + } \ + this.classname = #id; \ + if (!this.spawnfunc_checked) { \ + _checkWhitelisted(this, #id); \ + if (__fullspawndata) { \ + /* not supported in old DP */ \ + /* must be read inside the real spawnfunc */ \ + this.fullspawndata = __fullspawndata; \ + } \ + this.spawnfunc_checked = true; \ + if (this) { \ + /* not worldspawn, delay spawn */ \ + /* clear some dangerous fields (TODO: properly support these in the map!) */ \ + this.think = func_null; \ + this.nextthink = 0; \ + __spawnfunc_defer(this, __spawnfunc_##id); \ + } else { \ + /* world might not be "worldspawn" */ \ + this.__spawnfunc_constructor = __spawnfunc_##id; \ + } \ + } \ + if (dospawn) { __spawnfunc_##id(this); } \ + if (__spawnfunc_unreachable_workaround) return; \ + } \ + void __spawnfunc_##id(entity this) + +#endif