X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fweapons%2Fall.qh;h=929564c3ef8504efa2f77a5b1916da72109a4829;hb=c2d50c76c59b481a0b0e29a205f5e0dfc9f95630;hp=ecfe58199e135ae4e91a079c9d2b5c252f2a710a;hpb=1245fb3e998e9ace1b301dbe4bfb84b55f25bdf4;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/weapons/all.qh b/qcsrc/common/weapons/all.qh index ecfe58199..929564c3e 100644 --- a/qcsrc/common/weapons/all.qh +++ b/qcsrc/common/weapons/all.qh @@ -2,15 +2,12 @@ #define WEAPONS_ALL_H #include "../command/all.qh" +#include "../stats.qh" #include "config.qh" // weapon sets typedef vector WepSet; -#define WEPSET(id) WepSet_FromWeapon(WEP_##id.m_id) -WepSet WepSet_FromWeapon(int a); #ifdef SVQC -void WepSet_AddStat(); -void WepSet_AddStat_InMap(); void WriteWepSet(float dest, WepSet w); #endif @@ -34,10 +31,15 @@ WepSet ReadWepSet(); #endif REGISTRY(Weapons, 72) // Increase as needed. Can be up to 72. -REGISTER_REGISTRY(RegisterWeapons) +#define Weapons_from(i) _Weapons_from(i, WEP_Null) +REGISTER_REGISTRY(Weapons) STATIC_INIT(WeaponPickup) { FOREACH(Weapons, true, LAMBDA(it.m_pickup = NEW(WeaponPickup, it))); } -entity get_weaponinfo(int id); +.WepSet m_wepset; +#define WEPSET(id) (WEP_##id.m_wepset) +#define WepSet_FromWeapon(it) ((it).m_wepset) +WepSet _WepSet_FromWeapon(int i); +STATIC_INIT(WepSets) { FOREACH(Weapons, true, LAMBDA(it.m_wepset = _WepSet_FromWeapon(it.m_id))); } GENERIC_COMMAND(dumpweapons, "Dump all weapons into weapons_dump.txt") // WEAPONTODO: make this work with other progs than just server { @@ -92,98 +94,242 @@ GENERIC_COMMAND(dumpweapons, "Dump all weapons into weapons_dump.txt") // WEAPON } } -#define REGISTER_WEAPON(id, inst) \ - /* WepSet WEPSET_##id; */ \ - REGISTER(RegisterWeapons, WEP, Weapons, id, m_id, inst) +#ifdef SVQC +entity W_PROP_reloader; +float autocvar_w_prop_interval = 0; +.void(Weapon this, int) wr_net; +void W_PROP_reload(int chan, entity to) +{ + W_PROP_reloader.nextthink = time + autocvar_w_prop_interval; + msg_entity = to; + FOREACH(Weapons, true, { + it.wr_update(it); + void(Weapon, int) f = it.wr_net; + if (f) f(it, chan); + }); +} +void W_PROP_think() +{ + W_PROP_reload(MSG_ALL, NULL); +} +STATIC_INIT_LATE(W_PROP_reloader) +{ + entity e = W_PROP_reloader = new(W_PROP_reloader); + make_pure(e); + WITH(entity, self, e, (e.think = W_PROP_think)()); +} +#endif -// create cvars for weapon settings -#define WEP_ADD_CVAR_NONE(wepname,name) [[last]] float autocvar_g_balance_##wepname##_##name; +#define REGISTER_WEAPON(...) EVAL(OVERLOAD(REGISTER_WEAPON, __VA_ARGS__)) +#define REGISTER_WEAPON_2(id, inst) REGISTER(Weapons, WEP, id, m_id, inst) +/** TODO: deprecated - remove */ +#define REGISTER_WEAPON_3(id, sname, inst) \ + REGISTER_WEAPON_2(id, inst); \ + [[alias("WEP_" #id)]] Weapon _wep_##sname -#define WEP_ADD_CVAR_PRI(wepname,name) WEP_ADD_CVAR_NONE(wepname, primary_##name) -#define WEP_ADD_CVAR_SEC(wepname,name) WEP_ADD_CVAR_NONE(wepname, secondary_##name) -#define WEP_ADD_CVAR_BOTH(wepname,name) \ - WEP_ADD_CVAR_PRI(wepname, name) \ - WEP_ADD_CVAR_SEC(wepname, name) +REGISTER_WEAPON(Null, NEW(Weapon)); -#define WEP_ADD_CVAR(wepid,wepname,mode,name) WEP_ADD_CVAR_##mode(wepname, name) +Weapon Weapons_fromstr(string s) +{ + FOREACH(Weapons, it != WEP_Null && it.netname == s, return it); + return NULL; +} -// create properties for weapon settings -#define WEP_ADD_PROP(wepid,wepname,type,prop,name) \ - .type prop; \ - [[last]] type autocvar_g_balance_##wepname##_##name; -// read cvars from weapon settings -#define WEP_CVAR(wepname,name) autocvar_g_balance_##wepname##_##name -#define WEP_CVAR_PRI(wepname,name) WEP_CVAR(wepname, primary_##name) -#define WEP_CVAR_SEC(wepname,name) WEP_CVAR(wepname, secondary_##name) -#define WEP_CVAR_BOTH(wepname,isprimary,name) ((isprimary) ? WEP_CVAR_PRI(wepname, name) : WEP_CVAR_SEC(wepname, name)) +// legacy w_prop mappings +#define X(fld, T) .T fld; .T wepvar_##fld = fld; +X(switchdelay_drop, float) +X(switchdelay_raise, float) +X(weaponreplace, string) +X(weaponstartoverride, float) +X(weaponstart, float) +X(weaponthrowable, float) +X(reload_ammo, float) +.float reloading_ammo = reload_ammo; +X(reload_time, float) +.float reloading_time = reload_time; +#undef X + + + +#define W_PROPS(L, class, prefix) \ + L(W_PROP_BEGIN, W_PROP, W_PROP_END, class, prefix) \ + L(W_CONFIG_BEGIN, W_CONFIG, W_CONFIG_END, class, prefix) \ + L(W_UPDATE_BEGIN, W_UPDATE, W_UPDATE_END, class, prefix) \ + L(W_NET_BEGIN, W_NET, W_NET_END, class, prefix) \ + /**/ \ + + + #define W_PROP(class, wepname, fld, T, m) W_PROP_##m(class, fld, T, wepname) + #define W_PROP_NONE(class, fld, T, wepname) _W_PROP(class, fld, T, wepname) + #define W_PROP_PRI(class, fld, T, wepname) _W_PROP(class, primary_##fld, T, wepname) + #define W_PROP_SEC(class, fld, T, wepname) _W_PROP(class, secondary_##fld, T, wepname) + #define W_PROP_BOTH(class, fld, T, wepname) \ + W_PROP_PRI(class, fld, T, wepname) \ + W_PROP_SEC(class, fld, T, wepname) + #define W_PROP_BEGIN(class) + #define _W_PROP(class, fld, T, wepname) \ + /* static */ T _W_PROP_CVAR(wepname, fld); \ + ATTRIB(class, wepvar_##fld, T, _W_PROP_CVAR(wepname, fld)); + #define _W_PROP_CVAR(wepname, fld) autocvar_g_balance_##wepname##_##fld + #define W_PROP_END() + + + + #define W_CONFIG(class, wepname, fld, T, m) W_CONFIG_##m(class, fld, T, wepname) + #define W_CONFIG_NONE(class, fld, T, wepname) _W_CONFIG(class, fld, T, wepname) + #define W_CONFIG_PRI(class, fld, T, wepname) _W_CONFIG(class, primary_##fld, T, wepname) + #define W_CONFIG_SEC(class, fld, T, wepname) _W_CONFIG(class, secondary_##fld, T, wepname) + #define W_CONFIG_BOTH(class, fld, T, wepname) \ + W_CONFIG_PRI(class, fld, T, wepname) \ + W_CONFIG_SEC(class, fld, T, wepname) + #define W_CONFIG_BEGIN(class) METHOD(class, wr_config, void(class this)) { + #ifdef SVQC + #define _W_CONFIG(class, fld, T, wepname) if (#wepname == this.netname) WEP_CONFIG_WRITE_CVARS(wepname, fld, T); + #else + #define _W_CONFIG(class, fld, T, wepname) + #endif + #define W_CONFIG_END() } + + + #define W_UPDATE(class, wepname, fld, T, m) W_UPDATE_##m(class, fld, T, wepname) + #define W_UPDATE_NONE(class, fld, T, wepname) _W_UPDATE(class, fld, T, wepname) + #define W_UPDATE_PRI(class, fld, T, wepname) _W_UPDATE(class, primary_##fld, T, wepname) + #define W_UPDATE_SEC(class, fld, T, wepname) _W_UPDATE(class, secondary_##fld, T, wepname) + #define W_UPDATE_BOTH(class, fld, T, wepname) \ + W_UPDATE_PRI(class, fld, T, wepname) \ + W_UPDATE_SEC(class, fld, T, wepname) + .entity baseline, baseline_target; + #define W_UPDATE_BEGIN(class) \ + METHOD(class, wr_update, void(class this)) \ + { \ + noref entity b = this.baseline; \ + if (!b) \ + { \ + b = this.baseline = new(baseline); \ + make_pure(b); \ + b.baseline_target = this; \ + } + #ifdef SVQC + #define _W_UPDATE(class, fld, T, wepname) \ + { \ + T it = _W_PROP_CVAR(wepname, fld); \ + b.wepvar_##fld = this.wepvar_##fld; \ + this.wepvar_##fld = it; \ + } + #else + #define _W_UPDATE(class, fld, T, wepname) + #endif + #define W_UPDATE_END() } + + + #define W_NET(class, wepname, fld, T, m) W_NET_##m(class, fld, T, wepname) + #define W_NET_NONE(class, fld, T, wepname) _W_NET(class, fld, T, wepname) + #define W_NET_PRI(class, fld, T, wepname) _W_NET(class, primary_##fld, T, wepname) + #define W_NET_SEC(class, fld, T, wepname) _W_NET(class, secondary_##fld, T, wepname) + #define W_NET_BOTH(class, fld, T, wepname) \ + W_NET_PRI(class, fld, T, wepname) \ + W_NET_SEC(class, fld, T, wepname) + REGISTER_NET_TEMP(WeaponUpdate) + #if defined(CSQC) + #define W_NET_BEGIN(class) METHOD(class, wr_net, void(class this, int i)) { int n = 0; + #define _W_NET(class, fld, T, wepname) \ + { \ + if (++n == i) this.wepvar_##fld = Read_##T(); \ + } + .void(Weapon this, int i) wr_net; + NET_HANDLE(WeaponUpdate, bool isnew) + { + Weapon w = Weapons_from(ReadByte()); + for (int i; (i = ReadByte()); ) + { + w.wr_net(w, i); + } + return true; + } + #define W_NET_END() } + #elif defined(SVQC) + #define W_NET_BEGIN(class) \ + METHOD(class, wr_net, void(class this, int chan)) \ + { \ + bool commit = false; \ + int i = 0; + #define _W_NET(class, fld, T, wepname) \ + { \ + ++i; \ + T it = this.wepvar_##fld; \ + if (chan == MSG_ONE || it != this.baseline.wepvar_##fld) \ + { \ + if (!commit) { commit = true; WriteHeader(chan, WeaponUpdate); WriteByte(chan, this.m_id); } \ + WriteByte(chan, i); Write_##T(chan, it); \ + } \ + } + #define W_NET_END() \ + if (commit) WriteByte(chan, 0); \ + } + #else + #define W_NET_BEGIN(class) + #define _W_NET(class, fld, T, wepname) + #define W_NET_END() + #endif -// set initialization values for weapon settings -#define WEP_SKIP_CVAR(unuseda,unusedb,unusedc,unusedd) /* skip cvars */ -#define WEP_SET_PROP(wepid,wepname,type,prop,name) WEP_##wepid.prop = autocvar_g_balance_##wepname##_##name; + + +// read cvars from weapon settings +#define WEP_CVAR(wepname, name) (_wep_##wepname.wepvar_##name) +#define WEP_CVAR_PRI(wepname, name) WEP_CVAR(wepname, primary_##name) +#define WEP_CVAR_SEC(wepname, name) WEP_CVAR(wepname, secondary_##name) +#define WEP_CVAR_BOTH(wepname, isprimary, name) ((isprimary) ? WEP_CVAR_PRI(wepname, name) : WEP_CVAR_SEC(wepname, name)) const int WEP_FIRST = 1; #define WEP_LAST (Weapons_COUNT - 1) WepSet WEPSET_ALL; WepSet WEPSET_SUPERWEAPONS; -REGISTER_WEAPON(Null, NEW(Weapon)); - #include "all.inc" -entity get_weaponinfo(int id) -{ - if (id >= WEP_FIRST && id <= WEP_LAST) { - Weapon w = Weapons[id]; - if (w) return w; - } - return WEP_Null; -} - // TODO: remove after 0.8.2. Retains impulse number compatibility because 0.8.1 clients don't reload the weapons.cfg -#define WEP_HARDCODED_IMPULSES 22 +#define WEP_HARDCODED_IMPULSES 20 // TODO: invert after 0.8.2. Will require moving 'best weapon' impulses #define WEP_IMPULSE_BEGIN 230 #define WEP_IMPULSE_END bound(WEP_IMPULSE_BEGIN, WEP_IMPULSE_BEGIN + (Weapons_COUNT - 1) - 1, 253) -REGISTRY_SORT(Weapons, netname, WEP_HARDCODED_IMPULSES + 1) +REGISTRY_SORT(Weapons, WEP_HARDCODED_IMPULSES + 1) +REGISTRY_CHECK(Weapons) STATIC_INIT(register_weapons_done) { FOREACH(Weapons, true, LAMBDA( it.m_id = i; - WepSet set = WepSet_FromWeapon(it.m_id); + WepSet set = it.m_wepset; WEPSET_ALL |= set; if ((it.spawnflags) & WEP_FLAG_SUPERWEAPON) WEPSET_SUPERWEAPONS |= set; - it.weapon = it.m_id; it.weapons = set; + if (it == WEP_Null) continue; int imp = WEP_IMPULSE_BEGIN + it.m_id - 1; if (imp <= WEP_IMPULSE_END) localcmd(sprintf("alias weapon_%s \"impulse %d\"\n", it.netname, imp)); else - LOG_TRACEF(_("Impulse limit exceeded, weapon will not be directly accessible: %s\n"), it.netname); + LOG_TRACEF("Impulse limit exceeded, weapon will not be directly accessible: %s\n", it.netname); )); #ifdef CSQC FOREACH(Weapons, true, LAMBDA(it.wr_init(it))); #endif weaponorder_byid = ""; for (int i = Weapons_MAX - 1; i >= 1; --i) - if (Weapons[i]) + if (Weapons_from(i)) weaponorder_byid = strcat(weaponorder_byid, " ", ftos(i)); - weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1)); + weaponorder_byid = strzone(substring(weaponorder_byid, 1, -1)); } #ifndef MENUQC -.entity weaponentity[MAX_WEAPONSLOTS]; .entity weaponchild; .entity exteriorweaponentity; .vector weaponentity_glowmod; //.int weapon; // current weapon -.int switchweapon; // weapon requested to switch to -.int switchingweapon; // weapon currently being switched to (is copied from switchweapon once switch is possible) .string weaponname; // name of .weapon .vector spawnorigin; // for casings @@ -195,13 +341,16 @@ STATIC_INIT(register_weapons_done) .vector anim_reload; // static frame globals -.int wframe; -const float WFRAME_DONTCHANGE = -1; -const float WFRAME_FIRE1 = 0; -const float WFRAME_FIRE2 = 1; -const float WFRAME_IDLE = 2; -const float WFRAME_RELOAD = 3; +ENUMCLASS(WFRAME) +CASE(WFRAME, DONTCHANGE) +CASE(WFRAME, FIRE1) +CASE(WFRAME, FIRE2) +CASE(WFRAME, IDLE) +CASE(WFRAME, RELOAD) +ENUMCLASS_END(WFRAME) + +.WFRAME wframe; vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn); void CL_WeaponEntity_SetModel(entity this, string name);