From 35be0b101cb599dfaff692128abc5355ee267734 Mon Sep 17 00:00:00 2001 From: TimePath Date: Sun, 23 Aug 2015 13:18:05 +1000 Subject: [PATCH] Damage text --- qcsrc/client/main.qc | 54 +++++-------- qcsrc/client/mutators/events.qh | 11 +++ qcsrc/client/progs.src | 2 + qcsrc/common/constants.qh | 8 ++ qcsrc/common/mutators/all.inc | 1 + qcsrc/common/mutators/all.qc | 1 + qcsrc/common/mutators/events.qh | 20 +++++ qcsrc/common/mutators/mutator/damagetext.qc | 87 +++++++++++++++++++++ qcsrc/server/cl_player.qc | 1 + qcsrc/server/mutators/events.qh | 12 +++ qcsrc/server/progs.src | 1 + 11 files changed, 165 insertions(+), 33 deletions(-) create mode 100644 qcsrc/common/mutators/all.inc create mode 100644 qcsrc/common/mutators/all.qc create mode 100644 qcsrc/common/mutators/mutator/damagetext.qc diff --git a/qcsrc/client/main.qc b/qcsrc/client/main.qc index 12157531d..a585a136e 100644 --- a/qcsrc/client/main.qc +++ b/qcsrc/client/main.qc @@ -29,6 +29,8 @@ #include "../common/vehicles/cl_vehicles.qh" #include "../common/vehicles/vehicles.qh" +#include "mutators/events.qh" + #include "weapons/projectile.qh" #include "../common/buffs.qh" @@ -1259,69 +1261,55 @@ void Net_WeaponComplain() // Return value should be 1 if CSQC handled the temporary entity, otherwise return 0 to have the engine process the event. float CSQC_Parse_TempEntity() { - float bHandled; - bHandled = true; // Acquire TE ID - float nTEID; - nTEID = ReadByte(); + int nTEID = ReadByte(); - if(autocvar_developer_csqcentities) + if (autocvar_developer_csqcentities) printf("CSQC_Parse_TempEntity() with nTEID=%d\n", nTEID); - // NOTE: Could just do return instead of break... - switch(nTEID) + switch (nTEID) { + case TE_CSQC_MUTATOR: + int mutID = ReadMutator(); + if (MUTATOR_CALLHOOK(CSQC_Parse_TempEntity, mutID)) + return true; case TE_CSQC_TARGET_MUSIC: Net_TargetMusic(); - bHandled = true; - break; + return true; case TE_CSQC_PICTURE: Net_MapVote_Picture(); - bHandled = true; - break; + return true; case TE_CSQC_RACE: Net_ReadRace(); - bHandled = true; - break; + return true; case TE_CSQC_VORTEXBEAMPARTICLE: Net_ReadVortexBeamParticle(); - bHandled = true; - break; + return true; case TE_CSQC_TEAMNAGGER: Net_TeamNagger(); - bHandled = true; - break; + return true; case TE_CSQC_ARC: Net_ReadArc(); - bHandled = true; - break; + return true; case TE_CSQC_PINGPLREPORT: Net_ReadPingPLReport(); - bHandled = true; - break; + return true; case TE_CSQC_WEAPONCOMPLAIN: Net_WeaponComplain(); - bHandled = true; - break; + return true; case TE_CSQC_VEHICLESETUP: Net_VehicleSetup(); - bHandled = true; - break; + return true; case TE_CSQC_SVNOTICE: cl_notice_read(); - bHandled = true; - break; + return true; case TE_CSQC_SHOCKWAVEPARTICLE: Net_ReadShockwaveParticle(); - bHandled = true; - break; + return true; default: // No special logic for this temporary entity; return 0 so the engine can handle it - bHandled = false; - break; + return false; } - - return bHandled; } string getcommandkey(string text, string command) diff --git a/qcsrc/client/mutators/events.qh b/qcsrc/client/mutators/events.qh index 41177cb66..8f317c8e8 100644 --- a/qcsrc/client/mutators/events.qh +++ b/qcsrc/client/mutators/events.qh @@ -38,4 +38,15 @@ MUTATOR_HOOKABLE(CSQC_ConsoleCommand, EV_CSQC_ConsoleCommand); /* Called when the crosshair is being updated */ MUTATOR_HOOKABLE(UpdateCrosshair, EV_NO_ARGS); +/** + * Called when a temp entity is parsed + * NOTE: hooks MUST start with `if (MUTATOR_RETURNVALUE) return false;` + * NOTE: hooks MUST start with `if (!ReadMutatorEquals(mutator_argv_int_0, name_of_mutator)) return false;` + * NOTE: return true if you handled the command, return false to continue handling + */ +#define EV_CSQC_Parse_TempEntity(i, o) \ + /** entity id */ i(int, mutator_argv_int_0) \ + /**/ +MUTATOR_HOOKABLE(CSQC_Parse_TempEntity, EV_CSQC_Parse_TempEntity); + #endif diff --git a/qcsrc/client/progs.src b/qcsrc/client/progs.src index ea61aed0d..43c056aa3 100644 --- a/qcsrc/client/progs.src +++ b/qcsrc/client/progs.src @@ -60,6 +60,8 @@ weapons/projectile.qc // TODO ../common/monsters/all.qc +../common/mutators/all.qc + ../common/weapons/all.qc // TODO ../common/triggers/include.qc diff --git a/qcsrc/common/constants.qh b/qcsrc/common/constants.qh index 1953b1f33..1498e465e 100644 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@ -31,6 +31,14 @@ const int AS_INT = 2; const int AS_FLOAT_TRUNCATED = 2; const int AS_FLOAT = 8; +const int TE_CSQC_MUTATOR = 99; +#define MUTATOR_HASH(s) crc16(true, s) +#define WriteMutator(to, s) do { \ + WriteByte(to, TE_CSQC_MUTATOR); \ + WriteLong(to, MUTATOR_HASH(#s)); \ +} while (0) +#define ReadMutator() ReadLong() +#define ReadMutatorEquals(read, s) (read == MUTATOR_HASH(#s)) const int TE_CSQC_PICTURE = 100; const int TE_CSQC_RACE = 101; const int TE_CSQC_VORTEXBEAMPARTICLE = 103; diff --git a/qcsrc/common/mutators/all.inc b/qcsrc/common/mutators/all.inc new file mode 100644 index 000000000..4cb1a6cea --- /dev/null +++ b/qcsrc/common/mutators/all.inc @@ -0,0 +1 @@ +#include "mutator/damagetext.qc" diff --git a/qcsrc/common/mutators/all.qc b/qcsrc/common/mutators/all.qc new file mode 100644 index 000000000..14530a3c5 --- /dev/null +++ b/qcsrc/common/mutators/all.qc @@ -0,0 +1 @@ +#include "all.inc" diff --git a/qcsrc/common/mutators/events.qh b/qcsrc/common/mutators/events.qh index e193d5f8a..eb46486b6 100644 --- a/qcsrc/common/mutators/events.qh +++ b/qcsrc/common/mutators/events.qh @@ -3,8 +3,28 @@ #define EV_NO_ARGS(i, o) +#pragma noref 1 string ret_string; +#define MUTATOR_TYPES(_, x) \ + _(x, bool) \ + _(x, int) \ + _(x, entity) \ + _(x, float) \ + _(x, vector) \ + _(x, string) \ + /**/ + +#define MUTATOR_NEWGLOBAL(x, type) type mutator_argv_##type##_##x; + +MUTATOR_TYPES(MUTATOR_NEWGLOBAL, 0) +MUTATOR_TYPES(MUTATOR_NEWGLOBAL, 1) + +#undef MUTATOR_TYPES +#undef MUTATOR_NEWGLOBAL + +#pragma noref 0 + /** appends ":mutatorname" to ret_string for logging */ #define EV_BuildMutatorsString(i, o) \ /**/ i(string, ret_string) \ diff --git a/qcsrc/common/mutators/mutator/damagetext.qc b/qcsrc/common/mutators/mutator/damagetext.qc new file mode 100644 index 000000000..43c4f6063 --- /dev/null +++ b/qcsrc/common/mutators/mutator/damagetext.qc @@ -0,0 +1,87 @@ +REGISTER_MUTATOR(damagetext, true); + +#ifdef CSQC +vector autocvar_cl_damagetext_color = '1 1 0'; +float autocvar_cl_damagetext_size = 8; +float autocvar_cl_damagetext_alpha_start = 1; +float autocvar_cl_damagetext_alpha_lifetime = 3; +vector autocvar_cl_damagetext_velocity = '0 0 20'; +vector autocvar_cl_damagetext_offset = '0 -40 0'; +float autocvar_cl_damagetext_accumulate_range = 300; + +CLASS(DamageText, Object) + ATTRIB(DamageText, m_color, vector, autocvar_cl_damagetext_color) + ATTRIB(DamageText, m_size, float, autocvar_cl_damagetext_size) + ATTRIB(DamageText, alpha, float, autocvar_cl_damagetext_alpha_start) + ATTRIB(DamageText, fade_rate, float, 1 / autocvar_cl_damagetext_alpha_lifetime) + ATTRIB(DamageText, velocity, vector, autocvar_cl_damagetext_velocity) + ATTRIB(DamageText, m_damage, int, 0) + ATTRIB(DamageText, m_armordamage, int, 0) + ATTRIB(DamageText, time_prev, float, time) + + void DamageText_draw() { + entity this = self; + float dt = time - this.time_prev; + this.time_prev = time; + setorigin(this, this.origin + dt * this.velocity); + this.alpha -= dt * this.fade_rate; + if (this.alpha < 0) remove(this); + vector pos = project_3d_to_2d(this.origin) + autocvar_cl_damagetext_offset; + if (pos.z >= 0 && this.m_size > 0) { + pos.z = 0; + string s = sprintf("-%d", this.m_damage + this.m_armordamage); + drawstring(pos, s, this.m_size * '1 1 0', this.m_color, this.alpha, DRAWFLAG_NORMAL); + } + } + ATTRIB(DamageText, draw2d, void(), DamageText_draw) + + void DamageText_update(DamageText this, vector _origin, int _health, int _armor) { + this.m_damage = _health; + this.m_armordamage = _armor; + setorigin(this, _origin); + this.alpha = 1; + } + + CONSTRUCTOR(DamageText, vector _origin, int _health, int _armor) { + CONSTRUCT(DamageText); + DamageText_update(this, _origin, _health, _armor); + return this; + } +ENDCLASS(DamageText) +#endif + +#ifdef SVQC +MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) { + const entity me = mutator_argv_entity_0; if (!IS_REAL_CLIENT(me)) return; + const entity hit = mutator_argv_entity_1; if (hit == me) return; + const int health = mutator_argv_int_0; + const int armor = mutator_argv_int_1; + const vector location = hit.origin; + msg_entity = me; + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteMutator(MSG_ONE, damagetext); + WriteShort(MSG_ONE, health); + WriteShort(MSG_ONE, armor); + WriteCoord(MSG_ONE, location.x); + WriteCoord(MSG_ONE, location.y); + WriteCoord(MSG_ONE, location.z); +} +#endif + +#ifdef CSQC +MUTATOR_HOOKFUNCTION(damagetext, CSQC_Parse_TempEntity) { + if (MUTATOR_RETURNVALUE) return false; + if (!ReadMutatorEquals(mutator_argv_int_0, damagetext)) return false; + int health = ReadShort(); + int armor = ReadShort(); + vector location = vec3(ReadCoord(), ReadCoord(), ReadCoord()); + for (entity e = findradius(location, autocvar_cl_damagetext_accumulate_range); e; e = e.chain) { + if (e.instanceOfDamageText) { + DamageText_update(e, location, e.m_damage + health, e.m_armordamage + armor); + return true; + } + } + NEW(DamageText, location, health, armor); + return true; +} +#endif diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index 9bc36c8df..e3bb91e39 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -492,6 +492,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, int deathtyp dh = dh - max(self.health, 0); da = da - max(self.armorvalue, 0); WeaponStats_LogDamage(awep, abot, self.weapon, vbot, dh + da); + MUTATOR_CALLHOOK(PlayerDamaged, attacker, self, dh, da, hitloc); } if (self.health < 1) diff --git a/qcsrc/server/mutators/events.qh b/qcsrc/server/mutators/events.qh index 88c58f309..ec9e9c99a 100644 --- a/qcsrc/server/mutators/events.qh +++ b/qcsrc/server/mutators/events.qh @@ -260,6 +260,18 @@ float frag_mirrordamage; vector frag_force; MUTATOR_HOOKABLE(PlayerDamage_Calculate, EV_PlayerDamage_Calculate); +/** + * Called when a player is damaged + */ +#define EV_PlayerDamaged(i, o) \ + /** attacker */ i(entity, mutator_argv_entity_0) \ + /** target */ i(entity, mutator_argv_entity_1) \ + /** health */ i(int, mutator_argv_int_0) \ + /** armor */ i(int, mutator_argv_int_1) \ + /** location */ i(vector, mutator_argv_vector_0) \ + /**/ +MUTATOR_HOOKABLE(PlayerDamaged, EV_PlayerDamaged); + /** called at the end of player_powerups() in cl_client.qc, used for manipulating the values which are set by powerup items. */ #define EV_PlayerPowerups(i, o) \ /**/ i(entity, self) \ diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index 2ed1e03d6..bb6288101 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -88,6 +88,7 @@ weapons/weaponsystem.qc ../common/effects.qc ../common/mapinfo.qc ../common/monsters/all.qc +../common/mutators/all.qc ../common/monsters/spawn.qc ../common/monsters/sv_monsters.qc ../common/movetypes/include.qc -- 2.39.2