diff --git a/README.md b/README.md index 7b60cf7d..5ab773d4 100644 --- a/README.md +++ b/README.md @@ -66,10 +66,10 @@ New features * Option for hitsounds (1 - enemies only, 2 - enemies and teammates). `setinfo hitsound 2` * Option for medic to be immune from concussion effects. `localinfo medicnocuss on`. * Option to adjust concussion grenade effect time in seconds. `localinfo cussgrentime n`. +* Option to adjust blast grenade effect time in seconds. `localinfo blastgrentime n`. * Increased nail velocity. Disable with `localinfo old_ng_velocity on`. * Nailgun and Super-nailgun damage configurable with `localinfo ng_damage` and `localinfo sng_damage`. * Keys and flags glow their colour. -* Option to adjust conussion grenade effect time in seconds. `localinfo cussgrentime`. * Option to fully restock player on cap. `localinfo stock_on_cap on`. * Option for packs to fully restock health and armor of player. `localinfo stockfull on`. * Automatic server-side mvd recording of clan matches. Requires `localinfo serverdemo on`. diff --git a/share/defs.h b/share/defs.h index 354149f1..0bb2b106 100644 --- a/share/defs.h +++ b/share/defs.h @@ -257,6 +257,7 @@ #define TFSTATE_FLAMES_MAX 131072 #define TFSTATE_FLASHED 262144 #define TFSTATE_CONCUSSED 524288 +#define TFSTATE_BLASTED 1048576 // Defines used by TF_T_Damage (see combat.qc) #define TF_TD_IGNOREARMOR 1 // Bypasses the armor of the target @@ -971,8 +972,6 @@ #define PC_MEDIC_MAXHEALTH 100 #define PC_MEDIC_MAXSPEED 320 #define PC_MEDIC_MAXSTRAFESPEED 320 -#define PC_BLASTMEDIC_MAXSPEED 280 -#define PC_BLASTMEDIC_MAXSTRAFESPEED 280 #define PC_MEDIC_MAXARMOR 90 #define PC_MEDIC_INITARMOR 40 #define PC_MEDIC_MAXARMORTYPE 0.6 diff --git a/ssqc/client.qc b/ssqc/client.qc index 0b2123df..27e11a0b 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -569,6 +569,12 @@ void () DecodeLevelParms = { // concussion grenade effect time [19] cussgrentime = CF_GetSetting("cgt", "cussgrentime", "19"); + // blast grenade effect time [2] + blastgrentime = CF_GetSetting("bgt", "blastgrentime", "2"); + + // blast grenade effect strength [1] + blastgrenstrength = CF_GetSetting("bgs", "blastgrenstrength", "1"); + // concussion grenade effect time proportional to distance from explosion distance_based_cuss_duration = CF_GetSetting("dbcd", "distance_based_cuss_duration", "off"); @@ -952,6 +958,8 @@ void () DecodeLevelParms = { drop_gren1 = 0; drop_gren2 = 0; cussgrentime = 19; + blastgrentime = 2; + blastgrenstrength = 1; spawnfull = FALSE; stockfull = FALSE; stock_on_cap = FALSE; @@ -2347,15 +2355,16 @@ void () PlayerJump = { TeamFortress_SetSpeed(self); } } + if (old_grens != 1) { te = find(world, classname, "timer"); - while (((te.owner != self) || (te.think != ConcussionGrenadeTimer)) - && (te != world)) + while (((te.owner != self) || (te.think != ConcussionGrenadeTimer)) && (te != world)) te = find(te, classname, "timer"); if ((te != world) && (te != self)) { crandom(); stumble = crandom() * (te.health / 100); + if (crandom() < 0) { self.velocity_x = self.velocity_y + stumble; self.velocity_y = self.velocity_x + stumble; @@ -2489,7 +2498,9 @@ void () PlayerPreThink = { IntermissionThink(); return; } + makevectors(self.v_angle); + if (self.view_ofs == '0 0 0') { return; } @@ -2548,9 +2559,11 @@ void () PlayerPreThink = { self.flags = self.flags | FL_JUMPRELEASED; } } + if ((time < self.pausetime) || (cease_fire == 1)) { self.velocity = '0 0 0'; } + if (time > self.attack_finished && !self.currentammo && self.weapon > WEAP_AXE) { W_ChangeWeapon(W_BestWeaponSlot()); W_SetCurrentAmmo(self); diff --git a/ssqc/qw.qc b/ssqc/qw.qc index efb5d24f..b38fbafd 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -31,6 +31,7 @@ typedef void (float n) f_void_float; .float is_zooming; // TRUE for a SNIPER if they're currently zoomed in .float is_quickfiring; // TRUE for a player if they're using the quick slots .float is_concussed; // TRUE for a player who is affected by concussion grenade +.float aircurve; // Multiplier on air speed. No air curve (0), normal (1), heaps (2) .float has_quickfired; // TRUE for a player that has stopped quick firing (until weapon is ready) .float has_throwngren; // TRUE for a player that has thrown a grenade (won't get a free suicide) .float has_changedteam; // TRUE for a player that has changed team @@ -562,6 +563,8 @@ float stock_on_cap; float stock_reload; float classtips; float cussgrentime; +float blastgrentime; +float blastgrenstrength; float medicnocuss; float distance_based_cuss_duration; float sniperpower; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index 1ef2a762..d4b43e3f 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -12,12 +12,9 @@ void () ConcussionGrenadeTouch; void () ConcussionGrenadeExplode; float (string ps_short, string ps_setting, string ps_default) CF_GetSetting; -void (entity inflictor, entity attacker, float bounce, - entity ignore) T_RadiusBounce; -void (entity inflictor, entity attacker, float bounce, - entity ignore) T_RadiusBounceBlast; -entity(entity scanner, float scanrange, float enemies, - float friends) T_RadiusScan; +void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounceCuss; +void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounceBlast; +entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan; void () CF_Scout_Dash = { if (self.playerclass != PC_SCOUT) @@ -360,7 +357,7 @@ void () ConcussionGrenadeTouch = { }; void () ConcussionGrenadeExplode = { - T_RadiusBounce(self, self.owner, 240, world); + T_RadiusBounceCuss(self, self.owner, 240, world); WriteByte(MSG_MULTICAST, SVC_TEMPENTITY); WriteByte(MSG_MULTICAST, TE_EXPLOSION); WriteCoord(MSG_MULTICAST, self.origin_x); @@ -447,9 +444,7 @@ void () ConcussionGrenadeTimer = { return; } - if ((self.health == 200) || (self.health == 400) || - (self.health == 600) - || (self.health == 800) || (self.health == 1000)) { + if ((self.health == 200) || (self.health == 400) || (self.health == 600) || (self.health == 800) || (self.health == 1000)) { newmis = spawn(); FO_SetModel(newmis, "progs/s_bubble.spr"); setorigin(newmis, self.owner.origin); @@ -464,7 +459,9 @@ void () ConcussionGrenadeTimer = { newmis.cnt = 0; setsize(newmis, '-8 -8 -8', '8 8 8'); } + self.health = self.health - 10; + if (self.owner.playerclass == 5) self.health = self.health - 10; @@ -472,6 +469,7 @@ void () ConcussionGrenadeTimer = { self.health = 0; concadjust = 1; + self.nextthink = time + 0.25 * concadjust; if (concadjust > 1) @@ -509,6 +507,33 @@ void () ConcussionGrenadeTimer = { } }; +void () BlastGrenadeTimer = { + local vector src; + local float pos; + + if (self.owner.invincible_finished > time) { + sprint(self.owner, PRINT_HIGH, "Your air-control is back to normal\n"); + self.owner.aircurve = 0; + dremove(self); + return; + } + self.owner.aircurve = (((40 * blastgrentime) - (self.health * blastgrenstrength)) / (40 * blastgrentime)); + TeamFortress_SetSpeed(self.owner); + + self.nextthink = time + 0.25; + self.health = self.health - 10; + + if (self.health < 0) + self.health = 0; + + if (self.health <= 0) { + sprint(self.owner, PRINT_HIGH, "Your air-control is back to normal\n"); + + TeamFortress_SetSpeed(self); + dremove(self); + } +}; + void () ScannerSwitch = { local entity te; @@ -773,62 +798,90 @@ void CussSpeedBump() } } -void (entity inflictor, entity attacker, float bounce, - entity ignore) T_RadiusBounceBlast = { +void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounceBlast = { local float points; local entity head; local vector org; + local entity te; head = findradius(inflictor.origin, bounce + 40); + while (head) { if (head != ignore) { if (head.takedamage) { + org = head.origin + (head.mins + head.maxs) * 0.5; points = 0.5 * vlen(org - inflictor.origin); + if (points < 0) points = 0; + points = bounce - points; - if ((head.classname != "building_dispenser") - && (head.classname != "building_sentrygun") - && (head.classname != "building_sentrygun_base") - && (points > 0)) { + if ((head.classname != "building_dispenser") && (head.classname != "building_sentrygun") && (head.classname != "building_sentrygun_base") && (points > 0)) { head.velocity = org - inflictor.origin; head.velocity = head.velocity * (points / 20) * blastgren_velocity_multiplier; + if (head.classname != "player") { if (head.flags & FL_ONGROUND) head.flags = head.flags - FL_ONGROUND; + } else { + te = find(world, classname, "timer"); + + while (((te.owner != head) || (te.think != BlastGrenadeTimer)) && (te != world)) + te = find(te, classname, "timer"); + + if (te != world) { + te.health = 40 * blastgrentime; + te.nextthink = time + 0.25; + + } else { + LogEventAffliction(attacker, head, TFSTATE_BLASTED); + + te = spawn(); + te.nextthink = time + 0.25; + te.think = BlastGrenadeTimer; + te.team_no = attacker.team_no; + te.classname = "timer"; + te.owner = head; + te.health = 40 * blastgrentime; + self.owner.aircurve = 1; + } } } } } + head = head.chain; } }; -void (entity inflictor, entity attacker, float bounce, - entity ignore) T_RadiusBounce = { +void (entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounceCuss = { local float actual_cuss_time = cussgrentime; - local float distance; + local float distance; local float points; local entity head; local entity te; local vector org; head = findradius(inflictor.origin, bounce + 40); + while (head) { if (head != ignore) { if (head.takedamage) { org = head.origin + (head.mins + head.maxs) * 0.5; distance = vlen(org - inflictor.origin); points = 0.5 * distance; + if (points < 0) points = 0; + points = bounce - points; if (distance_based_cuss_duration) { // Actual cuss time based on distance from max explosion radius local float fractional_distance = (1 - (distance / (bounce + 40))); + if (fractional_distance <= 1 && fractional_distance > 0.80) { actual_cuss_time = cussgrentime; } else if (fractional_distance <= 0.8 && fractional_distance > 0.2) { @@ -838,52 +891,23 @@ void (entity inflictor, entity attacker, float bounce, } } - if ((head.classname != "building_dispenser") - && (head.classname != "building_sentrygun") - && (head.classname != "building_sentrygun_base") - && (points > 0)) { + if ((head.classname != "building_dispenser") && (head.classname != "building_sentrygun") && (head.classname != "building_sentrygun_base") && (points > 0)) { head.velocity = org - inflictor.origin; head.velocity = head.velocity * (points / 20); + if (head.classname != "player") { if (head.flags & FL_ONGROUND) head.flags = head.flags - FL_ONGROUND; } else { - if (head.playerclass == PC_MEDIC) - { - if (medicnocuss && (medic_type != MEDIC_TYPE_BLAST)) - { - entity speedbump; - speedbump = spawn(); - speedbump.think = CussSpeedBump; - speedbump.nextthink = time + 1; - speedbump.owner = head; - - head = head.chain; - continue; - } - } - - if (distance_based_cuss_duration - && ((head.playerclass == PC_MEDIC) || (head.playerclass == PC_SCOUT))) { - entity speedbump; - speedbump = spawn(); - speedbump.think = CussSpeedBump; - speedbump.nextthink = time + 1; - speedbump.owner = head; - } - te = find(world, classname, "timer"); - if (old_grens == TRUE) - while (((te.owner != head) || - (te.think != - OldConcussionGrenadeTimer)) - && (te != world)) + + if (old_grens == TRUE) { + while (((te.owner != head) || (te.think != OldConcussionGrenadeTimer)) && (te != world)) te = find(te, classname, "timer"); - else - while (((te.owner != head) || - (te.think != ConcussionGrenadeTimer)) - && (te != world)) + } else { + while (((te.owner != head) || (te.think != ConcussionGrenadeTimer)) && (te != world)) te = find(te, classname, "timer"); + } if (te != world) { if (old_grens == TRUE) { diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 82e2636e..652cad7b 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -668,6 +668,11 @@ void () TeamFortress_ShowTF = { sprint(self, PRINT_HIGH, "Concussion effect lasts "); sprint(self, PRINT_HIGH, ftos(cussgrentime)); sprint(self, PRINT_HIGH, " seconds"); + sprint(self, PRINT_HIGH, "Blast effect lasts "); + sprint(self, PRINT_HIGH, ftos(blastgrentime)); + sprint(self, PRINT_HIGH, " seconds"); + sprint(self, PRINT_HIGH, "Blast effect strength "); + sprint(self, PRINT_HIGH, ftos(blastgrenstrength)); sprint(self, PRINT_HIGH, "\n== Scout ==\n"); CF_PrintSetting("Scout dash ability", scoutdash, "", 1); @@ -1253,13 +1258,8 @@ void (entity p) TeamFortress_SetSpeed = { p.maxfbspeed = PC_DEMOMAN_MAXSPEED; p.maxstrafespeed = PC_DEMOMAN_MAXSTRAFESPEED; } else if (p.playerclass == PC_MEDIC) { - if (medic_type == MEDIC_TYPE_BLAST) { - p.maxfbspeed = PC_BLASTMEDIC_MAXSPEED; - p.maxstrafespeed = PC_BLASTMEDIC_MAXSTRAFESPEED; - } else { - p.maxfbspeed = PC_MEDIC_MAXSPEED; - p.maxstrafespeed = PC_MEDIC_MAXSTRAFESPEED; - } + p.maxfbspeed = PC_MEDIC_MAXSPEED; + p.maxstrafespeed = PC_MEDIC_MAXSTRAFESPEED; } else if (p.playerclass == PC_HVYWEAP) { p.maxfbspeed = PC_HVYWEAP_MAXSPEED; p.maxstrafespeed = PC_HVYWEAP_MAXSTRAFESPEED; @@ -1314,6 +1314,13 @@ void (entity p) TeamFortress_SetSpeed = { p.maxstrafespeed = 80; } } + + if ((p.aircurve < 1) && !(p.flags & FL_ONGROUND)) { + p.maxfbspeed = p.maxfbspeed * p.aircurve; + p.maxstrafespeed = p.maxstrafespeed * p.aircurve; + p.maxspeed = p.maxspeed * p.aircurve; + } + sp = ftos(p.maxfbspeed); stuffcmd(p, "cl_backspeed "); stuffcmd(p, sp); @@ -1539,6 +1546,7 @@ void () TeamFortress_SetEquipment = { self.is_feigning = 0; self.is_unabletospy = 0; self.is_concussed = 0; + self.aircurve = 1; self.disguise_skin = 0; self.disguise_team = 0; self.detpack_left = 0; @@ -2371,6 +2379,7 @@ void () TeamFortress_RemoveTimers = { self.leg_damage = 0; self.is_concussed = 0; + self.aircurve = 1; self.is_undercover = 0; if (self.is_building && engineer_move) { diff --git a/ssqc/weapons.qc b/ssqc/weapons.qc index e5555816..91298c9b 100644 --- a/ssqc/weapons.qc +++ b/ssqc/weapons.qc @@ -8,6 +8,7 @@ void (vector org, float damage) SpawnBlood; void () SuperDamageSound; void () ConcussionGrenadeTimer; +void () BlastGrenadeTimer; void () OldConcussionGrenadeTimer; void (float inp) W_ChangeWeapon; @@ -379,10 +380,12 @@ void () W_FireMedikit = { healam = 200; te = find(world, classname, "timer"); + while (((te.owner != trace_ent) - || ((te.think != ConcussionGrenadeTimer) - && (te.think != OldConcussionGrenadeTimer))) - && (te != world)) + || ((te.think != ConcussionGrenadeTimer) + && (te.think != OldConcussionGrenadeTimer) + && (te.think != BlastGrenadeTimer))) + && (te != world)) te = find(te, classname, "timer"); if (te != world) { @@ -400,6 +403,7 @@ void () W_FireMedikit = { dremove(te); } + if (trace_ent.tfstate & TFSTATE_HALLUCINATING) { te = find(world, classname, "timer");