From: Mircea Kitsune Date: Thu, 25 Aug 2011 12:36:41 +0000 (+0300) Subject: Merge branch 'master' into mirceakitsune/damage_effects X-Git-Tag: xonotic-v0.6.0~110^2^2~101 X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=f2a79cba0897fb6f6cb7ebeecb596b5547af3ddd;hp=f3cd6e8e994c399d573bf829b43ef04efb6d1a67 Merge branch 'master' into mirceakitsune/damage_effects Conflicts: effectinfo.txt qcsrc/client/Main.qc qcsrc/client/autocvars.qh qcsrc/client/gibs.qc --- diff --git a/defaultXonotic.cfg b/defaultXonotic.cfg index 8a76f7a99e..b896923f7f 100644 --- a/defaultXonotic.cfg +++ b/defaultXonotic.cfg @@ -358,6 +358,12 @@ set g_telefrags_teamplay 1 "never telefrag team mates" set g_telefrags_avoid 1 "when teleporters have a random destination, avoid teleporting to locations where a telefrag would happen" set g_teleport_maxspeed 0 "maximum speed that a player can keep when going through a teleporter (if a misc_teleporter_dest also has a cap the smallest one of these will be used), 0 = don't limit, -1 = keep no speed" +set sv_damageeffect_tick 0.05 "how often the damage effect is updated (particles per second), low values might cause lag" +set sv_damageeffect_lifetime 0.04 "how much a damage effect lasts, multiplied by damage amount" +set sv_damageeffect_lifetime_max 5 "maximum amount of lifetime a damage effect may have at a time" +set cl_damageeffect 1 "enable weapon damage effects on players, values between 0 and 1 specify probability of the effect showing on players each tick (used to reduce the effect)" +set cl_damageeffect_gibs 0.15 "probability of the effect showing on gibs each tick (used to reduce the effect)" + set g_respawn_ghosts 1 "if 1 dead bodies become ghosts and float away when the player respawns" set g_respawn_ghosts_speed 5 "the speed with which respawn ghosts float and rotate" set g_respawn_ghosts_maxtime 6 "maximum amount of time a respawn ghost can last, minimum time is half this value. 0 disables and ghosts fade when the body would" diff --git a/effectinfo.txt b/effectinfo.txt index bf631fb254..f69cdc907d 100644 --- a/effectinfo.txt +++ b/effectinfo.txt @@ -6407,3 +6407,647 @@ velocityoffset 0 0 200 airfriction 4 color 0x4F4B46 0x000000 rotate -180 180 -20 20 + +// tuba does not use the weapon damage effect + +// laser damage effect +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_laser +count 3 +type smoke +tex 0 8 +color 0x880000 0xff4400 +size 8 16 +sizeincrease 10 +alpha 128 16 128 +gravity 0 +originjitter 4 4 16 +velocityjitter 0.4 0.4 0.6 +velocitymultiplier 0 +airfriction -0.35 +rotate 0 180 -30 30 + +// shotgun damage effect, normal blood +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_shotgun +count 0.5 +type blood +tex 24 32 +size 4 9 +alpha 256 256 64 +color 0xA8FFFF 0xA8FFFFF +bounce -1 +airfriction 1 +liquidfriction 4 +velocityjitter 64 64 64 +velocitymultiplier 5 +staincolor 0x808080 0x808080 +staintex 16 24 +//blood mist +effect weapondamage_shotgun +countabsolute 1 +type alphastatic +tex 0 8 +size 8 16 +alpha 100 256 400 +color 0x000000 0x420000 +originjitter 11 11 11 + +// shotgun damage effect, alien blood +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_shotgun_alien +count 0.5 +type blood +tex 24 32 +size 4 9 +alpha 256 256 64 +color 0xDC9BCD 0xDC9BCD +bounce -1 +airfriction 1 +liquidfriction 4 +velocityjitter 64 64 64 +velocitymultiplier 5 +staincolor 0x808080 0x808080 +staintex 16 24 +//blood mist +effect weapondamage_shotgun_alien +countabsolute 1 +type alphastatic +tex 0 8 +size 8 16 +alpha 100 256 400 +color 0x000000 0x204010 +originjitter 11 11 11 + +// shotgun damage effect, robot blood +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_shotgun_robot +count 0.5 +type blood +tex 24 32 +size 4 9 +alpha 256 256 64 +color 0xC0D890 0xC0D890 +bounce -1 +airfriction 1 +liquidfriction 4 +velocityjitter 64 64 64 +velocitymultiplier 5 +staincolor 0x808080 0x808080 +staintex 16 24 +//blood mist +effect weapondamage_shotgun_robot +countabsolute 1 +type alphastatic +tex 0 8 +size 8 16 +alpha 100 256 400 +color 0x000000 0x301860 +originjitter 11 11 11 + +// uzi damage effect, normal blood +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_uzi +count 0.25 +type blood +tex 24 32 +size 3 8 +alpha 256 256 64 +color 0xA8FFFF 0xA8FFFFF +bounce -1 +airfriction 1 +liquidfriction 4 +velocityjitter 64 64 64 +velocitymultiplier 5 +staincolor 0x808080 0x808080 +staintex 16 24 +//blood mist +effect weapondamage_uzi +countabsolute 1 +type alphastatic +tex 0 8 +size 6 12 +alpha 100 256 400 +color 0x000000 0x420000 +originjitter 11 11 11 + +// uzi damage effect, alien blood +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_uzi_alien +count 0.25 +type blood +tex 24 32 +size 3 8 +alpha 256 256 64 +color 0xDC9BCD 0xDC9BCD +bounce -1 +airfriction 1 +liquidfriction 4 +velocityjitter 64 64 64 +velocitymultiplier 5 +staincolor 0x808080 0x808080 +staintex 16 24 +//blood mist +effect weapondamage_uzi_alien +countabsolute 1 +type alphastatic +tex 0 8 +size 6 12 +alpha 100 256 400 +color 0x000000 0x204010 +originjitter 11 11 11 + +// uzi damage effect, robot blood +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_uzi_robot +count 0.25 +type blood +tex 24 32 +size 3 8 +alpha 256 256 64 +color 0xC0D890 0xC0D890 +bounce -1 +airfriction 1 +liquidfriction 4 +velocityjitter 64 64 64 +velocitymultiplier 5 +staincolor 0x808080 0x808080 +staintex 16 24 +//blood mist +effect weapondamage_uzi_robot +countabsolute 1 +type alphastatic +tex 0 8 +size 6 12 +alpha 100 256 400 +color 0x000000 0x301860 +originjitter 11 11 11 + +// minelayer damage effect +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_minelayer +//notunderwater +count 2 +type smoke +tex 48 55 +size 6 12 +alpha 256 16 256 +gravity -0.5 +color 0x8f0d00 0xff5a00 +sizeincrease -10 +originoffset 0 0 10 +originjitter 6 6 8 +velocityjitter 22 22 50 +// smoke +effect weapondamage_minelayer +type alphastatic +count 2 +tex 0 8 +size 4 8 +sizeincrease 5 +alpha 128 32 128 +color 0x000000 0x111111 +gravity -0.3 +originoffset 0 0 10 +originjitter 6 6 8 +velocityjitter 11 11 50 +// light +effect weapondamage_minelayer +trailspacing 8 +lightradius 60 +lightradiusfade 280 +lightcolor 0.9 0.6 0.2 + +// grenadelauncher damage effect +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_grenadelauncher +//notunderwater +count 2 +type smoke +tex 48 55 +size 6 12 +alpha 256 16 256 +gravity -0.5 +color 0x8f0d00 0xff5a00 +sizeincrease -10 +originoffset 0 0 10 +originjitter 6 6 8 +velocityjitter 22 22 50 +// smoke +effect weapondamage_grenadelauncher +type alphastatic +count 2 +tex 0 8 +size 4 8 +sizeincrease 5 +alpha 128 32 128 +color 0x000000 0x111111 +gravity -0.3 +originoffset 0 0 10 +originjitter 6 6 8 +velocityjitter 11 11 50 +// light +effect weapondamage_grenadelauncher +trailspacing 8 +lightradius 60 +lightradiusfade 280 +lightcolor 0.9 0.6 0.2 + +// electro damage effect +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_electro +count 2 +type static +tex 47 47 +color 0x66ffff 0x2288ff +size 10 20 +sizeincrease -16 +alpha 48 8 48 +gravity -0.0001 +airfriction 0.2 +liquidfriction 0.8 +originjitter 16 16 32 +velocityjitter 8 8 16 +velocitymultiplier 0 +airfriction -0.5 +rotate 180 360 -30 30 +// plasma smoke +effect weapondamage_electro +count 4 +type smoke +tex 0 8 +color 0x2244ff 0x002266 +size 8 16 +sizeincrease 10 +alpha 64 16 64 +gravity 0 +originjitter 4 4 16 +velocityjitter 0.4 0.4 0.6 +velocitymultiplier 0 +airfriction -0.35 +rotate 0 180 -30 30 +// light +effect weapondamage_electro +trailspacing 8 +lightradius 50 +lightradiusfade 220 +lightcolor 0.2 0.8 1.0 + +// crylink damage effect +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_crylink +count 2 +type static +tex 38 38 +color 0xff44ff 0x9966ff +size 8 16 +sizeincrease -8 +alpha 48 16 48 +gravity -0.0001 +airfriction 0.6 +liquidfriction 0.8 +originjitter 8 8 16 +velocityjitter 10 10 20 +velocitymultiplier 0 +airfriction -0.5 +rotate 180 360 -30 30 +// plasma smoke +effect weapondamage_crylink +count 4 +type smoke +tex 0 8 +color 0x8844ff 0x662244 +size 10 20 +sizeincrease 6 +alpha 64 16 64 +gravity 0.001 +originjitter 6 6 12 +velocityjitter 0.4 0.4 0.6 +velocitymultiplier 0 +airfriction -0.35 +rotate 0 180 -30 30 +// light +effect weapondamage_crylink +trailspacing 8 +lightradius 50 +lightradiusfade 240 +lightcolor 0.8 0.2 1.0 + +// hlac damage effect +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_hlac +count 3 +type smoke +tex 0 8 +color 0x880000 0xff4400 +size 8 16 +sizeincrease 10 +alpha 128 16 128 +gravity 0 +originjitter 4 4 16 +velocityjitter 0.4 0.4 0.6 +velocitymultiplier 0 +airfriction -0.35 +rotate 0 180 -30 30 + +// nex damage effect +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_nex +count 1 +type static +tex 47 47 +color 0xffffff 0x88ffff +size 7 14 +sizeincrease -14 +alpha 64 8 64 +gravity -0.0001 +airfriction 0.1 +liquidfriction 0.6 +originjitter 4 4 8 +velocityjitter 8 8 16 +velocitymultiplier 0 +airfriction -0.5 +rotate 180 360 -30 30 +// plasma smoke +effect weapondamage_nex +count 2 +type smoke +tex 0 8 +color 0x6688ff 0x226688 +size 5 10 +sizeincrease 8 +alpha 64 16 64 +gravity 0 +originjitter 6 6 12 +velocityjitter 0.5 0.5 0.8 +velocitymultiplier 0 +airfriction -0.35 +rotate 0 180 -30 30 +// light +effect weapondamage_nex +trailspacing 8 +lightradius 60 +lightradiusfade 280 +lightcolor 0.8 1.0 1.0 + +// minstanex damage effect +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_minstanex +count 2 +type static +tex 47 47 +color 0xffffff 0x88ffff +size 10 20 +sizeincrease -14 +alpha 64 8 64 +gravity -0.0001 +airfriction 0.1 +liquidfriction 0.6 +originjitter 4 4 8 +velocityjitter 8 8 16 +velocitymultiplier 0 +airfriction -0.5 +rotate 180 360 -30 30 +// plasma smoke +effect weapondamage_minstanex +count 4 +type smoke +tex 0 8 +color 0x6688ff 0x226688 +size 8 16 +sizeincrease 8 +alpha 64 16 64 +gravity 0 +originjitter 6 6 12 +velocityjitter 0.5 0.5 0.8 +velocitymultiplier 0 +airfriction -0.35 +rotate 0 180 -30 30 +// light +effect weapondamage_minstanex +trailspacing 8 +lightradius 60 +lightradiusfade 240 +lightcolor 0.8 1.0 1.0 + +// sniperrifle damage effect, normal blood +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_sniperrifle +count 0.25 +type blood +tex 24 32 +size 3 8 +alpha 256 256 64 +color 0xA8FFFF 0xA8FFFFF +bounce -1 +airfriction 1 +liquidfriction 4 +velocityjitter 64 64 64 +velocitymultiplier 5 +staincolor 0x808080 0x808080 +staintex 16 24 +//blood mist +effect weapondamage_sniperrifle +countabsolute 1 +type alphastatic +tex 0 8 +size 6 12 +alpha 100 256 400 +color 0x000000 0x420000 +originjitter 11 11 11 + +// sniperrifle damage effect, alien blood +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_sniperrifle_alien +count 0.25 +type blood +tex 24 32 +size 3 8 +alpha 256 256 64 +color 0xDC9BCD 0xDC9BCD +bounce -1 +airfriction 1 +liquidfriction 4 +velocityjitter 64 64 64 +velocitymultiplier 5 +staincolor 0x808080 0x808080 +staintex 16 24 +//blood mist +effect weapondamage_sniperrifle_alien +countabsolute 1 +type alphastatic +tex 0 8 +size 6 12 +alpha 100 256 400 +color 0x000000 0x204010 +originjitter 11 11 11 + +// sniperrifle damage effect, robot blood +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_sniperrifle_robot +count 0.25 +type blood +tex 24 32 +size 3 8 +alpha 256 256 64 +color 0xC0D890 0xC0D890 +bounce -1 +airfriction 1 +liquidfriction 4 +velocityjitter 64 64 64 +velocitymultiplier 5 +staincolor 0x808080 0x808080 +staintex 16 24 +//blood mist +effect weapondamage_sniperrifle_robot +countabsolute 1 +type alphastatic +tex 0 8 +size 6 12 +alpha 100 256 400 +color 0x000000 0x301860 +originjitter 11 11 11 + +// seeker damage effect +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_seeker +//notunderwater +count 2 +type smoke +tex 48 55 +size 5 10 +alpha 256 16 256 +gravity -0.5 +color 0x8f0d00 0xff5a00 +sizeincrease -10 +originoffset 0 0 10 +originjitter 5 5 7 +velocityjitter 22 22 50 +// smoke +effect weapondamage_seeker +type alphastatic +count 2 +tex 0 8 +size 3 6 +sizeincrease 5 +alpha 128 32 128 +color 0x000000 0x111111 +gravity -0.3 +originoffset 0 0 10 +originjitter 5 5 7 +velocityjitter 11 11 50 +// light +effect weapondamage_seeker +trailspacing 8 +lightradius 65 +lightradiusfade 280 +lightcolor 0.9 0.7 0.2 + +// hagar damage effect +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_hagar +//notunderwater +count 2 +type smoke +tex 48 55 +size 5 10 +alpha 256 16 256 +gravity -0.5 +color 0x8f0d00 0xff5a00 +sizeincrease -10 +originoffset 0 0 10 +originjitter 5 5 7 +velocityjitter 22 22 50 +// smoke +effect weapondamage_hagar +type alphastatic +count 2 +tex 0 8 +size 3 6 +sizeincrease 5 +alpha 128 32 128 +color 0x000000 0x111111 +gravity -0.3 +originoffset 0 0 10 +originjitter 5 5 7 +velocityjitter 11 11 50 +// light +effect weapondamage_hagar +trailspacing 8 +lightradius 65 +lightradiusfade 280 +lightcolor 0.9 0.7 0.2 + +// fireball damage effect +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_fireball +//notunderwater +count 4 +type smoke +tex 48 55 +size 10 20 +alpha 192 16 192 +gravity -0.5 +color 0x8f0d00 0xff5a00 +sizeincrease -10 +originoffset 0 0 10 +originjitter 8 8 24 +velocityjitter 22 22 50 +// smoke +effect weapondamage_fireball +type alphastatic +count 4 +tex 0 8 +size 8 16 +sizeincrease 5 +alpha 128 32 128 +color 0x000000 0x111111 +gravity -0.3 +originoffset 0 0 10 +originjitter 8 8 24 +velocityjitter 11 11 50 +// light +effect weapondamage_fireball +trailspacing 8 +lightradius 65 +lightradiusfade 280 +lightcolor 0.9 0.6 0.2 + +// rocketlauncher damage effect +// used in qcsrc/client/gibs.qc: pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +effect weapondamage_rocketlauncher +//notunderwater +count 3 +type smoke +tex 48 55 +size 7 14 +alpha 256 16 256 +gravity -0.5 +color 0x8f0d00 0xff5a00 +sizeincrease -10 +originoffset 0 0 10 +originjitter 6 6 8 +velocityjitter 22 22 50 +// smoke +effect weapondamage_rocketlauncher +type alphastatic +count 3 +tex 0 8 +size 5 10 +sizeincrease 5 +alpha 128 32 128 +color 0x000000 0x111111 +gravity -0.3 +originoffset 0 0 10 +originjitter 6 6 8 +velocityjitter 11 11 50 +// light +effect weapondamage_rocketlauncher +trailspacing 8 +lightradius 60 +lightradiusfade 280 +lightcolor 0.9 0.6 0.2 + +// porto does not use the weapon damage effect + +// hook does not use the weapon damage effect diff --git a/qcsrc/client/Main.qc b/qcsrc/client/Main.qc index f5dfec4e4a..0c7643d0ef 100644 --- a/qcsrc/client/Main.qc +++ b/qcsrc/client/Main.qc @@ -1000,6 +1000,7 @@ void(float bIsNewEntity) CSQC_Ent_Update = case ENT_CLIENT_ACCURACY: Ent_ReadAccuracy(); break; case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break; case ENT_CLIENT_TURRET: ent_turret(); break; + case ENT_CLIENT_DAMAGEEFFECT: Ent_DamageEffect(); break; default: //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype)); error(sprintf(_("Unknown entity type in CSQC_Ent_Update (enttype: %d, edict: %d, classname: %s)\n"), self.enttype, num_for_edict(self), self.classname)); diff --git a/qcsrc/client/autocvars.qh b/qcsrc/client/autocvars.qh index 2f2b80cc59..10fee18945 100644 --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@ -362,3 +362,5 @@ var float autocvar_cl_eventchase_distance = 140; var float autocvar_cl_eventchase_speed = 1.3; float autocvar_cl_lerpexcess; string autocvar__togglezoom; +float autocvar_cl_damageeffect; +float autocvar_cl_damageeffect_gibs; diff --git a/qcsrc/client/gibs.qc b/qcsrc/client/gibs.qc index 409f809426..78aee37752 100644 --- a/qcsrc/client/gibs.qc +++ b/qcsrc/client/gibs.qc @@ -103,17 +103,19 @@ void Gib_Draw() } } -void TossGib (string mdlname, vector safeorg, vector org, vector vconst, vector vrand, float specnum, float destroyontouch, float issilent) +void TossGib (string mdlname, vector safeorg, vector org, vector vconst, vector vrand, float specnum, float destroyontouch, float issilent, float gibownernum) { entity gib; // TODO remove some gibs according to cl_nogibs gib = RubbleNew("gib"); + gib.classname = "gib"; gib.move_movetype = MOVETYPE_BOUNCE; gib.gravity = 1; gib.solid = SOLID_CORPSE; gib.cnt = specnum; gib.silent = issilent; + gib.team = gibownernum; Gib_setmodel(gib, mdlname, specnum); setsize (gib, '-8 -8 -8', '8 8 8'); @@ -145,7 +147,7 @@ void TossGib (string mdlname, vector safeorg, vector org, vector vconst, vector void Ent_GibSplash(float isNew) { - float amount, type, specnum; + float amount, type, specnum, entnumber; vector org, vel; string specstr; float issilent; @@ -155,6 +157,7 @@ void Ent_GibSplash(float isNew) type = ReadByte(); // gibbage type amount = ReadByte() / 16.0; // gibbage amount + entnumber = ReadByte(); // player num org_x = ReadShort() * 4 + 2; org_y = ReadShort() * 4 + 2; org_z = ReadShort() * 4 + 2; @@ -202,37 +205,37 @@ void Ent_GibSplash(float isNew) sound (self, CH_PAIN, "misc/gib.wav", VOL_BASE, ATTN_NORM); if(prandom() < amount) - TossGib ("models/gibs/eye.md3", org, org, vel, prandomvec() * 150, specnum, 0, issilent); + TossGib ("models/gibs/eye.md3", org, org, vel, prandomvec() * 150, specnum, 0, issilent, entnumber); new_te_bloodshower(particleeffectnum(strcat(specstr, "bloodshower")), org, 1200, amount); if(prandom() < amount) - TossGib ("models/gibs/bloodyskull.md3", org, org + 16 * prandomvec(), vel, prandomvec() * 100, specnum, 0, issilent); + TossGib ("models/gibs/bloodyskull.md3", org, org + 16 * prandomvec(), vel, prandomvec() * 100, specnum, 0, issilent, entnumber); for(c = 0; c < amount; ++c) { randomvalue = amount - c; if(prandom() < randomvalue) - TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent); + TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent, entnumber); if(prandom() < randomvalue) - TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent); + TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent, entnumber); if(prandom() < randomvalue) - TossGib ("models/gibs/chest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent); + TossGib ("models/gibs/chest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent, entnumber); if(prandom() < randomvalue) - TossGib ("models/gibs/smallchest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent); + TossGib ("models/gibs/smallchest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent, entnumber); if(prandom() < randomvalue) - TossGib ("models/gibs/leg1.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent); + TossGib ("models/gibs/leg1.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent, entnumber); if(prandom() < randomvalue) - TossGib ("models/gibs/leg2.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent); + TossGib ("models/gibs/leg2.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent, entnumber); // these splat on impact if(prandom() < randomvalue) - TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent); + TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent, entnumber); if(prandom() < randomvalue) - TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent); + TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent, entnumber); if(prandom() < randomvalue) - TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent); + TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent, entnumber); if(prandom() < randomvalue) - TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent); + TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent, entnumber); } break; case 0x02: @@ -240,7 +243,7 @@ void Ent_GibSplash(float isNew) break; case 0x03: if(prandom() < amount) - TossGib ("models/gibs/chunk.mdl", org, org, vel, prandomvec() * (prandom() * 30 + 20), specnum, 1, issilent); // TODO maybe adjust to more randomization? + TossGib ("models/gibs/chunk.mdl", org, org, vel, prandomvec() * (prandom() * 30 + 20), specnum, 1, issilent, entnumber); // TODO maybe adjust to more randomization? break; case 0x81: pointparticles(particleeffectnum(strcat(gentle_prefix, "damage_dissolve")), org, vel, amount); @@ -281,3 +284,63 @@ void GibSplash_Precache() precache_sound ("misc/gib_splat03.wav"); precache_sound ("misc/gib_splat04.wav"); } + +void Ent_DamageEffect() +{ + float type, specnum1, specnum2, entnumber, body; + vector org; + string specstr, effectnum; + entity e; + + type = ReadByte(); // damage weapon + specnum1 = ReadByte(); // player species + entnumber = ReadByte(); // player entnum + body = ReadByte(); // is dead body / gibbed + org_x = ReadCoord(); + org_y = ReadCoord(); + org_z = ReadCoord(); + + if not(autocvar_cl_damageeffect) + return; + if(autocvar_cl_gentle || autocvar_cl_gentle_damage) + return; + + e = get_weaponinfo(type); + + specnum2 = (specnum1 & 0x78) / 8; // blood type: using four bits (0..7, bit indexes 3,4,5) + specstr = species_prefix(specnum2); + + effectnum = strcat("weapondamage_", e.netname); + // If the weapon is a bullet weapon, its damage effect is blood. + // Since blood is species dependent, we make this effect per-species. + if(type == WEP_SHOTGUN || type == WEP_UZI || type == WEP_RIFLE) + if(specstr != "") + { + effectnum = strcat(effectnum, "_", specstr); + effectnum = substring(effectnum, 0, strlen(effectnum) - 1); // remove the _ symbol at the end of the species name + } + + entity head; + + // Scan the owner of all gibs in the world. If a gib owner is the same as the player we're applying the + // effect to, it means our player is gibbed. Therefore, apply the particles to the gibs as well. + if(autocvar_cl_damageeffect_gibs && body > 1) + for(head = world; (head = find(head, classname, "gib")); ) + { + if(head.team == entnumber) + if(random() < autocvar_cl_damageeffect_gibs) + pointparticles(particleeffectnum(effectnum), head.origin, '0 0 0', 1); + } + + // if we aren't in third person mode, hide our own damage effect + if(entnumber == player_localentnum && !body) + if(!autocvar_chase_active) + return; + // if this is a gibbed dead body, don't apply the effects to it, only the gibs as done above + if(body > 1) + return; + + // Now apply the effect to the actual player. + if(random() < autocvar_cl_damageeffect) + pointparticles(particleeffectnum(effectnum), org, '0 0 0', 1); +} diff --git a/qcsrc/common/constants.qh b/qcsrc/common/constants.qh index 9180b66832..634ab397bd 100644 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@ -116,6 +116,7 @@ const float ENT_CLIENT_GAUNTLET = 29; const float ENT_CLIENT_ACCURACY = 30; const float ENT_CLIENT_SHOWNAMES = 31; const float ENT_CLIENT_WARPZONE_TELEPORTED = 32; +const float ENT_CLIENT_DAMAGEEFFECT = 33; const float ENT_CLIENT_TURRET = 40; const float ENT_CLIENT_AUXILIARYXHAIR = 50; diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index ff99823330..401dd07979 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -1170,6 +1170,9 @@ float autocvar_sv_warsowbunny_topspeed; float autocvar_sv_warsowbunny_turnaccel; string autocvar_sv_weaponstats_file; float autocvar_sv_gibhealth; +float autocvar_sv_damageeffect_tick; +float autocvar_sv_damageeffect_lifetime; +float autocvar_sv_damageeffect_lifetime_max; float autocvar_sys_ticrate; float autocvar_teamplay_lockonrestart; float autocvar_teamplay_mode; diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index f3d34bb475..61884b8780 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -887,6 +887,8 @@ void PutClientInServer (void) RemoveGrapplingHook(self); // Wazat's Grappling Hook + Violence_DamageEffect_Remove(self); + self.classname = "player"; self.wasplayer = TRUE; self.iscreature = TRUE; @@ -1951,6 +1953,7 @@ void respawn(void) pointparticles(particleeffectnum("respawn_ghost"), self.origin, '0 0 0', 1); if(autocvar_g_respawn_ghosts_maxtime) SUB_SetFade (self, time + autocvar_g_respawn_ghosts_maxtime / 2 + random () * (autocvar_g_respawn_ghosts_maxtime - autocvar_g_respawn_ghosts_maxtime / 2), 1.5); + Violence_DamageEffect_Remove(self); } CopyBody(1); diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index 63ba50d5ba..4b8dc143f6 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -180,6 +180,9 @@ void CopyBody(float keepvelocity) Drag_MoveDrag(oldself, self); + Violence_DamageEffect_Copy(oldself, self); + + self.owner = oldself; self = oldself; } @@ -405,6 +408,7 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float Violence_GibSplash(self, 1, 1, attacker); self.modelindex = 0; // restore later self.solid = SOLID_NOT; // restore later + self.takedamage = DAMAGE_NO; // restore later } } diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index d5ef02034c..d66a2187d9 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -492,6 +492,8 @@ float GetPlayerSoundSampleField_notFound; .float cvar_cl_voice_directional; .float cvar_cl_voice_directional_taunt_attenuation; +.float cvar_cl_damageeffect; + .float version_mismatch; float independent_players; diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index d6020bd349..efdd9ed1cf 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -493,6 +493,10 @@ entity damage_attacker; void Damage (entity targ, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { + // if the target is a player or dead body, activate damage effects + if(targ.classname == "player" || targ.classname == "body") + Violence_DamageEffect_SetRepeat(targ, damage, DEATH_WEAPONOF(deathtype)); + float mirrordamage; float mirrorforce; float teamdamage0; diff --git a/qcsrc/server/g_violence.qc b/qcsrc/server/g_violence.qc index f5def6a7dd..1c3c8d04ec 100644 --- a/qcsrc/server/g_violence.qc +++ b/qcsrc/server/g_violence.qc @@ -3,6 +3,7 @@ float Violence_GibSplash_SendEntity(entity to, float sf) WriteByte(MSG_ENTITY, ENT_CLIENT_GIBSPLASH); WriteByte(MSG_ENTITY, self.state); // actually type WriteByte(MSG_ENTITY, bound(1, self.cnt * 16, 255)); // gibbage amount multiplier + WriteByte(MSG_ENTITY, self.team); // player num 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 @@ -25,6 +26,13 @@ void Violence_GibSplash_At(vector org, vector dir, float type, float amount, ent if(!sound_allowed(MSG_BROADCAST, gibowner) || !sound_allowed(MSG_BROADCAST, attacker)) e.state |= 0x40; // "silence" bit e.state |= 8 * self.species; // gib type, ranges from 0 to 15 + + // if this is a copied dead body, send the num of its player instead + if(self.classname == "body") + e.team = num_for_edict(self.owner); + else + e.team = num_for_edict(self); + setorigin(e, org); e.velocity = dir; @@ -37,3 +45,118 @@ void Violence_GibSplash(entity source, float type, float amount, entity attacker { Violence_GibSplash_At(source.origin + source.view_ofs, source.velocity, type, amount, source, attacker); } + +// damage effect + +.float damageeffect_lifetime; +.entity damageeffect_repeater; + +float Violence_DamageEffect_SendEntity(entity to, float sf) +{ + // if the client doesn't have the effect enabled, don't send to him and waste bandwidth + if not(to.cvar_cl_damageeffect) + return FALSE; + // if the client cannot see the damaged player, avoid sending and further save bandwidth + if not(checkpvs(to.origin + to.view_ofs, self)) + return FALSE; + + WriteByte(MSG_ENTITY, ENT_CLIENT_DAMAGEEFFECT); + WriteByte(MSG_ENTITY, self.cnt); // damage weapon + WriteByte(MSG_ENTITY, self.state); // player species + WriteByte(MSG_ENTITY, self.team); // player entnum + WriteByte(MSG_ENTITY, self.deadflag); // is dead body / gibbed + WriteCoord(MSG_ENTITY, floor(self.origin_x)); + WriteCoord(MSG_ENTITY, floor(self.origin_y)); + WriteCoord(MSG_ENTITY, floor(self.origin_z)); + return TRUE; +} + +void Violence_DamageEffect(entity pl, float type) +{ + entity e; + + e = spawn(); + e.classname = "damageeffect"; + e.cnt = type; + e.state |= 8 * pl.species; // gib type, ranges from 0 to 15 + + // if this is a copied dead body, send the num of its player instead + if(pl.classname == "body") + e.team = num_for_edict(pl.owner); + else + e.team = num_for_edict(pl); + + // is this a whole dead body, or a gibbed body / player? + if(!pl.modelindex) // gibbed + e.deadflag = 2; + else if(pl.classname == "body") + e.deadflag = 1; + + // if the player is dead, show the effect lower, else it appears floating above the body + if(pl.health <= 0) + setorigin(e, pl.origin - '0 0 25'); + else + setorigin(e, pl.origin); + + Net_LinkEntity(e, FALSE, 0.2, Violence_DamageEffect_SendEntity); +} + +void Violence_DamageEffect_Remove(entity pl); +void Violence_DamageEffect_DoRepeat() +{ + if(time > self.damageeffect_lifetime || (self.owner.classname != "player" && self.owner.classname != "body")) + { + Violence_DamageEffect_Remove(self.owner); + return; + } + + Violence_DamageEffect(self.owner, self.cnt); + self.nextthink = time + autocvar_sv_damageeffect_tick; +} + +void Violence_DamageEffect_SetRepeat(entity pl, float damage, float type) +{ + if not(autocvar_sv_damageeffect_tick && autocvar_sv_damageeffect_lifetime) + return; + if(sv_gentle || !type) + return; // return if gentle mode is enabled or the damage was not caused by a weapon + + // if a repeater doesn't exist, spawn one, else update the existing one + if(pl.damageeffect_repeater == world) + { + pl.damageeffect_repeater = spawn(); + pl.damageeffect_repeater.classname = "damageeffect_repeater"; + pl.damageeffect_repeater.owner = pl; + pl.damageeffect_repeater.think = Violence_DamageEffect_DoRepeat; + + pl.damageeffect_repeater.damageeffect_lifetime = time + (autocvar_sv_damageeffect_lifetime * damage); + } + else + { + // if the repeater is being updated, increase its lifetime instead of re-setting it entirely + // this fixes the shotgun among other things, where only the damage of one bullet would be taken into account + pl.damageeffect_repeater.damageeffect_lifetime += (autocvar_sv_damageeffect_lifetime * damage); + } + + if(autocvar_sv_damageeffect_lifetime_max) + pl.damageeffect_repeater.damageeffect_lifetime = bound(0, pl.damageeffect_repeater.damageeffect_lifetime, time + autocvar_sv_damageeffect_lifetime_max); + + pl.damageeffect_repeater.cnt = type; + pl.damageeffect_repeater.nextthink = time; +} + +void Violence_DamageEffect_Remove(entity pl) +{ + pl.damageeffect_repeater.nextthink = 0; + remove(pl.damageeffect_repeater); + pl.damageeffect_repeater = world; +} + +void Violence_DamageEffect_Copy(entity old_pl, entity pl) +{ + if(pl.damageeffect_repeater != world) + Violence_DamageEffect_Remove(pl); + + Violence_DamageEffect_SetRepeat(pl, 0, old_pl.damageeffect_repeater.cnt); // spawn a new repeater + pl.damageeffect_repeater.damageeffect_lifetime = old_pl.damageeffect_repeater.damageeffect_lifetime; // copy the lifetime +} diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index 0dca3ab282..c490881566 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -600,6 +600,7 @@ void GetCvars(float f) GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete); GetCvars_handleFloat(s, f, cvar_cl_weaponimpulsemode, "cl_weaponimpulsemode"); GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt"); + GetCvars_handleFloat(s, f, cvar_cl_damageeffect, "cl_damageeffect"); GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag"); GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional"); GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");