From dc0b9e54800842911ac64e1628d4a8726507fc39 Mon Sep 17 00:00:00 2001 From: div0 Date: Sat, 17 Jan 2009 17:53:48 +0000 Subject: [PATCH] moved gibbing from server to client SavageX: please reimplement sv_gentle as client cvar in client/gibs.qc git-svn-id: svn://svn.icculus.org/nexuiz/trunk@5587 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/qcsrc/client/Defs.qc | 3 + data/qcsrc/client/Main.qc | 5 + data/qcsrc/client/csqc_builtins.qc | 2 + data/qcsrc/client/damage.qc | 52 +++++++ data/qcsrc/client/gibs.qc | 141 ++++++++++++++++++ data/qcsrc/client/movetypes.qc | 128 ++++++++++++++-- data/qcsrc/client/movetypes.qh | 9 +- data/qcsrc/client/progs.src | 2 + data/qcsrc/client/projectile.qc | 41 ++++- data/qcsrc/common/constants.qh | 6 +- data/qcsrc/common/util.qc | 6 + data/qcsrc/common/util.qh | 3 + .../qcsrc/menu/nexuiz/dialog_settings_audio.c | 4 +- data/qcsrc/server/cl_player.qc | 94 ++---------- data/qcsrc/server/cl_weaponsystem.qc | 2 + data/qcsrc/server/g_damage.qc | 48 ++++++ data/qcsrc/server/g_violence.qc | 124 +++++---------- data/qcsrc/server/miscfunctions.qc | 6 - data/qcsrc/server/w_hook.qc | 1 + 19 files changed, 475 insertions(+), 202 deletions(-) create mode 100644 data/qcsrc/client/damage.qc create mode 100644 data/qcsrc/client/gibs.qc diff --git a/data/qcsrc/client/Defs.qc b/data/qcsrc/client/Defs.qc index 99b9d0bed..bb66ae989 100644 --- a/data/qcsrc/client/Defs.qc +++ b/data/qcsrc/client/Defs.qc @@ -218,3 +218,6 @@ float blurtest_time0, blurtest_time1, blurtest_radius, blurtest_power; float servertime, serverprevtime, serverdeltatime; float ticrate; + +.float damageforcescale; +.void(float thisdmg, float hittype, vector org, vector thisforce) event_damage; diff --git a/data/qcsrc/client/Main.qc b/data/qcsrc/client/Main.qc index 23f7bae83..1a05f7dfa 100644 --- a/data/qcsrc/client/Main.qc +++ b/data/qcsrc/client/Main.qc @@ -133,6 +133,7 @@ void CSQC_Init(void) WaypointSprite_Load(); Projectile_Precache(); + GibSplash_Precache(); } // CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc) @@ -517,6 +518,10 @@ void(float bIsNewEntity) CSQC_Ent_Update = Ent_RadarLink(); else if(self.enttype == ENT_CLIENT_PROJECTILE) Ent_Projectile(); + else if(self.enttype == ENT_CLIENT_GIBSPLASH) + Ent_GibSplash(); + else if(self.enttype == ENT_CLIENT_DAMAGEINFO) + Ent_DamageInfo(); else error(strcat("unknown entity type in CSQC_Ent_Update: ", ftos(self.enttype), "\n")); diff --git a/data/qcsrc/client/csqc_builtins.qc b/data/qcsrc/client/csqc_builtins.qc index a14a78c96..4e590a405 100644 --- a/data/qcsrc/client/csqc_builtins.qc +++ b/data/qcsrc/client/csqc_builtins.qc @@ -275,3 +275,5 @@ string findkeysforcommand(string command) = #521; string(float ccase, float calpha, float cnum, string s, ...) strconv = #224; float(entity ent) wasfreed = #353; + +entity(vector org, float rad) findradius = #22; diff --git a/data/qcsrc/client/damage.qc b/data/qcsrc/client/damage.qc new file mode 100644 index 000000000..a09ee43fd --- /dev/null +++ b/data/qcsrc/client/damage.qc @@ -0,0 +1,52 @@ +void Ent_DamageInfo() +{ + float hittype, dmg, rad, edge, thisdmg; + vector force, org, thisforce; + entity oldself; + + oldself = self; + + hittype = ReadShort(); + org_x = ReadCoord(); + org_y = ReadCoord(); + org_z = ReadCoord(); + + dmg = ReadByte(); + rad = ReadByte(); + edge = ReadByte(); + force = decompressShortVector(ReadShort()); + + for(self = findradius(org, rad); self; self = self.chain) + { + print("findradius found something\n"); + + if(rad) + { + thisdmg = vlen(self.origin - org) / rad; + print("thisdmg = ", ftos(thisdmg), "\n"); + if(thisdmg >= 1) + continue; + thisdmg = dmg + (edge - dmg) * thisdmg; + thisforce = force_z * normalize(self.origin - org); + } + else + { + thisdmg = dmg; + thisforce = force; + } + + if(self.damageforcescale) + if(vlen(thisforce)) + { + self.move_velocity = self.move_velocity + self.damageforcescale * thisforce; + self.move_flags &~= FL_ONGROUND; + } + + if(self.event_damage) + self.event_damage(thisdmg, hittype, org, thisforce); + } + + self = oldself; + + // TODO spawn particle effects and sounds based on hittype +} diff --git a/data/qcsrc/client/gibs.qc b/data/qcsrc/client/gibs.qc new file mode 100644 index 000000000..1f5fadc74 --- /dev/null +++ b/data/qcsrc/client/gibs.qc @@ -0,0 +1,141 @@ +void Gib_Touch() +{ + // TODO maybe bounce of walls, make more gibs, etc. + + sound(self, CHAN_PAIN, strcat("misc/gib_splat0", ftos(floor(random() * 4 + 1)), ".wav"), VOL_BASE, ATTN_NORM); + pointparticles(particleeffectnum("blood"), self.origin + '0 0 1', '0 0 30', 10); + + remove(self); +} + +void Gib_Draw() +{ + vector oldorg; + oldorg = self.origin; + + Movetype_Physics(FALSE); + + trailparticles(self, particleeffectnum("TR_BLOOD"), oldorg, self.origin); + + self.renderflags = 0; + self.alpha = bound(0, self.nextthink - time, 1); + + if(self.alpha == 0) + remove(self); + else + R_AddEntity(self); +} + +void TossGib (string mdlname, vector org, vector v, float destroyontouch) +{ + entity gib; + + // TODO remove some gibs according to cl_nogibs + + gib = spawn(); + gib.classname = "gib"; + gib.move_movetype = MOVETYPE_BOUNCE; + gib.gravity = 1; + gib.solid = SOLID_CORPSE; + + setmodel (gib, mdlname); // precision set above + + setsize (gib, '-8 -8 -8', '8 8 8'); + + gib.draw = Gib_Draw; + if(destroyontouch) + gib.move_touch = Gib_Touch; + + gib.move_origin = org; + gib.move_velocity = v + randomvec(); + gib.move_avelocity = randomvec() * vlen(gib.move_velocity); + gib.move_time = time; + gib.damageforcescale = 3.5; + + gib.nextthink = time + 12 + random () * 4; +} + +void Ent_GibSplash() +{ + float amount, type; + vector org, vel, mi, ma; + + float c, gibfactor, randomvalue; + + amount = ReadByte() / 16.0; // gibbage amount + type = ReadByte(); // gibbage type + org_x = ReadShort() * 4 + 2; + org_y = ReadShort() * 4 + 2; + org_z = ReadShort() * 4 + 2; + vel = decompressShortVector(ReadShort()); + mi = decompressShortVector(ReadShort()); + ma = decompressShortVector(ReadShort()); + + gibfactor = 1 - cvar("cl_nogibs"); + if(gibfactor <= 0) + return; + + amount *= gibfactor; + + if(cvar("ekg")) + amount *= 5; + + if(type == 1) // full gibbage + { + sound (self, CHAN_PAIN, "misc/gib.wav", VOL_BASE, ATTN_NORM); + + if(random() < amount) + TossGib("models/gibs/eye.md3", org, vel + randomvec() * 150, 0); + te_bloodshower(org + mi, org + ma, 1200, 1000 * amount); + if(random() < amount) + TossGib("models/gibs/bloodyskull.md3", org, vel, 0); + + for(c = 0; c < amount; ++c) + { + randomvalue = amount - c; + + if(random() < randomvalue) + TossGib ("models/gibs/arm.md3", org, vel + randomvec() * (random() * 120 + 90),0); + if(random() < randomvalue) + TossGib ("models/gibs/arm.md3", org, vel + randomvec() * (random() * 120 + 90),0); + if(random() < randomvalue) + TossGib ("models/gibs/chest.md3", org + '0 0 -12', vel + randomvec() * (random() * 120 + 80),0); + if(random() < randomvalue) + TossGib ("models/gibs/smallchest.md3", org, vel + randomvec() * (random() * 120 + 80),0); + if(random() < randomvalue) + TossGib ("models/gibs/leg1.md3", org + '0 0 -5', vel + randomvec() * (random() * 120 + 85),0); + if(random() < randomvalue) + TossGib ("models/gibs/leg2.md3", org + '0 0 -9', vel + randomvec() * (random() * 120 + 85),0); + + // these splat on impact + if(random() < randomvalue) + TossGib ("models/gibs/chunk.mdl", org, vel + randomvec() * 450,1); + if(random() < randomvalue) + TossGib ("models/gibs/chunk.mdl", org, vel + randomvec() * 450,1); + if(random() < randomvalue) + TossGib ("models/gibs/chunk.mdl", org, vel + randomvec() * 450,1); + if(random() < randomvalue) + TossGib ("models/gibs/chunk.mdl", org, vel + randomvec() * 450,1); + } + } + else if(type == 2) // just blood + { + pointparticles(particleeffectnum("blood"), org, vel, amount); + } + else if(type == 3) // single gib + { + TossGib ("models/gibs/chunk.mdl", org, vel, 1); + } +} + +void GibSplash_Precache() +{ + precache_model("models/gibs/chunk.mdl"); + precache_model("models/gibs/leg1.mdl"); + precache_model("models/gibs/leg2.mdl"); + precache_model("models/gibs/chest.mdl"); + precache_model("models/gibs/smallchest.mdl"); + precache_model("models/gibs/arm.mdl"); + precache_model("models/gibs/bloodyskull.mdl"); + precache_model("models/gibs/eye.mdl"); +} diff --git a/data/qcsrc/client/movetypes.qc b/data/qcsrc/client/movetypes.qc index 41bbd9e37..345cfada7 100644 --- a/data/qcsrc/client/movetypes.qc +++ b/data/qcsrc/client/movetypes.qc @@ -17,16 +17,106 @@ void _Movetype_CheckWaterTransition() // SV_CheckWaterTransition void _Movetype_Impact(entity oth) // SV_Impact { - if(self.move_moveflags & MOVEFLAG_STOPONIMPACT) + entity oldother, oldself; + + oldself = self; + oldother = other; + + if(self.move_touch) + { + other = oth; + + self.move_touch(); + + other = oldother; + } + + if(oth.move_touch) + { + other = self; + self = oth; + + self.move_touch(); + + self = oldself; + other = oldother; + } +} + +void _Movetype_LinkEdict_TouchAreaGrid() // SV_LinkEdict_TouchAreaGrid +{ + entity e, oldself, oldother; + + oldself = self; + oldother = other; + + for(e = findradius(0.5 * (self.absmin + self.absmax), 0.5 * vlen(self.absmax - self.absmin)); e; e = e.chain) { - // don't CLIP the velocity, but stop ENTIRELY - self.velocity = '0 0 0'; - self.avelocity = '0 0 0'; + if(e.move_touch) + if(boxesoverlap(e.absmin, e.absmax, oldself.absmin, oldself.absmax)) + { + self = e; + other = oldself; + + trace_allsolid = FALSE; + trace_startsolid = FALSE; + trace_fraction = 1; + trace_inwater = FALSE; + trace_inopen = TRUE; + trace_endpos = e.origin; + trace_plane_normal = '0 0 1'; + trace_plane_dist = 0; + trace_ent = oldself; + + e.move_touch(); + } } + + other = oldother; + self = oldself; } void _Movetype_LinkEdict(float touch_triggers) // SV_LinkEdict { + vector mi, ma; + if(self.solid == SOLID_BSP) + { + // TODO set the absolute bbox + mi = self.mins; + ma = self.maxs; + } + else + { + mi = self.mins; + ma = self.maxs; + } + mi = mi + self.origin; + ma = ma + self.origin; + + if(self.move_flags & FL_ITEM) + { + mi_x -= 15; + mi_y -= 15; + mi_z -= 1; + ma_x += 15; + ma_y += 15; + ma_z += 1; + } + else + { + mi_x -= 1; + mi_y -= 1; + mi_z -= 1; + ma_x += 1; + ma_y += 1; + ma_z += 1; + } + + self.absmin = mi; + self.absmax = ma; + + if(touch_triggers) + _Movetype_LinkEdict_TouchAreaGrid(); } float _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition @@ -111,8 +201,9 @@ float _Movetype_PushEntity(vector push, float failonstartsolid) // SV_PushEntity self.move_origin = trace_endpos; - if(self.solid >= SOLID_TRIGGER && trace_ent && (!(self.move_flags & FL_ONGROUND) || (self.move_groundentity != trace_ent))) - _Movetype_Impact(trace_ent); + if(trace_fraction < 1) + if(self.solid >= SOLID_TRIGGER && (!(self.move_flags & FL_ONGROUND) || (self.move_groundentity != trace_ent))) + _Movetype_Impact(trace_ent); return trace_fraction; } @@ -139,7 +230,10 @@ void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss if(self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS) { self.move_didgravity = TRUE; - self.move_velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY); + if(self.gravity) + self.move_velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY); + else + self.move_velocity_z -= dt * getstatf(STAT_MOVEVARS_GRAVITY); } self.move_angles = self.move_angles + self.move_avelocity * dt; @@ -168,11 +262,15 @@ void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss } else if(self.move_movetype == MOVETYPE_BOUNCE) { - self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1.5); + float d, bouncefac, bouncestop; + + bouncefac = self.move_bounce_factor; if(!bouncefac) bouncefac = 0.5; + bouncestop = self.move_bounce_stopspeed; if(!bouncestop) bouncestop = 60; + + self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1 + bouncefac); - float d; d = trace_plane_normal * self.move_velocity; - if(trace_plane_normal_z > 0.7 && d < 60 && d > -60) + if(trace_plane_normal_z > 0.7 && d < bouncestop && d > -bouncestop) { self.move_flags |= FL_ONGROUND; self.move_groundentity = trace_ent; @@ -269,7 +367,12 @@ void Movetype_Physics(float matchserver) // SV_Physics_Entity // now continue the move from move_time to time self.velocity = self.move_velocity; if(self.move_didgravity) - self.velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY); + { + if(self.gravity) + self.velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY); + else + self.velocity_z -= dt * getstatf(STAT_MOVEVARS_GRAVITY); + } self.angles = self.move_angles + dt * self.avelocity; @@ -288,4 +391,7 @@ void Movetype_Physics(float matchserver) // SV_Physics_Entity self.angles = self.move_angles; self.origin = self.move_origin; } + + if(!wasfreed(self)) + setorigin(self, self.origin); } diff --git a/data/qcsrc/client/movetypes.qh b/data/qcsrc/client/movetypes.qh index 8a2df2d2f..34b0a1cd5 100644 --- a/data/qcsrc/client/movetypes.qh +++ b/data/qcsrc/client/movetypes.qh @@ -1,11 +1,13 @@ -.float move_flags; .float move_movetype; .float move_time; .vector move_origin; .vector move_angles; .vector move_velocity; .vector move_avelocity; -.float move_moveflags; +.float move_flags; +.void(void) move_touch; +.float move_bounce_factor; +.float move_bounce_stopspeed; void Movetype_Physics(float matchserver); @@ -24,6 +26,5 @@ float MOVETYPE_BOUNCEMISSILE = 11; // Like bounce but doesn't lose speed on boun float MOVETYPE_FOLLOW = 12; float MOVETYPE_FAKEPUSH = 13; +float FL_ITEM = 256; float FL_ONGROUND = 512; - -float MOVEFLAG_STOPONIMPACT = 1; diff --git a/data/qcsrc/client/progs.src b/data/qcsrc/client/progs.src index d035d9a08..4669b2e36 100644 --- a/data/qcsrc/client/progs.src +++ b/data/qcsrc/client/progs.src @@ -30,6 +30,8 @@ hook.qc particles.qc laser.qc projectile.qc +gibs.qc +damage.qc Main.qc View.qc diff --git a/data/qcsrc/client/projectile.qc b/data/qcsrc/client/projectile.qc index 8eb553eca..35707a31e 100644 --- a/data/qcsrc/client/projectile.qc +++ b/data/qcsrc/client/projectile.qc @@ -1,3 +1,13 @@ +void SUB_Null() +{ +} + +void SUB_Stop() +{ + self.move_velocity = self.move_avelocity = '0 0 0'; + self.move_movetype = MOVETYPE_NONE; +} + .float count; // set if clientside projectile .float cnt; // sound index .float gravity; @@ -82,7 +92,7 @@ void loopsound(entity e, float ch, string samp, float vol, float attn) void Ent_RemoveProjectile() { if(self.cnt) - loopsound(self, CHAN_PAIN, "misc/null.wav", VOL_BASE, ATTN_NORM); + loopsound(self, CHAN_PROJECTILE, "misc/null.wav", VOL_BASE, ATTN_NORM); } void Ent_Projectile() @@ -170,26 +180,26 @@ void Ent_Projectile() self.mins = '0 0 0'; self.maxs = '0 0 0'; self.colormod = '0 0 0'; + self.move_touch = SUB_Stop; self.move_movetype = MOVETYPE_TOSS; - self.move_moveflags = MOVEFLAG_STOPONIMPACT; switch(self.cnt) { case PROJECTILE_ELECTRO: // only new engines support sound moving with object - loopsound(self, CHAN_PAIN, "weapons/electro_fly.wav", VOL_BASE, ATTN_NORM); + loopsound(self, CHAN_PROJECTILE, "weapons/electro_fly.wav", VOL_BASE, ATTN_NORM); self.mins = '0 0 -3'; self.maxs = '0 0 -3'; self.move_movetype = MOVETYPE_BOUNCE; - self.move_moveflags = 0; + self.move_touch = SUB_Null; break; case PROJECTILE_ROCKET: - loopsound(self, CHAN_PAIN, "weapons/rocket_fly.wav", VOL_BASE, ATTN_NORM); + loopsound(self, CHAN_PROJECTILE, "weapons/rocket_fly.wav", VOL_BASE, ATTN_NORM); self.mins = '-3 -3 -3'; self.maxs = '3 3 3'; break; case PROJECTILE_TAG: - loopsound(self, CHAN_PAIN, "weapons/tag_rocket_fly.wav", VOL_BASE, ATTN_NORM); + loopsound(self, CHAN_PROJECTILE, "weapons/tag_rocket_fly.wav", VOL_BASE, ATTN_NORM); self.mins = '-2 -2 -2'; self.maxs = '2 2 2'; break; @@ -197,7 +207,7 @@ void Ent_Projectile() self.mins = '0 0 -3'; self.maxs = '0 0 -3'; self.move_movetype = MOVETYPE_BOUNCE; - self.move_moveflags = 0; + self.move_touch = SUB_Null; break; case PROJECTILE_SEEKER: self.mins = '-2 -2 -2'; @@ -211,13 +221,28 @@ void Ent_Projectile() break; case PROJECTILE_HAGAR_BOUNCING: self.move_movetype = MOVETYPE_BOUNCE; - self.move_moveflags = 0; + self.move_touch = SUB_Null; break; default: break; } } + if(self.gravity) + { + if(self.move_movetype == MOVETYPE_FLY) + self.movetype = MOVETYPE_TOSS; + if(self.move_movetype == MOVETYPE_BOUNCEMISSILE) + self.movetype = MOVETYPE_BOUNCE; + } + else + { + if(self.move_movetype == MOVETYPE_TOSS) + self.movetype = MOVETYPE_FLY; + if(self.move_movetype == MOVETYPE_BOUNCE) + self.movetype = MOVETYPE_BOUNCEMISSILE; + } + if(!(self.count & 0x80)) InterpolateOrigin_Note(); diff --git a/data/qcsrc/common/constants.qh b/data/qcsrc/common/constants.qh index 0e412a445..f9a264740 100644 --- a/data/qcsrc/common/constants.qh +++ b/data/qcsrc/common/constants.qh @@ -55,6 +55,8 @@ const float ENT_CLIENT_NAGGER = 9; // flags [votecalledvote] const float ENT_CLIENT_WAYPOINT = 10; // flags origin [team displayrule] [spritename] [spritename2] [spritename3] [lifetime maxdistance hideable] const float ENT_CLIENT_RADARLINK = 11; // flags [startorigin] [endorigin] [startcolor+16*endcolor] const float ENT_CLIENT_PROJECTILE = 12; +const float ENT_CLIENT_GIBSPLASH = 13; +const float ENT_CLIENT_DAMAGEINFO = 14; const float SPRITERULE_DEFAULT = 0; const float SPRITERULE_TEAMPLAY = 1; @@ -326,7 +328,7 @@ float CHAN_PROJECTILE = 4; // Projectiles // on world: UNUSED // on players: projectiles hitting player SHOTS // on entities: projectiles SHOTS - // on csqc: UNUSED + // on csqc: projectile sounds SHOTS float CHAN_WEAPON2 = 5; // Nex fire (separated as it is a very long sound) // on world: UNUSED // on players: weapon firing WEAPONS @@ -336,7 +338,7 @@ float CHAN_PAIN = 6; // Pain // on world: UNUSED // on players: pain PAIN // on entities: projectiles flying SHOTS - // on csqc: projectiles flying SHOTS + // on csqc: player pain PAIN float CHAN_PLAYER = 7; // Player body // on world: UNUSED // on players: player sounds PLAYER diff --git a/data/qcsrc/common/util.qc b/data/qcsrc/common/util.qc index 967f9d603..c32e7a001 100644 --- a/data/qcsrc/common/util.qc +++ b/data/qcsrc/common/util.qc @@ -1301,3 +1301,9 @@ string rgb_to_hexcolor(vector rgb) DEC_TO_HEXDIGIT(floor(rgb_z * 15 + 0.5)) ); } + +// requires that m2>m1 in all coordinates, and that m4>m3 +float boxesoverlap(vector m1, vector m2, vector m3, vector m4) {return m2_x >= m3_x && m1_x <= m4_x && m2_y >= m3_y && m1_y <= m4_y && m2_z >= m3_z && m1_z <= m4_z;}; + +// requires the same, but is a stronger condition +float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs) {return smins_x >= bmins_x && smaxs_x <= bmaxs_x && smins_y >= bmins_y && smaxs_y <= bmaxs_y && smins_z >= bmins_z && smaxs_z <= bmaxs_z;}; diff --git a/data/qcsrc/common/util.qh b/data/qcsrc/common/util.qh index 2968cdc83..f420156ec 100644 --- a/data/qcsrc/common/util.qh +++ b/data/qcsrc/common/util.qh @@ -132,3 +132,6 @@ vector hsl_to_rgb(vector hsl); vector rgb_to_hsv(vector rgb); vector hsv_to_rgb(vector hsv); string rgb_to_hexcolor(vector rgb); + +float boxesoverlap(vector m1, vector m2, vector m3, vector m4); +float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs); diff --git a/data/qcsrc/menu/nexuiz/dialog_settings_audio.c b/data/qcsrc/menu/nexuiz/dialog_settings_audio.c index d4e750a88..a1cffd3f7 100644 --- a/data/qcsrc/menu/nexuiz/dialog_settings_audio.c +++ b/data/qcsrc/menu/nexuiz/dialog_settings_audio.c @@ -56,7 +56,7 @@ void fillNexuizAudioSettingsTab(entity me) setDependentStringNotEqual(s, "volume", "0"); me.TR(me); me.TDempty(me, 0.2); - s = makeNexuizDecibelsSlider(-20, 0, 0.5, "snd_playerchannel6volume"); + s = makeNexuizDecibelsSlider(-20, 0, 0.5, "snd_playerchannel6volume snd_csqcchannel6volume"); me.TD(me, 1, 0.8, e = makeNexuizSliderCheckBox(-1000000, 1, s, "Pain:")); me.TD(me, 1, 2, s); setDependentStringNotEqual(e, "volume", "0"); @@ -72,7 +72,7 @@ void fillNexuizAudioSettingsTab(entity me) me.TR(me); me.TDempty(me, 0.2); s = makeNexuizDecibelsSlider(-20, 0, 0.5, "snd_entchannel4volume"); - makeMulti(s, "snd_playerchannel4volume snd_entchannel6volume snd_csqcchannel6volume"); + makeMulti(s, "snd_playerchannel4volume snd_entchannel6volume snd_csqcchannel4volume"); me.TD(me, 1, 0.8, e = makeNexuizSliderCheckBox(-1000000, 1, s, "Shots:")); me.TD(me, 1, 2, s); setDependentStringNotEqual(e, "volume", "0"); diff --git a/data/qcsrc/server/cl_player.qc b/data/qcsrc/server/cl_player.qc index f38b061c4..684bfa90f 100644 --- a/data/qcsrc/server/cl_player.qc +++ b/data/qcsrc/server/cl_player.qc @@ -51,7 +51,6 @@ void CopyBody(float keepvelocity) self.solid = oldself.solid; self.takedamage = oldself.takedamage; self.think = oldself.think; - self.gibrandom = oldself.gibrandom; self.customizeentityforclient = oldself.customizeentityforclient; if (keepvelocity == 1) self.velocity = oldself.velocity; @@ -258,8 +257,8 @@ void SpawnThrownWeapon (vector org, float w) void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { local float take, save; - if(sv_gentle < 1) - pointparticles(particleeffectnum("blood"), hitloc, force, bound(0, damage, 200)); + Violence_GibSplash_At(hitloc, '0 0 0', '0 0 0', force, 2, bound(0, damage, 200) / 16); + // damage resistance (ignore most of the damage from a bullet or similar) damage = max(damage - 5, 1); @@ -273,13 +272,10 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float else if (take > 10) sound (self, CHAN_PROJECTILE, "misc/bodyimpact1.wav", VOL_BASE, ATTN_NORM); - if(independent_players) - if(sv_gentle < 1) { - if (take > 50) - TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.1,1); - if (take > 100) - TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.2,1); - } + if (take > 50) + Violence_GibSplash_At(hitloc, '0 0 0', '0 0 0', force * -0.1, 3, 1); + if (take > 100) + Violence_GibSplash_At(hitloc, '0 0 0', '0 0 0', force * -0.2, 3, 1); if (!(self.flags & FL_GODMODE)) { @@ -292,7 +288,7 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float self.dmg_take = self.dmg_take + take;//max(take - 10, 0); self.dmg_inflictor = inflictor; - if (self.health <= -75) + if (self.health <= -75 && self.modelindex != 0) { // don't use any animations as a gib self.frame = 0; @@ -300,61 +296,9 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float // view just above the floor self.view_ofs = '0 0 4'; - // make a juicy mess - local float multiplier; - multiplier = 1; - if (cvar("ekg")) - multiplier = 5; - - - // make a meaty mess - if(independent_players) - { - TossGib (self, "models/gibs/eye.md3", self.origin + self.view_ofs, self.velocity + randomvec() * 150,0); - self.solid = SOLID_TRIGGER; // undo SOLID_CORPSE - self.takedamage = DAMAGE_NO; // can't damage this gib, to prevent better jumps from it - } - else - TossGib (self, "models/gibs/eye.md3", self.origin + self.view_ofs, self.velocity + randomvec() * 150,0); - - if not(independent_players) - if(sv_gentle < 1) { - te_bloodshower (self.origin + self.mins, self.origin + self.maxs, 1200 * multiplier, 1000); - TossGib (world, "models/gibs/bloodyskull.md3", self.origin + self.view_ofs, self.velocity,0); - - local float c; - c = 0; - - while (c < multiplier) - { - c = c + 1; - //TossGib (world, "models/gibs/gib1.md3", self.origin, self.velocity + randomvec() * 450,0); - //TossGib (world, "models/gibs/gib2.md3", self.origin, self.velocity + randomvec() * 450,0); - //TossGib (world, "models/gibs/gib3.md3", self.origin, self.velocity + randomvec() * 450,0); - //TossGib (world, "models/gibs/gib4.md3", self.origin, self.velocity + randomvec() * 450,0); - //TossGib (world, "models/gibs/gib5.md3", self.origin, self.velocity + randomvec() * 450,0); - //TossGib (world, "models/gibs/gib6.md3", self.origin, self.velocity + randomvec() * 450,0); - - TossGib (world, "models/gibs/arm.md3", self.origin + self.view_ofs, self.velocity + randomvec() * (random() * 120 + 90),0); - TossGib (world, "models/gibs/arm.md3", self.origin + self.view_ofs, self.velocity + randomvec() * (random() * 120 + 90),0); - //TossGib (world, "models/gibs/arm.md3", self.origin + self.view_ofs, self.velocity + randomvec() * 150,0); - //TossGib (world, "models/gibs/arm.md3", self.origin + self.view_ofs, self.velocity + randomvec() * 150,0); - TossGib (world, "models/gibs/chest.md3", self.origin + self.view_ofs * 0.5, self.velocity + randomvec() * (random() * 120 + 80),0); - //TossGib (world, "models/gibs/smallchest.md3", self.origin + self.view_ofs, self.velocity + randomvec() * 150,0); - TossGib (world, "models/gibs/smallchest.md3", self.origin + self.view_ofs, self.velocity + randomvec() * (random() * 120 + 80),0); - TossGib (world, "models/gibs/leg1.md3", self.origin + self.view_ofs * -0.2, self.velocity + randomvec() * (random() * 120 + 85),0); - TossGib (world, "models/gibs/leg2.md3", self.origin + self.view_ofs * -0.4, self.velocity + randomvec() * (random() * 120 + 85),0); - //TossGib (world, "models/gibs/leg1.md3", self.origin + self.view_ofs * -0.2, self.velocity + randomvec() * 150,0); - //TossGib (world, "models/gibs/leg2.md3", self.origin + self.view_ofs * -0.4, self.velocity + randomvec() * 150,0); - - // these splat on impact - TossGib (world, "models/gibs/chunk.mdl", self.origin, self.velocity + randomvec() * 450,1); - TossGib (world, "models/gibs/chunk.mdl", self.origin, self.velocity + randomvec() * 450,1); - TossGib (world, "models/gibs/chunk.mdl", self.origin, self.velocity + randomvec() * 450,1); - TossGib (world, "models/gibs/chunk.mdl", self.origin, self.velocity + randomvec() * 450,1); - } - sound (self, CHAN_PLAYER, "misc/gib.wav", VOL_BASE, ATTN_NORM); - } + Violence_GibSplash(self, 1, 1); + self.modelindex = 0; // restore later + self.solid = SOLID_NOT; // restore later } } @@ -371,11 +315,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht damage /= sqrt(bound(1.0, attacker.cvar_cl_handicap, 100.0)); } - if(sv_gentle > 0) { - pointparticles(particleeffectnum("damage_hit"), hitloc, force, bound(0, damage, 200)); - } else { - pointparticles(particleeffectnum("blood"), hitloc, force, bound(0, damage, 200)); - } + Violence_GibSplash_At(hitloc, '0 0 0', '0 0 0', force, 2, bound(0, damage, 200) / 16); if(g_arena) if(numspawned < 2) @@ -399,14 +339,10 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht else if (take > 10) sound (self, CHAN_PROJECTILE, "misc/bodyimpact1.wav", VOL_BASE, ATTN_NORM); // FIXME possibly remove them? - if(sv_gentle < 1) - if not(independent_players) - { - if (take > 50) - TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.1,1); - if (take > 100) - TossGib (world, "models/gibs/chunk.mdl", hitloc, force * -0.2,1); - } + if (take > 50) + Violence_GibSplash_At(hitloc, '0 0 0', '0 0 0', force * -0.1, 3, 1); + if (take > 100) + Violence_GibSplash_At(hitloc, '0 0 0', '0 0 0', force * -0.2, 3, 1); if (time > self.spawnshieldtime) { diff --git a/data/qcsrc/server/cl_weaponsystem.qc b/data/qcsrc/server/cl_weaponsystem.qc index f18d6917b..28c51c5fa 100644 --- a/data/qcsrc/server/cl_weaponsystem.qc +++ b/data/qcsrc/server/cl_weaponsystem.qc @@ -351,6 +351,7 @@ void CL_ExteriorWeaponentity_Think() void CL_SpawnWeaponentity() { self.weaponentity = spawn(); + self.weaponentity.classname = "weaponentity"; self.weaponentity.solid = SOLID_NOT; self.weaponentity.owner = self; self.weaponentity.weaponentity = self.weaponentity; @@ -365,6 +366,7 @@ void CL_SpawnWeaponentity() self.weaponentity.scale = 0.61; self.exteriorweaponentity = spawn(); + self.exteriorweaponentity.classname = "exteriorweaponentity"; self.exteriorweaponentity.solid = SOLID_NOT; self.exteriorweaponentity.exteriorweaponentity = self.exteriorweaponentity; self.exteriorweaponentity.owner = self; diff --git a/data/qcsrc/server/g_damage.qc b/data/qcsrc/server/g_damage.qc index ee9f51d56..ba5a77e13 100644 --- a/data/qcsrc/server/g_damage.qc +++ b/data/qcsrc/server/g_damage.qc @@ -1,3 +1,47 @@ +.float dmg; +.float dmg_edge; +.float dmg_force; +.float dmg_radius; + +float Damage_DamageInfo_SendEntity(entity to, float sf) +{ + WriteByte(MSG_ENTITY, ENT_CLIENT_DAMAGEINFO); + WriteShort(MSG_ENTITY, self.projectiledeathtype); + WriteCoord(MSG_ENTITY, floor(self.origin_x)); + WriteCoord(MSG_ENTITY, floor(self.origin_y)); + WriteCoord(MSG_ENTITY, floor(self.origin_z)); + WriteByte(MSG_ENTITY, bound(1, self.dmg, 255)); + WriteByte(MSG_ENTITY, bound(0, self.dmg_radius, 255)); + WriteByte(MSG_ENTITY, bound(1, self.dmg_edge, 255)); + WriteShort(MSG_ENTITY, self.oldorigin_x); + return TRUE; +} + +void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, float deathtype) +{ + // TODO maybe call this from non-edgedamage too? + // TODO maybe make the client do the particle effects for the weapons and the impact sounds using this info? + + entity e; + + e = spawn(); + e.classname = "damageinfo"; + setorigin(e, org); + setmodel(e, "null"); + e.think = SUB_Remove; + e.nextthink = time + 0.2; + e.projectiledeathtype = deathtype; + e.dmg = coredamage; + e.dmg_edge = edgedamage; + e.dmg_radius = rad; + e.dmg_force = vlen(force); + e.velocity = force; + + e.oldorigin_x = compressShortVector(e.velocity); + + e.SendEntity = Damage_DamageInfo_SendEntity; +} + #define DAMAGE_CENTERPRINT_SPACER NEWLINES float checkrules_firstblood; @@ -898,11 +942,15 @@ float RadiusDamage (entity inflictor, entity attacker, float coredamage, float e return 0; } + RadiusDamage_running = 1; blastorigin = (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5); total_damage_to_creatures = 0; + if(deathtype == WEP_HOOK | HITTYPE_SECONDARY | HITTYPE_BOUNCE) // only send gravity bomb damage once + Damage_DamageInfo(blastorigin, coredamage, edgedamage, rad, forceintensity * '0 0 1', deathtype); + targ = findradius (blastorigin, rad); while (targ) { diff --git a/data/qcsrc/server/g_violence.qc b/data/qcsrc/server/g_violence.qc index 030fae9d1..14dc6239c 100644 --- a/data/qcsrc/server/g_violence.qc +++ b/data/qcsrc/server/g_violence.qc @@ -1,98 +1,42 @@ -void GibDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) +float Violence_GibSplash_SendEntity(entity to, float sf) { - float r; - r = random (); - if (r < 0.60) - sound (self, CHAN_PROJECTILE, "misc/gib_splat01.wav", VOL_BASE, ATTN_NORM); - else if (r < 0.65) - sound (self, CHAN_PROJECTILE, "misc/gib_splat02.wav", VOL_BASE, ATTN_NORM); - else if (r < 0.70) - sound (self, CHAN_PROJECTILE, "misc/gib_splat03.wav", VOL_BASE, ATTN_NORM); - else if (r < 0.75) - sound (self, CHAN_PROJECTILE, "misc/gib_splat04.wav", VOL_BASE, ATTN_NORM); - - if(sv_gentle < 1) - pointparticles(particleeffectnum("blood"), self.origin + '0 0 1', '0 0 30', 10); - self.health = self.health - damage; - if (self.health <= -1000) - { - self.event_damage = SUB_Null; - SUB_VanishOrRemove (self); - } + WriteByte(MSG_ENTITY, ENT_CLIENT_GIBSPLASH); + WriteByte(MSG_ENTITY, bound(1, self.cnt * 16, 255)); // gibbage amount multiplier + WriteByte(MSG_ENTITY, self.state); // actually type + WriteShort(MSG_ENTITY, floor(self.origin_x / 4)); // not using a coord here, as gibs don't need this accuracy + WriteShort(MSG_ENTITY, floor(self.origin_y / 4)); // not using a coord here, as gibs don't need this accuracy + WriteShort(MSG_ENTITY, floor(self.origin_z / 4)); // not using a coord here, as gibs don't need this accuracy + WriteShort(MSG_ENTITY, self.oldorigin_x); // acrually compressed velocity + WriteShort(MSG_ENTITY, self.oldorigin_y); // acrually compressed mins + WriteShort(MSG_ENTITY, self.oldorigin_z); // acrually compressed maxs + return TRUE; } - -void GibTouch () +// TODO maybe convert this to a TE? +void Violence_GibSplash_At(vector org, vector mi, vector ma, vector dir, float type, float amount) { - if(SUB_NoImpactCheck()) - { - SUB_VanishOrRemove(self); - return; - } - GibDamage (other, other, 1000, 0, self.origin, '0 0 0'); + entity e; + + e = spawn(); + e.classname = "gibsplash"; + e.cnt = amount; + e.state = type; + e.SendEntity = Violence_GibSplash_SendEntity; + e.nextthink = time + 0.2; + e.think = SUB_Remove; + // 0.2s should be enough time for all clients to receive this ent once, do the gibbage and be done with it + setmodel(e, "null"); + e.effects = EF_NODEPTHTEST; // show gibs from around the corner + setorigin(e, org); + setsize(e, mi, ma); + e.velocity = dir; + + e.oldorigin_x = compressShortVector(e.velocity); + e.oldorigin_y = compressShortVector(e.mins); + e.oldorigin_z = compressShortVector(e.maxs); } - -.float gibrandom; -.float gibmodelindex; -float Gib_customizeentityforclient() +void Violence_GibSplash(entity source, float type, float amount) { - if(self.classname == "player") // the eye - { - if(sv_gentle > 0) { - self.model = ""; - return TRUE; - } - if(self.gibrandom > other.cvar_cl_nogibs) - self.model = self.mdl; - else - self.model = ""; - return TRUE; - } - else // other gibs - don't even need to send them - return (self.gibrandom > other.cvar_cl_nogibs); -}; - -// changes by LordHavoc on 03/30/04 -// TossGib now takes a gib entity so it can be used for tossing heads -// gib.velocity now uses randomvec() instead of a bunch of manual random calls -// merged Gib() into PlayerGib() -void TossGib (entity gib, string mdlname, vector org, vector v, float destroyontouch) -{ - if (gib == world) - { - gib = spawn (); - gib.deadflag = DEAD_DEAD; - } - - // don't set his classname to something else or it'll screw up a lot of stuff - if(gib.classname != "player") - gib.classname = "gib"; - gib.iscreature = FALSE; // not a creature, because lava sounds on gibs are annoying - gib.movetype = MOVETYPE_BOUNCE; - gib.solid = SOLID_CORPSE; - gib.skin = 0; - gib.effects = 0; - gib.gibrandom = random(); // used for customize function to reduce gibs - gib.customizeentityforclient = Gib_customizeentityforclient; - gib.effects = EF_LOWPRECISION; // use less bandwidth - - gib.mdl = mdlname; - setmodel (gib, mdlname); // precision set above - gib.gibmodelindex = gib.modelindex; - setsize (gib, '-8 -8 -8', '8 8 8'); - setorigin (gib, org); - - gib.health = -1; - gib.takedamage = DAMAGE_YES; - gib.damageforcescale = 3.5; - gib.event_damage = GibDamage; - if (destroyontouch == 1) - gib.touch = GibTouch; - - gib.velocity = v + randomvec(); - gib.avelocity = randomvec() * vlen(gib.velocity); - gib.oldvelocity = gib.velocity; - - SUB_SetFade (gib, time + 12 + random () * 4, 1); + Violence_GibSplash_At(source.origin + source.view_ofs, source.mins - source.view_ofs, source.maxs - source.view_ofs, source.velocity, type, amount); } diff --git a/data/qcsrc/server/miscfunctions.qc b/data/qcsrc/server/miscfunctions.qc index 34bddfbe4..8fd4190cf 100644 --- a/data/qcsrc/server/miscfunctions.qc +++ b/data/qcsrc/server/miscfunctions.qc @@ -689,12 +689,6 @@ vector randompos(vector m1, vector m2) return v; }; -// requires that m2>m1 in all coordinates, and that m4>m3 -float boxesoverlap(vector m1, vector m2, vector m3, vector m4) {return m2_x >= m3_x && m1_x <= m4_x && m2_y >= m3_y && m1_y <= m4_y && m2_z >= m3_z && m1_z <= m4_z;}; - -// requires the same, but is a stronger condition -float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs) {return smins_x >= bmins_x && smaxs_x <= bmaxs_x && smins_y >= bmins_y && smaxs_y <= bmaxs_y && smins_z >= bmins_z && smaxs_z <= bmaxs_z;}; - float g_pickup_shells; float g_pickup_shells_max; float g_pickup_nails; diff --git a/data/qcsrc/server/w_hook.qc b/data/qcsrc/server/w_hook.qc index 9bf51e3e0..129e6d778 100644 --- a/data/qcsrc/server/w_hook.qc +++ b/data/qcsrc/server/w_hook.qc @@ -20,6 +20,7 @@ void W_Hook_ExplodeThink (void) self.dmg_last = dmg_remaining_next; RadiusDamage (self, self.owner, self.dmg * f, self.dmg_edge * f, self.dmg_radius, self.owner, self.dmg_force * f, self.projectiledeathtype, world); + self.projectiledeathtype |= HITTYPE_BOUNCE; //RadiusDamage (self, world, self.dmg * f, self.dmg_edge * f, self.dmg_radius, world, self.dmg_force * f, self.projectiledeathtype, world); if(dt < self.dmg_duration) -- 2.39.2