From 591308c7b3ef684394fb6cade9931d9c7107560c Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Mon, 19 Jul 2010 12:04:56 +0200 Subject: [PATCH] VERY experimental change to handle electro lg beam in csqc --- qcsrc/client/Defs.qc | 1 + qcsrc/client/Main.qc | 5 +- qcsrc/client/hook.qc | 134 ++++++++--- qcsrc/common/constants.qh | 1 + qcsrc/server/cl_client.qc | 3 + qcsrc/server/cl_weaponsystem.qc | 394 +++++++++++++++++--------------- qcsrc/server/g_hook.qc | 19 +- qcsrc/server/g_world.qc | 1 + qcsrc/server/progs.src | 1 + qcsrc/server/w_electro.qc | 113 +++------ 10 files changed, 372 insertions(+), 300 deletions(-) diff --git a/qcsrc/client/Defs.qc b/qcsrc/client/Defs.qc index 80bd84a07..7a0881aaa 100644 --- a/qcsrc/client/Defs.qc +++ b/qcsrc/client/Defs.qc @@ -233,6 +233,7 @@ float announcer_5min; float tempdb; float ClientProgsDB; vector hook_shotorigin; +vector electro_shotorigin; #ifdef BLURTEST float blurtest_time0, blurtest_time1, blurtest_radius, blurtest_power; diff --git a/qcsrc/client/Main.qc b/qcsrc/client/Main.qc index de5aad9d4..3c42098e9 100644 --- a/qcsrc/client/Main.qc +++ b/qcsrc/client/Main.qc @@ -1025,6 +1025,9 @@ void Ent_Init() hook_shotorigin_x = ReadCoord(); hook_shotorigin_y = ReadCoord(); hook_shotorigin_z = ReadCoord(); + electro_shotorigin_x = ReadCoord(); + electro_shotorigin_y = ReadCoord(); + electro_shotorigin_z = ReadCoord(); if(forcefog) strunzone(forcefog); @@ -1290,7 +1293,7 @@ float CSQC_Parse_TempEntity() Net_ReadRace(); bHandled = true; break; - case 13: // TE_BEAM + case TE_CSQC_BEAM: Net_GrapplingHook(); bHandled = true; break; diff --git a/qcsrc/client/hook.qc b/qcsrc/client/hook.qc index dbd8ab2ad..e30b7d905 100644 --- a/qcsrc/client/hook.qc +++ b/qcsrc/client/hook.qc @@ -1,6 +1,11 @@ .vector HookStart; .vector HookEnd; .float HookKillTime; +.vector LGBeamStart; +.vector LGBeamEnd; +.float LGBeamKillTime; +.float LGBeamSound; +.float LGBeamSilent; void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float alpha, float drawflag) { @@ -51,55 +56,91 @@ void Draw_GrapplingHook() vector rgb; float t; - if(time >= self.HookKillTime) - return; - if(self.sv_entnum == player_localentnum - 1) - a = view_origin + view_forward * hook_shotorigin_x + view_right * hook_shotorigin_y + view_up * hook_shotorigin_z; - else - a = self.HookStart; - b = self.HookEnd; - - t = GetPlayerColorForce(self.sv_entnum); - - if(t == COLOR_TEAM1) - { - tex = "particles/hook_red"; - rgb = '1 .3 .3'; - } - else if(t == COLOR_TEAM2) + if(time < self.HookKillTime) { - tex = "particles/hook_blue"; - rgb = '.3 .3 1'; + if(self.sv_entnum == player_localentnum - 1) + a = view_origin + view_forward * hook_shotorigin_x + view_right * hook_shotorigin_y + view_up * hook_shotorigin_z; + else + a = self.HookStart; + b = self.HookEnd; + + t = GetPlayerColorForce(self.sv_entnum); + + if(t == COLOR_TEAM1) + { + tex = "particles/hook_red"; + rgb = '1 .3 .3'; + } + else if(t == COLOR_TEAM2) + { + tex = "particles/hook_blue"; + rgb = '.3 .3 1'; + } + else if(t == COLOR_TEAM3) + { + tex = "particles/hook_yellow"; + rgb = '1 1 .3'; + } + else if(t == COLOR_TEAM4) + { + tex = "particles/hook_pink"; + rgb = '1 .3 1'; + } + else + { + tex = "particles/hook_green"; + rgb = '.3 1 .3'; + } + + Draw_GrapplingHook_trace_callback_tex = tex; + Draw_GrapplingHook_trace_callback_rnd = random(); + WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, MOVE_NOMONSTERS, world, world, Draw_GrapplingHook_trace_callback); + Draw_GrapplingHook_trace_callback_tex = string_null; } - else if(t == COLOR_TEAM3) + + if(time < self.LGBeamKillTime) { - tex = "particles/hook_yellow"; - rgb = '1 1 .3'; + if(self.sv_entnum == player_localentnum - 1) + a = view_origin + view_forward * electro_shotorigin_x + view_right * electro_shotorigin_y + view_up * electro_shotorigin_z; + else + a = self.LGBeamStart; + b = self.LGBeamEnd; + + tex = "particles/lgbeam"; + rgb = '1 1 1'; + + Draw_GrapplingHook_trace_callback_tex = tex; + Draw_GrapplingHook_trace_callback_rnd = random(); + WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, MOVE_NOMONSTERS, world, world, Draw_GrapplingHook_trace_callback); + Draw_GrapplingHook_trace_callback_tex = string_null; } - else if(t == COLOR_TEAM4) + + if(time < self.LGBeamKillTime && !self.LGBeamSilent) { - tex = "particles/hook_pink"; - rgb = '1 .3 1'; + if(!self.LGBeamSound) + { + sound (self, CHAN_PROJECTILE, "weapons/lgbeam_fly.wav", VOL_BASE, ATTN_NORM); + self.LGBeamSound = 1; + } } else { - tex = "particles/hook_green"; - rgb = '.3 1 .3'; + if(self.LGBeamSound) + { + sound (self, CHAN_PROJECTILE, "misc/null.wav", VOL_BASE, ATTN_NORM); + self.LGBeamSound = 0; + } } - - Draw_GrapplingHook_trace_callback_tex = tex; - Draw_GrapplingHook_trace_callback_rnd = random(); - WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, MOVE_NOMONSTERS, world, world, Draw_GrapplingHook_trace_callback); - Draw_GrapplingHook_trace_callback_tex = string_null; } void Net_GrapplingHook() { - float i; + float i, t; vector start, end; entity p; - i = ReadShort(); + i = ReadByte(); + t = ReadByte(); end_x = ReadCoord(); end_y = ReadCoord(); end_z = ReadCoord(); @@ -115,8 +156,27 @@ void Net_GrapplingHook() if(!p) return; - p.HookKillTime = time + 0.1; - p.HookStart = start; - p.HookEnd = end; - p.draw = Draw_GrapplingHook; + switch(t) + { + case 0: // hook beam + p.HookKillTime = time + 0.1; + p.HookStart = start; + p.HookEnd = end; + p.draw = Draw_GrapplingHook; + break; + case 1: // electro lgbeam + p.LGBeamKillTime = time + 0.1; + p.LGBeamStart = start; + p.LGBeamEnd = end; + p.LGBeamSilent = 0; + p.draw = Draw_GrapplingHook; + break; + case 2: // silent electro lgbeam + p.LGBeamKillTime = time + 0.1; + p.LGBeamStart = start; + p.LGBeamEnd = end; + p.LGBeamSilent = 1; + p.draw = Draw_GrapplingHook; + break; + } } diff --git a/qcsrc/common/constants.qh b/qcsrc/common/constants.qh index 775628e06..5e96ce38a 100644 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@ -59,6 +59,7 @@ const float TE_CSQC_ANNOUNCE = 110; const float TE_CSQC_TARGET_MUSIC = 111; const float TE_CSQC_NOTIFY = 112; const float TE_CSQC_WEAPONCOMPLAIN = 113; +const float TE_CSQC_BEAM = 114; const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder const float RACE_NET_CHECKPOINT_CLEAR = 1; diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index 08c53c194..339b236c4 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -1066,6 +1066,9 @@ float ClientInit_SendEntity(entity to, float sf) WriteCoord(MSG_ENTITY, hook_shotorigin_x); WriteCoord(MSG_ENTITY, hook_shotorigin_y); WriteCoord(MSG_ENTITY, hook_shotorigin_z); + WriteCoord(MSG_ENTITY, electro_shotorigin_x); + WriteCoord(MSG_ENTITY, electro_shotorigin_y); + WriteCoord(MSG_ENTITY, electro_shotorigin_z); if(sv_foginterval && world.fog != "") WriteString(MSG_ENTITY, world.fog); else diff --git a/qcsrc/server/cl_weaponsystem.qc b/qcsrc/server/cl_weaponsystem.qc index d362a8b9d..f48f75c3e 100644 --- a/qcsrc/server/cl_weaponsystem.qc +++ b/qcsrc/server/cl_weaponsystem.qc @@ -391,228 +391,258 @@ vector weapon_adjust = '10 0 -15'; * g_tuba.md3 - pickup model */ -void CL_Weaponentity_Think() +// writes: +// self.origin, self.angles +// self.weaponentity +// self.movedir, self.view_ofs +// attachment stuff +// anim stuff +// to free: +// call again with "" +// remove the ent +void CL_WeaponEntity_SetModel(string name) { - float tb, v_shot_idx; - self.nextthink = time; - if (intermission_running) - self.frame = self.anim_idle_x; - if (self.owner.weaponentity != self) - { - if (self.weaponentity) - remove(self.weaponentity); - remove(self); - return; - } - if (self.owner.deadflag != DEAD_NO) + string animfilename; + float animfile; + float v_shot_idx; + if (name != "") { - self.model = ""; + // if there is a child entity, hide it until we're sure we use it if (self.weaponentity) self.weaponentity.model = ""; - return; - } - if (self.cnt != self.owner.weapon || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag) - { - self.cnt = self.owner.weapon; - self.dmg = self.owner.modelindex; - self.deadflag = self.owner.deadflag; + setmodel(self, strcat("models/weapons/v_", name, ".md3")); // precision set below + v_shot_idx = gettagindex(self, "shot"); // used later + if(!v_shot_idx) + v_shot_idx = gettagindex(self, "tag_shot"); - string animfilename; - float animfile; - if (self.owner.weaponname != "") + if(qcweaponanimation) { - // if there is a child entity, hide it until we're sure we use it - if (self.weaponentity) - self.weaponentity.model = ""; - setmodel(self, strcat("models/weapons/v_", self.owner.weaponname, ".md3")); // precision set below - v_shot_idx = gettagindex(self, "shot"); // used later - if(!v_shot_idx) - v_shot_idx = gettagindex(self, "tag_shot"); + self.angles = '0 0 0'; + makevectors(self.angles_x * '-1 0 0' + self.angles_y * '0 1 0' + self.angles_z * '0 0 1'); + self.movedir = weapon_offset_x * v_forward - weapon_offset_y * v_right + weapon_offset_z * v_up + weapon_adjust; + self.movedir_x += 32; + self.spawnorigin = self.movedir; + // oldorigin - not calculated here + } + else + { + setmodel(self, strcat("models/weapons/h_", name, ".iqm")); // precision set below + animfilename = strcat("models/weapons/h_", name, ".iqm.animinfo"); + animfile = fopen(animfilename, FILE_READ); + // preset some defaults that work great for renamed zym files (which don't need an animinfo) + self.anim_fire1 = '0 1 0.01'; + self.anim_fire2 = '1 1 0.01'; + self.anim_idle = '2 1 0.01'; + self.anim_reload = '3 1 0.01'; + if (animfile >= 0) + { + animparseerror = FALSE; + self.anim_fire1 = animparseline(animfile); + self.anim_fire2 = animparseline(animfile); + self.anim_idle = animparseline(animfile); + self.anim_reload = animparseline(animfile); + fclose(animfile); + if (animparseerror) + print("Parse error in ", animfilename, ", some player animations are broken\n"); + } - if(qcweaponanimation) + // 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 + if(gettagindex(self, "weapon")) + { + if (!self.weaponentity) + self.weaponentity = spawn(); + setmodel(self.weaponentity, strcat("models/weapons/v_", name, ".md3")); // precision does not matter + setattachment(self.weaponentity, self, "weapon"); + } + else if(gettagindex(self, "tag_weapon")) { - self.angles = '0 0 0'; - makevectors(self.angles_x * '-1 0 0' + self.angles_y * '0 1 0' + self.angles_z * '0 0 1'); - self.movedir = weapon_offset_x * v_forward - weapon_offset_y * v_right + weapon_offset_z * v_up + weapon_adjust; - self.movedir_x += 32; - self.spawnorigin = self.movedir; - // oldorigin - not calculated here + if (!self.weaponentity) + self.weaponentity = spawn(); + setmodel(self.weaponentity, strcat("models/weapons/v_", name, ".md3")); // precision does not matter + setattachment(self.weaponentity, self, "tag_weapon"); } else { - setmodel(self, strcat("models/weapons/h_", self.owner.weaponname, ".iqm")); // precision set below - animfilename = strcat("models/weapons/h_", self.owner.weaponname, ".iqm.animinfo"); - animfile = fopen(animfilename, FILE_READ); - // preset some defaults that work great for renamed zym files (which don't need an animinfo) - self.anim_fire1 = '0 1 0.01'; - self.anim_fire2 = '1 1 0.01'; - self.anim_idle = '2 1 0.01'; - self.anim_reload = '3 1 0.01'; - if (animfile >= 0) - { - animparseerror = FALSE; - self.anim_fire1 = animparseline(animfile); - self.anim_fire2 = animparseline(animfile); - self.anim_idle = animparseline(animfile); - self.anim_reload = animparseline(animfile); - fclose(animfile); - if (animparseerror) - print("Parse error in ", animfilename, ", some player animations are broken\n"); - } - - // 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 - if(gettagindex(self, "weapon")) - { - if (!self.weaponentity) - self.weaponentity = spawn(); - setmodel(self.weaponentity, strcat("models/weapons/v_", self.owner.weaponname, ".md3")); // precision does not matter - setattachment(self.weaponentity, self, "weapon"); - } - else if(gettagindex(self, "tag_weapon")) - { - if (!self.weaponentity) - self.weaponentity = spawn(); - setmodel(self.weaponentity, strcat("models/weapons/v_", self.owner.weaponname, ".md3")); // precision does not matter - setattachment(self.weaponentity, self, "tag_weapon"); - } - else - { - if(self.weaponentity) - remove(self.weaponentity); - self.weaponentity = world; - } + if(self.weaponentity) + remove(self.weaponentity); + self.weaponentity = world; + } - setorigin(self,'0 0 0'); - self.angles = '0 0 0'; - self.frame = 0; - self.viewmodelforclient = world; + setorigin(self,'0 0 0'); + self.angles = '0 0 0'; + self.frame = 0; + self.viewmodelforclient = world; - float idx; + float idx; - if(v_shot_idx) // v_ model attached to invisible h_ model + if(v_shot_idx) // v_ model attached to invisible h_ model + { + self.movedir = gettaginfo(self.weaponentity, v_shot_idx); + } + else + { + idx = gettagindex(self, "shot"); + if(!idx) + idx = gettagindex(self, "tag_shot"); + if(idx) + self.movedir = gettaginfo(self, idx); + else { - self.movedir = gettaginfo(self.weaponentity, v_shot_idx); + print("WARNING: weapon model ", self.model, " does not support the 'shot' tag, will display shots TOTALLY wrong\n"); + self.movedir = '0 0 0'; } + } + + if(self.weaponentity) // v_ model attached to invisible h_ model + { + idx = gettagindex(self.weaponentity, "shell"); + if(!idx) + idx = gettagindex(self.weaponentity, "tag_shell"); + if(idx) + self.spawnorigin = gettaginfo(self.weaponentity, idx); + } + else + idx = 0; + if(!idx) + { + idx = gettagindex(self, "shell"); + if(!idx) + idx = gettagindex(self, "tag_shell"); + if(idx) + self.spawnorigin = gettaginfo(self, idx); else { - idx = gettagindex(self, "shot"); - if(!idx) - idx = gettagindex(self, "tag_shot"); - if(idx) - self.movedir = gettaginfo(self, idx); - else - { - print("WARNING: weapon model ", self.model, " does not support the 'shot' tag, will display shots TOTALLY wrong\n"); - self.movedir = '0 0 0'; - } + print("WARNING: weapon model ", self.model, " does not support the 'shell' tag, will display casings wrong\n"); + self.spawnorigin = self.movedir; } + } - if(self.weaponentity) // v_ model attached to invisible h_ model + if(v_shot_idx) + { + self.oldorigin = '0 0 0'; // use regular attachment + } + else + { + if(self.weaponentity) { - idx = gettagindex(self.weaponentity, "shell"); + idx = gettagindex(self, "weapon"); if(!idx) - idx = gettagindex(self.weaponentity, "tag_shell"); - if(idx) - self.spawnorigin = gettaginfo(self.weaponentity, idx); + idx = gettagindex(self, "tag_weapon"); } else - idx = 0; - if(!idx) { - idx = gettagindex(self, "shell"); + idx = gettagindex(self, "handle"); if(!idx) - idx = gettagindex(self, "tag_shell"); - if(idx) - self.spawnorigin = gettaginfo(self, idx); - else - { - print("WARNING: weapon model ", self.model, " does not support the 'shell' tag, will display casings wrong\n"); - self.spawnorigin = self.movedir; - } + idx = gettagindex(self, "tag_handle"); } - - if(v_shot_idx) + if(idx) { - self.oldorigin = '0 0 0'; // use regular attachment + self.oldorigin = self.movedir - gettaginfo(self, idx); } else { - if(self.weaponentity) - { - idx = gettagindex(self, "weapon"); - if(!idx) - idx = gettagindex(self, "tag_weapon"); - } - else - { - idx = gettagindex(self, "handle"); - if(!idx) - idx = gettagindex(self, "tag_handle"); - } - if(idx) - { - self.oldorigin = self.movedir - gettaginfo(self, idx); - } - else - { - print("WARNING: weapon model ", self.model, " does not support the 'handle' tag and neither does the v_ model support the 'shot' tag, will display muzzle flashes TOTALLY wrong\n"); - self.oldorigin = '0 0 0'; // there is no way to recover from this - } + print("WARNING: weapon model ", self.model, " does not support the 'handle' tag and neither does the v_ model support the 'shot' tag, will display muzzle flashes TOTALLY wrong\n"); + self.oldorigin = '0 0 0'; // there is no way to recover from this } - - self.viewmodelforclient = self.owner; } + + self.viewmodelforclient = self.owner; } - else - { - self.model = ""; - if(self.weaponentity) - remove(self.weaponentity); - self.weaponentity = world; - self.movedir = '0 0 0'; - self.spawnorigin = '0 0 0'; - self.oldorigin = '0 0 0'; - self.anim_fire1 = '0 1 0.01'; - self.anim_fire2 = '0 1 0.01'; - self.anim_idle = '0 1 0.01'; - self.anim_reload = '0 1 0.01'; - } + } + else + { + self.model = ""; + if(self.weaponentity) + remove(self.weaponentity); + self.weaponentity = world; + self.movedir = '0 0 0'; + self.spawnorigin = '0 0 0'; + self.oldorigin = '0 0 0'; + self.anim_fire1 = '0 1 0.01'; + self.anim_fire2 = '0 1 0.01'; + self.anim_idle = '0 1 0.01'; + self.anim_reload = '0 1 0.01'; + } - self.view_ofs = '0 0 0'; + self.view_ofs = '0 0 0'; - if(self.movedir_x >= 0) - { - vector v0; - v0 = self.movedir; - self.movedir = shotorg_adjust(v0, FALSE, FALSE); - self.view_ofs = shotorg_adjust(v0, FALSE, TRUE) - v0; - } - self.owner.stat_shotorg = compressShotOrigin(self.movedir); - self.movedir = decompressShotOrigin(self.owner.stat_shotorg); // make them match perfectly + if(self.movedir_x >= 0) + { + vector v0; + v0 = self.movedir; + self.movedir = shotorg_adjust(v0, FALSE, FALSE); + self.view_ofs = shotorg_adjust(v0, FALSE, TRUE) - v0; + } + self.owner.stat_shotorg = compressShotOrigin(self.movedir); + self.movedir = decompressShotOrigin(self.owner.stat_shotorg); // make them match perfectly - self.spawnorigin += self.view_ofs; // offset the casings origin by the same amount + self.spawnorigin += self.view_ofs; // offset the casings origin by the same amount - // check if an instant weapon switch occurred - if (qcweaponanimation) + // check if an instant weapon switch occurred + if (qcweaponanimation) + { + if (self.state == WS_READY) { - if (self.state == WS_READY) - { - self.angles = '0 0 0'; - makevectors(self.angles_x * '-1 0 0' + self.angles_y * '0 1 0' + self.angles_z * '0 0 1'); - setorigin(self, QCWEAPONANIMATION_ORIGIN(self)); - } + self.angles = '0 0 0'; + makevectors(self.angles_x * '-1 0 0' + self.angles_y * '0 1 0' + self.angles_z * '0 0 1'); + setorigin(self, QCWEAPONANIMATION_ORIGIN(self)); } - else - setorigin(self, self.view_ofs); - // reset animstate now - self.wframe = WFRAME_IDLE; - self.weapon_morph0time = 0; - self.weapon_morph1time = 0; - self.weapon_morph2time = 0; - self.weapon_morph3time = 0; - self.weapon_morph4time = 0; - setanim(self, self.anim_idle, TRUE, FALSE, TRUE); + } + else + setorigin(self, self.view_ofs); + // reset animstate now + self.wframe = WFRAME_IDLE; + self.weapon_morph0time = 0; + self.weapon_morph1time = 0; + self.weapon_morph2time = 0; + self.weapon_morph3time = 0; + self.weapon_morph4time = 0; + setanim(self, self.anim_idle, TRUE, FALSE, TRUE); +} + +vector CL_Weapon_GetShotOrg(float wpn) +{ + entity wi, oldself; + vector ret; + wi = get_weaponinfo(wpn); + oldself = self; + self = spawn(); + CL_WeaponEntity_SetModel(wi.mdl); + ret = self.movedir; + CL_WeaponEntity_SetModel(""); + remove(self); + self = oldself; + return ret; +} + +void CL_Weaponentity_Think() +{ + float tb; + self.nextthink = time; + if (intermission_running) + self.frame = self.anim_idle_x; + if (self.owner.weaponentity != self) + { + if (self.weaponentity) + remove(self.weaponentity); + remove(self); + return; + } + if (self.owner.deadflag != DEAD_NO) + { + self.model = ""; + if (self.weaponentity) + self.weaponentity.model = ""; + return; + } + if (self.cnt != self.owner.weapon || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag) + { + self.cnt = self.owner.weapon; + self.dmg = self.owner.modelindex; + self.deadflag = self.owner.deadflag; + + CL_WeaponEntity_SetModel(self.owner.weaponname); } tb = (self.effects & (EF_TELEPORT_BIT | EF_RESTARTANIM_BIT)); diff --git a/qcsrc/server/g_hook.qc b/qcsrc/server/g_hook.qc index a88fae947..2bc542ef7 100644 --- a/qcsrc/server/g_hook.qc +++ b/qcsrc/server/g_hook.qc @@ -235,7 +235,19 @@ void GrapplingHookThink() } makevectors(self.angles_x * '-1 0 0' + self.angles_y * '0 1 0'); - te_beam(self.owner, WarpZone_RefSys_TransformOrigin(self, self.owner, self.origin) + v_forward * (-9), org); + myorg = WarpZone_RefSys_TransformOrigin(self, self.owner, self.origin) + v_forward * (-9); + + // TODO turn into a csqc entity + WriteByte(MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte(MSG_BROADCAST, TE_CSQC_BEAM); + WriteByte(MSG_BROADCAST, num_for_edict(self.owner)); + WriteByte(MSG_BROADCAST, 0); + WriteCoord(MSG_BROADCAST, myorg_x); + WriteCoord(MSG_BROADCAST, myorg_y); + WriteCoord(MSG_BROADCAST, myorg_z); + WriteCoord(MSG_BROADCAST, org_x); + WriteCoord(MSG_BROADCAST, org_y); + WriteCoord(MSG_BROADCAST, org_z); } void GrapplingHookTouch (void) @@ -436,7 +448,10 @@ void GrappleHookInit() if(g_grappling_hook) hook_shotorigin = '8 -8 -12'; else - hook_shotorigin = shotorg_adjust('26.2148 9.2059 -15.9772', TRUE, FALSE); + { + weapon_action(WEP_HOOK, WR_PRECACHE); + hook_shotorigin = shotorg_adjust(CL_Weapon_GetShotOrg(WEP_HOOK), TRUE, FALSE); + } } void SetGrappleHookBindings() diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index a5165706b..020c24bb3 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -512,6 +512,7 @@ void spawnfunc_worldspawn (void) InitGameplayMode(); readlevelcvars(); GrappleHookInit(); + ElectroInit(); player_count = 0; bot_waypoints_for_items = cvar("g_waypoints_for_items"); diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index c174177b2..929b0df20 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -43,6 +43,7 @@ cheats.qh portals.qh g_hook.qh +w_electro.qh scores.qh diff --git a/qcsrc/server/w_electro.qc b/qcsrc/server/w_electro.qc index 62ae00893..f44c0ba05 100644 --- a/qcsrc/server/w_electro.qc +++ b/qcsrc/server/w_electro.qc @@ -188,7 +188,7 @@ void W_Electro_Attack2() .float nextdamagethink; void lgbeam_think() { - if (self.owner.weaponentity.state != WS_INUSE || (self.owner.ammo_cells <= 0 && !(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)) || self != self.owner.lgbeam || self.owner.BUTTON_ATCK == 0 || self.owner.deadflag != DEAD_NO) + if (self.owner.weaponentity.state != WS_INUSE || (self.owner.ammo_cells <= 0 && !(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)) || self != self.owner.lgbeam || self.owner.deadflag != DEAD_NO || !self.owner.BUTTON_ATCK) { remove(self); return; @@ -200,60 +200,42 @@ void lgbeam_think() vector angle; angle = v_forward; - vector force; - force = angle * cvar("g_balance_electro_primary_force"); - traceline_antilag(self.owner, self.owner.origin + self.owner.view_ofs, self.owner.origin + self.owner.view_ofs + angle * cvar("g_balance_electro_primary_range"), FALSE, self.owner, ANTILAG_LATENCY(self.owner)); - self.scale = vlen(self.owner.origin - trace_endpos) / 256 * (0.75 + 0.75 * random()); -} + if not(self.owner.items & IT_UNLIMITED_WEAPON_AMMO) + self.owner.ammo_cells = max(0, self.owner.ammo_cells - cvar("g_balance_electro_primary_ammo") * frametime); -// execute each frame to update the beam visuals, but only apply damage at intervals of "refire" to prevent massive hitsound spam -void exteriorlgbeam_think() -{ - if (self.owner.weaponentity.state != WS_INUSE || (self.owner.ammo_cells <= 0 && !(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)) || self != self.owner.exteriorlgbeam || self.owner.BUTTON_ATCK == 0 || self.owner.deadflag != DEAD_NO) + // apply the damage + if(trace_fraction < 1) { - sound (self, CHAN_PROJECTILE, "sound/misc/null.wav", VOL_BASE, ATTN_NORM); - remove(self); - return; + vector force; + force = angle * cvar("g_balance_electro_primary_force") + '0 0 1' * cvar("g_balance_electro_primary_force_up"); + Damage (trace_ent, self.owner, self.owner, cvar("g_balance_electro_primary_damage") * frametime, WEP_ELECTRO, trace_endpos, force * frametime); + W_Plasma_TriggerCombo(trace_endpos, cvar("g_balance_electro_primary_comboradius"), self.owner); } - if (time - self.shot_spread + random() * 0.2 > 0) - { - self.shot_spread = time + 2; - sound (self, CHAN_PROJECTILE, "turrets/phaser.wav", VOL_BASE, ATTN_NORM); - } - - self.nextthink = time; - - makevectors(self.owner.v_angle); - vector angle; - angle = v_forward; - - traceline_antilag(self.owner, self.owner.origin + self.owner.view_ofs, self.owner.origin + self.owner.view_ofs + angle * cvar("g_balance_electro_primary_range"), FALSE, self.owner, ANTILAG_LATENCY(self.owner)); - - if(self.nextdamagethink <= time) + // draw effect + vector vecs, org; + if(self.owner.weaponentity.movedir_x > 0) { - if not(self.owner.items & IT_UNLIMITED_WEAPON_AMMO) - self.owner.ammo_cells = max(0, self.owner.ammo_cells - cvar("g_balance_electro_primary_ammo") * cvar("g_balance_electro_primary_refire")); - - // apply the damage - if(trace_fraction < 1) - { - vector force; - force = angle * cvar("g_balance_electro_primary_force") + '0 0 1' * cvar("g_balance_electro_primary_force_up"); - Damage (trace_ent, self.owner, self.owner, cvar("g_balance_electro_primary_damage") * cvar("g_balance_electro_primary_refire"), WEP_ELECTRO, trace_endpos, force * cvar("g_balance_electro_primary_refire")); - W_Plasma_TriggerCombo(trace_endpos, cvar("g_balance_electro_primary_comboradius"), self.owner); - } - self.nextdamagethink = time + cvar("g_balance_electro_primary_refire"); + vecs = self.owner.weaponentity.movedir; + vecs_y = -vecs_y; } - - self.angles = '0 0 0'; - self.scale = vlen(gettaginfo(self, 0) - trace_endpos) / 256 * (0.75 + 0.75 * random()); - - // v_forward, v_right, v_up now are the ACTUAL directions - // express self.angles in terms of them to aim at target! - self.angles = vectoangles('1 0 0' * (angle * v_forward) + '0 -1 0' * (angle * v_right) + '0 0 1' * (angle * v_up)); + else + vecs = '0 0 0'; + org = self.owner.origin + self.owner.view_ofs + v_forward * vecs_x + v_right * vecs_y + v_up * vecs_z; + + // TODO turn into a csqc entity + WriteByte(MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte(MSG_BROADCAST, TE_CSQC_BEAM); + WriteByte(MSG_BROADCAST, num_for_edict(self.owner)); + WriteByte(MSG_BROADCAST, sound_allowed(MSG_BROADCAST, self.owner) ? 1 : 2); + WriteCoord(MSG_BROADCAST, org_x); + WriteCoord(MSG_BROADCAST, org_y); + WriteCoord(MSG_BROADCAST, org_z); + WriteCoord(MSG_BROADCAST, trace_endpos_x); + WriteCoord(MSG_BROADCAST, trace_endpos_y); + WriteCoord(MSG_BROADCAST, trace_endpos_z); } // experimental lightning gun @@ -268,37 +250,6 @@ void W_Electro_Attack3 (void) beam.think = lgbeam_think; beam.owner = self; beam.movetype = MOVETYPE_NONE; - if(gettagindex(self.weaponentity, "shot")) - setattachment(beam, self.weaponentity, "shot"); - else - setattachment(beam, self.weaponentity, "tag_shot"); - - oldself = self; - self = beam; - self.think(); - self = oldself; - - self.exteriorlgbeam = beam = spawn(); - setmodel(beam,"models/turrets/phaser_beam.md3"); - beam.effects = EF_LOWPRECISION; - beam.solid = SOLID_NOT; - beam.think = exteriorlgbeam_think; - beam.owner = self; - beam.movetype = MOVETYPE_NONE; - //beam.viewmodelforclient = self; - if(self.weaponentity.oldorigin_x > 0) - { - setattachment(beam, self.exteriorweaponentity, ""); - setorigin(beam, self.weaponentity.oldorigin); - } - else - { - if(gettagindex(self.exteriorweaponentity, "shot")) - setattachment(beam, self.exteriorweaponentity, "shot"); - else - setattachment(beam, self.exteriorweaponentity, "tag_shot"); - } - beam.shot_spread = 0; beam.bot_dodge = TRUE; beam.bot_dodgerating = cvar("g_balance_electro_primary_damage"); @@ -309,6 +260,12 @@ void W_Electro_Attack3 (void) self = oldself; } +void ElectroInit() +{ + weapon_action(WEP_ELECTRO, WR_PRECACHE); + electro_shotorigin = shotorg_adjust(CL_Weapon_GetShotOrg(WEP_ELECTRO), TRUE, FALSE); +} + void spawnfunc_weapon_electro (void) { weapon_defaultspawnfunc(WEP_ELECTRO); -- 2.39.2