X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fcommon%2Fweapons%2Fall.qc;h=849403f8713740773c0c7d780b6213b073064f96;hp=f7ba35cc407ed9e2cea30a5bd6af2dc604da5fef;hb=201f6309c92217b63dc34daf004fbb7424096eca;hpb=ca72730bfd00d5f872bf27931adc42e3d67ff2bb diff --git a/qcsrc/common/weapons/all.qc b/qcsrc/common/weapons/all.qc index f7ba35cc40..849403f871 100644 --- a/qcsrc/common/weapons/all.qc +++ b/qcsrc/common/weapons/all.qc @@ -45,7 +45,7 @@ #include "../../server/g_hook.qh" #endif #ifndef MENUQC -#include "calculations.qc" + #include "calculations.qc" #endif #define IMPLEMENTATION #include "all.inc" @@ -53,48 +53,46 @@ // WEAPON PLUGIN SYSTEM -WepSet _WepSet_FromWeapon(int a) { +WepSet _WepSet_FromWeapon(int a) +{ a -= WEP_FIRST; if (Weapons_MAX > 24) - if (a >= 24) { - a -= 24; - if (Weapons_MAX > 48) - if (a >= 24) { + if (a >= 24) + { a -= 24; - return '0 0 1' * power2of(a); + if (Weapons_MAX > 48) + if (a >= 24) + { + a -= 24; + return '0 0 1' * power2of(a); + } + return '0 1 0' * power2of(a); } - return '0 1 0' * power2of(a); - } return '1 0 0' * power2of(a); } #ifdef SVQC -void WriteWepSet(float dst, WepSet w) -{ - if (Weapons_MAX > 48) - WriteInt72_t(dst, w); - else if (Weapons_MAX > 24) - WriteInt48_t(dst, w); - else - WriteInt24_t(dst, w.x); -} + void WriteWepSet(float dst, WepSet w) + { + if (Weapons_MAX > 48) WriteInt72_t(dst, w); + else if (Weapons_MAX > 24) WriteInt48_t(dst, w); + else WriteInt24_t(dst, w.x); + } #endif #ifdef CSQC -WepSet WepSet_GetFromStat() -{ - return STAT(WEAPONS); -} -WepSet WepSet_GetFromStat_InMap() -{ - return STAT(WEAPONSINMAP); -} -WepSet ReadWepSet() -{ - if (Weapons_MAX > 48) - return ReadInt72_t(); - if (Weapons_MAX > 24) - return ReadInt48_t(); - return ReadInt24_t() * '1 0 0'; -} + WepSet WepSet_GetFromStat() + { + return STAT(WEAPONS); + } + WepSet WepSet_GetFromStat_InMap() + { + return STAT(WEAPONSINMAP); + } + WepSet ReadWepSet() + { + if (Weapons_MAX > 48) return ReadInt72_t(); + if (Weapons_MAX > 24) return ReadInt48_t(); + return ReadInt24_t() * '1 0 0'; + } #endif string W_FixWeaponOrder(string order, float complete) @@ -104,26 +102,25 @@ string W_FixWeaponOrder(string order, float complete) string W_NameWeaponOrder_MapFunc(string s) { entity wi; - if(s == "0" || stof(s)) + if (s == "0" || stof(s)) { wi = get_weaponinfo(stof(s)); - if(wi != WEP_Null) - return wi.netname; + if (wi != WEP_Null) return wi.netname; } return s; } string W_UndeprecateName(string s) { - switch ( s ) + switch (s) { - case "nex" : return "vortex"; - case "rocketlauncher" : return "devastator"; - case "laser" : return "blaster"; - case "minstanex" : return "vaporizer"; + case "nex": return "vortex"; + case "rocketlauncher": return "devastator"; + case "laser": return "blaster"; + case "minstanex": return "vaporizer"; case "grenadelauncher": return "mortar"; - case "uzi" : return "machinegun"; - default : return s; + case "uzi": return "machinegun"; + default: return s; } } string W_NameWeaponOrder(string order) @@ -133,12 +130,10 @@ string W_NameWeaponOrder(string order) string W_NumberWeaponOrder_MapFunc(string s) { int i; - if(s == "0" || stof(s)) - return s; + if (s == "0" || stof(s)) return s; s = W_UndeprecateName(s); - for(i = WEP_FIRST; i <= WEP_LAST; ++i) - if(s == get_weaponinfo(i).netname) - return ftos(i); + for (i = WEP_FIRST; i <= WEP_LAST; ++i) + if (s == get_weaponinfo(i).netname) return ftos(i); return s; } string W_NumberWeaponOrder(string order) @@ -162,23 +157,24 @@ float W_FixWeaponOrder_BuildImpulseList_cmp(int i, int j, entity pass) e1 = get_weaponinfo(W_FixWeaponOrder_BuildImpulseList_buf[i]); e2 = get_weaponinfo(W_FixWeaponOrder_BuildImpulseList_buf[j]); d = (e1.impulse + 9) % 10 - (e2.impulse + 9) % 10; - if(d != 0) - return -d; // high impulse first! - return - strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[i]), 0) - - - strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[j]), 0) - ; // low char index first! + if (d != 0) return -d; // high impulse first! + return strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), + sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[i]), 0) + - + strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), + sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[j]), 0) + ; // low char index first! } string W_FixWeaponOrder_BuildImpulseList(string o) { int i; W_FixWeaponOrder_BuildImpulseList_order = o; - for(i = WEP_FIRST; i <= WEP_LAST; ++i) + for (i = WEP_FIRST; i <= WEP_LAST; ++i) W_FixWeaponOrder_BuildImpulseList_buf[i - WEP_FIRST] = i; - heapsort(WEP_LAST - WEP_FIRST + 1, W_FixWeaponOrder_BuildImpulseList_swap, W_FixWeaponOrder_BuildImpulseList_cmp, world); + heapsort(WEP_LAST - WEP_FIRST + 1, W_FixWeaponOrder_BuildImpulseList_swap, W_FixWeaponOrder_BuildImpulseList_cmp, + world); o = ""; - for(i = WEP_FIRST; i <= WEP_LAST; ++i) + for (i = WEP_FIRST; i <= WEP_LAST; ++i) o = strcat(o, " ", ftos(W_FixWeaponOrder_BuildImpulseList_buf[i - WEP_FIRST])); W_FixWeaponOrder_BuildImpulseList_order = string_null; return substring(o, 1, -1); @@ -191,8 +187,7 @@ string W_FixWeaponOrder_AllowIncomplete(string order) string W_FixWeaponOrder_ForceComplete(string order) { - if(order == "") - order = W_NumberWeaponOrder(cvar_defstring("cl_weaponpriority")); + if (order == "") order = W_NumberWeaponOrder(cvar_defstring("cl_weaponpriority")); return W_FixWeaponOrder(order, 1); } @@ -203,12 +198,11 @@ void W_RandomWeapons(entity e, float n) WepSet result; remaining = e.weapons; result = '0 0 0'; - for(i = 0; i < n; ++i) + for (i = 0; i < n; ++i) { RandomSelection_Init(); - for(j = WEP_FIRST; j <= WEP_LAST; ++j) - if(remaining & WepSet_FromWeapon(j)) - RandomSelection_Add(world, j, string_null, 1, 1); + for (j = WEP_FIRST; j <= WEP_LAST; ++j) + if (remaining & WepSet_FromWeapon(j)) RandomSelection_Add(world, j, string_null, 1, 1); result |= WepSet_FromWeapon(RandomSelection_chosen_float); remaining &= ~WepSet_FromWeapon(RandomSelection_chosen_float); } @@ -225,48 +219,48 @@ string GetAmmoPicture(.int ammotype) case ammo_cells: return ITEM_Cells.m_icon; case ammo_plasma: return ITEM_Plasma.m_icon; case ammo_fuel: return ITEM_JetpackFuel.m_icon; - default: return ""; // wtf, no ammo type? + default: return ""; // wtf, no ammo type? } } #ifdef CSQC -.int GetAmmoFieldFromNum(int i) -{ - switch(i) + .int GetAmmoFieldFromNum(int i) { - case 0: return ammo_shells; - case 1: return ammo_nails; - case 2: return ammo_rockets; - case 3: return ammo_cells; - case 4: return ammo_plasma; - case 5: return ammo_fuel; - default: return ammo_none; + switch (i) + { + case 0: return ammo_shells; + case 1: return ammo_nails; + case 2: return ammo_rockets; + case 3: return ammo_cells; + case 4: return ammo_plasma; + case 5: return ammo_fuel; + default: return ammo_none; + } } -} -int GetAmmoStat(.int ammotype) -{ - switch(ammotype) + int GetAmmoStat(.int ammotype) { - case ammo_shells: return STAT_SHELLS; - case ammo_nails: return STAT_NAILS; - case ammo_rockets: return STAT_ROCKETS; - case ammo_cells: return STAT_CELLS; - case ammo_plasma: return STAT_PLASMA.m_id; - case ammo_fuel: return STAT_FUEL.m_id; - default: return -1; + switch (ammotype) + { + case ammo_shells: return STAT_SHELLS; + case ammo_nails: return STAT_NAILS; + case ammo_rockets: return STAT_ROCKETS; + case ammo_cells: return STAT_CELLS; + case ammo_plasma: return STAT_PLASMA.m_id; + case ammo_fuel: return STAT_FUEL.m_id; + default: return -1; + } } -} #endif string W_Sound(string w_snd) { string output = strcat("weapons/", w_snd); #ifdef SVQC - MUTATOR_CALLHOOK(WeaponSound, w_snd, output); - return weapon_sound_output; + MUTATOR_CALLHOOK(WeaponSound, w_snd, output); + return weapon_sound_output; #else - return output; + return output; #endif } @@ -274,11 +268,346 @@ string W_Model(string w_mdl) { string output = strcat("models/weapons/", w_mdl); #ifdef SVQC - MUTATOR_CALLHOOK(WeaponModel, w_mdl, output); - return weapon_model_output; + MUTATOR_CALLHOOK(WeaponModel, w_mdl, output); + return weapon_model_output; #else - return output; + return output; +#endif +} + +#ifndef MENUQC +vector shotorg_adjustfromclient(vector vecs, float y_is_right, float algn) +{ + switch (algn) + { + default: + case 3: + // right alignment + break; + case 4: + // left + vecs.y = -vecs.y; + break; + case 1: + case 2: + // center + vecs.y = 0; + vecs.z -= 2; + break; + } + return vecs; +} + +vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn) +{ +#ifdef SVQC + string s; #endif + if (visual) + { + vecs = shotorg_adjustfromclient(vecs, y_is_right, algn); + } +#ifdef SVQC + else if (autocvar_g_shootfromeye) + { + vecs.y = vecs.z = 0; + } + else if (autocvar_g_shootfromcenter) + { + vecs.y = 0; + vecs.z -= 2; + } + else if ((s = autocvar_g_shootfromfixedorigin) != "") + { + vector v = stov(s); + if (y_is_right) v.y = -v.y; + if (v.x != 0) vecs.x = v.x; + vecs.y = v.y; + vecs.z = v.z; + } +#endif + else // just do the same as top + { + vecs = shotorg_adjustfromclient(vecs, y_is_right, algn); + } + + return vecs; } +#define shotorg_adjust shotorg_adjust_values + +/** + * supported formats: + * + * 1. simple animated model, muzzle flash handling on h_ model: + * h_tuba.dpm, h_tuba.dpm.framegroups - invisible model controlling the animation + * tags: + * shot = muzzle end (shot origin, also used for muzzle flashes) + * shell = casings ejection point (must be on the right hand side of the gun) + * weapon = attachment for v_tuba.md3 + * v_tuba.md3 - first and third person model + * g_tuba.md3 - pickup model + * + * 2. simple animated model, muzzle flash handling on v_ model: + * h_tuba.dpm, h_tuba.dpm.framegroups - invisible model controlling the animation + * tags: + * weapon = attachment for v_tuba.md3 + * v_tuba.md3 - first and third person model + * tags: + * shot = muzzle end (shot origin, also used for muzzle flashes) + * shell = casings ejection point (must be on the right hand side of the gun) + * g_tuba.md3 - pickup model + * + * 3. fully animated model, muzzle flash handling on h_ model: + * h_tuba.dpm, h_tuba.dpm.framegroups - animated first person model + * tags: + * shot = muzzle end (shot origin, also used for muzzle flashes) + * shell = casings ejection point (must be on the right hand side of the gun) + * handle = corresponding to the origin of v_tuba.md3 (used for muzzle flashes) + * v_tuba.md3 - third person model + * g_tuba.md3 - pickup model + * + * 4. fully animated model, muzzle flash handling on v_ model: + * h_tuba.dpm, h_tuba.dpm.framegroups - animated first person model + * tags: + * shot = muzzle end (shot origin) + * shell = casings ejection point (must be on the right hand side of the gun) + * v_tuba.md3 - third person model + * tags: + * shot = muzzle end (for muzzle flashes) + * g_tuba.md3 - pickup model + * + * writes: + * this.origin, this.angles + * this.weaponchild + * this.movedir, this.view_ofs + * attachment stuff + * anim stuff + * to free: + * call again with "" + * remove the ent + */ +void CL_WeaponEntity_SetModel(entity this, string name) +{ + if (name == "") + { + this.model = ""; + if (this.weaponchild) remove(this.weaponchild); + this.weaponchild = NULL; + this.movedir = '0 0 0'; + this.spawnorigin = '0 0 0'; + this.oldorigin = '0 0 0'; + this.anim_fire1 = '0 1 0.01'; + this.anim_fire2 = '0 1 0.01'; + this.anim_idle = '0 1 0.01'; + this.anim_reload = '0 1 0.01'; + } + else + { + // if there is a child entity, hide it until we're sure we use it + if (this.weaponchild) this.weaponchild.model = ""; + _setmodel(this, W_Model(strcat("v_", name, ".md3"))); + int v_shot_idx; // used later + (v_shot_idx = gettagindex(this, "shot")) || (v_shot_idx = gettagindex(this, "tag_shot")); + + _setmodel(this, W_Model(strcat("h_", name, ".iqm"))); + // preset some defaults that work great for renamed zym files (which don't need an animinfo) + this.anim_fire1 = animfixfps(this, '0 1 0.01', '0 0 0'); + this.anim_fire2 = animfixfps(this, '1 1 0.01', '0 0 0'); + this.anim_idle = animfixfps(this, '2 1 0.01', '0 0 0'); + this.anim_reload = animfixfps(this, '3 1 0.01', '0 0 0'); + + // if we have a "weapon" tag, let's attach the v_ model to it ("invisible hand" style model) + // if we don't, this is a "real" animated model + string t; + if ((t = "weapon", gettagindex(this, t)) || (t = "tag_weapon", gettagindex(this, t))) + { + if (!this.weaponchild) + { + this.weaponchild = new(weaponchild); +#ifdef CSQC + this.weaponchild.drawmask = MASK_NORMAL; + this.weaponchild.renderflags |= RF_VIEWMODEL; +#endif + } + _setmodel(this.weaponchild, W_Model(strcat("v_", name, ".md3"))); + setattachment(this.weaponchild, this, t); + } + else + { + if (this.weaponchild) remove(this.weaponchild); + this.weaponchild = NULL; + } + + setorigin(this, '0 0 0'); + this.angles = '0 0 0'; + this.frame = 0; +#ifdef SVQC + this.viewmodelforclient = NULL; +#else + this.renderflags &= ~RF_VIEWMODEL; +#endif + if (v_shot_idx) // v_ model attached to invisible h_ model + { + this.movedir = gettaginfo(this.weaponchild, v_shot_idx); + } + else + { + int idx; + if ((idx = gettagindex(this, "shot")) || (idx = gettagindex(this, "tag_shot"))) + { + this.movedir = gettaginfo(this, idx); + } + else + { + LOG_WARNINGF("weapon model %s does not support the 'shot' tag, will display shots TOTALLY wrong\n", + this.model); + this.movedir = '0 0 0'; + } + } + { + int idx = 0; + // v_ model attached to invisible h_ model + if (this.weaponchild + && ((idx = gettagindex(this.weaponchild, "shell")) || (idx = gettagindex(this.weaponchild, "tag_shell")))) + { + this.spawnorigin = gettaginfo(this.weaponchild, idx); + } + else if ((idx = gettagindex(this, "shell")) || (idx = gettagindex(this, "tag_shell"))) + { + this.spawnorigin = gettaginfo(this, idx); + } + else + { + LOG_WARNINGF("weapon model %s does not support the 'shell' tag, will display casings wrong\n", + this.model); + this.spawnorigin = this.movedir; + } + } + if (v_shot_idx) + { + this.oldorigin = '0 0 0'; // use regular attachment + } + else + { + int idx; + if (this.weaponchild) + (idx = gettagindex(this, "weapon")) || (idx = gettagindex(this, "tag_weapon")); + else + (idx = gettagindex(this, "handle")) || (idx = gettagindex(this, "tag_handle")); + if (idx) + { + this.oldorigin = this.movedir - gettaginfo(this, idx); + } + else + { + LOG_WARNINGF( + "weapon model %s does not support the 'handle' tag " + "and neither does the v_ model support the 'shot' tag, " + "will display muzzle flashes TOTALLY wrong\n", + this.model); + this.oldorigin = '0 0 0'; // there is no way to recover from this + } + } + +#ifdef SVQC + this.viewmodelforclient = this.owner; +#else + this.renderflags |= RF_VIEWMODEL; +#endif + } + + this.view_ofs = '0 0 0'; + + if (this.movedir.x >= 0) + { +#ifdef SVQC + int algn = this.owner.cvar_cl_gunalign; +#else + int algn = autocvar_cl_gunalign; +#endif + vector v = this.movedir; + this.movedir = shotorg_adjust(v, false, false, algn); + this.view_ofs = shotorg_adjust(v, false, true, algn) - v; + } + int compressed_shotorg = compressShotOrigin(this.movedir); + // make them match perfectly +#ifdef SVQC + this.movedir = decompressShotOrigin(this.owner.stat_shotorg = compressed_shotorg); +#else + this.movedir = decompressShotOrigin(compressed_shotorg); +#endif + + this.spawnorigin += this.view_ofs; // offset the casings origin by the same amount + + // check if an instant weapon switch occurred + setorigin(this, this.view_ofs); + // reset animstate now + this.wframe = WFRAME_IDLE; + setanim(this, this.anim_idle, true, false, true); +} +#endif + +#ifndef MENUQC + +REGISTER_NET_TEMP(wframe) +#ifdef CSQC +NET_HANDLE(wframe, bool isNew) +{ + vector a; + a.x = ReadCoord(); + a.y = ReadCoord(); + a.z = ReadCoord(); + bool restartanim = ReadByte(); + anim_set(viewmodel, a, !restartanim, restartanim, restartanim); + viewmodel.state = ReadByte(); + viewmodel.alpha = ReadByte() / 255; + return true; +} +#endif + +#ifdef SVQC +void wframe_send(entity actor, entity weaponentity, vector a, bool restartanim) +{ + if (!IS_REAL_CLIENT(actor)) return; + int channel = MSG_ONE; + msg_entity = actor; + WriteHeader(channel, wframe); + WriteCoord(channel, a.x); + WriteCoord(channel, a.y); + WriteCoord(channel, a.z); + WriteByte(channel, restartanim); + WriteByte(channel, weaponentity.state); + WriteByte(channel, weaponentity.alpha * 255); +} +#endif + +REGISTER_NET_TEMP(wglow) +#ifdef CSQC +NET_HANDLE(wglow, bool isNew) +{ + vector g = '0 0 0'; + g.x = ReadCoord(); + g.y = ReadCoord(); + g.z = ReadCoord(); + viewmodel.glowmod = g; + return true; +} +#endif + +#ifdef SVQC +void wglow_send(entity actor, vector g) +{ + if (!IS_REAL_CLIENT(actor)) return; + int channel = MSG_ONE; + msg_entity = actor; + WriteHeader(channel, wglow); + WriteCoord(channel, g.x); + WriteCoord(channel, g.y); + WriteCoord(channel, g.z); +} +#endif + +#endif + #endif