Correctly implement some projectile damages. Readjust damages to adapt to this change.

Add 3D explosion blast and knockback functions. Migrate pretty much everything to it.
Add "Classic Enhanced Shock Rifle" option, disables altfire and splash damage on beams.
Screen shakes for explosions now correctly fall off with distance.
Some minor refactoring/fixes.
This commit is contained in:
Marisa the Magician 2018-08-17 20:30:32 +02:00
commit 3267c89487
12 changed files with 103 additions and 45 deletions

View file

@ -21,3 +21,4 @@ user bool flak_footsteps = true;
server bool flak_translocator = false; server bool flak_translocator = false;
user bool flak_noswitchdeemer = true; // don't switch to redeemer when out of ammo user bool flak_noswitchdeemer = true; // don't switch to redeemer when out of ammo
user bool flak_deemershader = false; user bool flak_deemershader = false;
server bool flak_classicsshock = false; // classic enhanced shock rifle (no altfire, beams don't have splash damage)

View file

@ -25,6 +25,7 @@ OptionMenu "UTOptionMenu"
Option "Redeemer Target Visuals", "flak_redeemerreadout", "YesNo" Option "Redeemer Target Visuals", "flak_redeemerreadout", "YesNo"
Option "Redeemer View Shader", "flak_deemershader", "YesNo" Option "Redeemer View Shader", "flak_deemershader", "YesNo"
Option "No Redeemer Autoswitch", "flak_noswitchdeemer", "YesNo" Option "No Redeemer Autoswitch", "flak_noswitchdeemer", "YesNo"
Option "Classic Enh. Shock Rifle", "flak_classicsshock", "YesNo"
StaticText " " StaticText " "
Option "Enable Translocator", "flak_translocator", "YesNo" Option "Enable Translocator", "flak_translocator", "YesNo"
Command "Apply Changes", "event refreshtrans" Command "Apply Changes", "event refreshtrans"

View file

@ -411,7 +411,8 @@ Class BioGel : Actor
s.args[3] = int(s.args[3]*Scale.x); s.args[3] = int(s.args[3]*Scale.x);
invoker.deadtimer = -2; invoker.deadtimer = -2;
if ( invoker.atline ) invoker.atline.RemoteActivate(target,invoker.atside,SPAC_Impact,pos); if ( invoker.atline ) invoker.atline.RemoteActivate(target,invoker.atside,SPAC_Impact,pos);
A_Explode(int(Random[GES](10,15)*max(1,(Scale.x-1)**2)),Min(150,int(Scale.x*25))); UTMainHandler.DoBlast(self,Min(150,int(Scale.x*25)),200000);
A_Explode(int(Random[GES](18,22)*max(1,(Scale.x-1)**2)),Min(150,int(Scale.x*25)));
A_PlaySound("ges/explode",CHAN_VOICE); A_PlaySound("ges/explode",CHAN_VOICE);
int numpt = Min(300,int(Scale.x*30))+Random[GES](-10,10); int numpt = Min(300,int(Scale.x*30))+Random[GES](-10,10);
for ( int i=0; i<numpt; i++ ) for ( int i=0; i<numpt; i++ )
@ -437,13 +438,12 @@ Class BioGel : Actor
{ {
Obituary "%o drank a glass of %k's dripping green load."; Obituary "%o drank a glass of %k's dripping green load.";
DamageType 'Slime'; DamageType 'Slime';
DamageFunction int(Random[GES](10,15)*max(1,(Scale.x-1)**2)); Damage 0;
RenderStyle "Add"; RenderStyle "Add";
Radius 3; Radius 3;
Height 3; Height 3;
Scale 2; Scale 2;
Speed 18; Speed 18;
ProjectileKickback 120;
Gravity 0.5; Gravity 0.5;
PROJECTILE; PROJECTILE;
-NOGRAVITY; -NOGRAVITY;
@ -452,6 +452,7 @@ Class BioGel : Actor
+FORCERADIUSDMG; +FORCERADIUSDMG;
+FORCEXYBILLBOARD; +FORCEXYBILLBOARD;
+MOVEWITHSECTOR; +MOVEWITHSECTOR;
+NODAMAGETHRUST;
} }
States States
{ {

View file

@ -105,16 +105,17 @@ Class UTRocket : Actor
Default Default
{ {
Obituary "%o was smacked down by %k's Rocket Launcher."; Obituary "%o was smacked down by %k's Rocket Launcher.";
DamageFunction Random[Eightball](90,115); Damage 0;
DamageType 'RocketDeath'; DamageType 'RocketDeath';
Radius 2; Radius 2;
Height 2; Height 2;
Speed 18; Speed 18;
ProjectileKickback 400;
PROJECTILE; PROJECTILE;
+SKYEXPLODE; +SKYEXPLODE;
+EXPLODEONWATER; +EXPLODEONWATER;
+SEEKERMISSILE; +SEEKERMISSILE;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
} }
override void PostBeginPlay() override void PostBeginPlay()
{ {
@ -123,15 +124,16 @@ Class UTRocket : Actor
l.target = self; l.target = self;
A_PlaySound("utrl/fly",CHAN_VOICE,1.0,true,2.5); A_PlaySound("utrl/fly",CHAN_VOICE,1.0,true,2.5);
} }
action void A_RocketExplode() action void A_RocketExplode( int dmg )
{ {
bFORCEXYBILLBOARD = true; bFORCEXYBILLBOARD = true;
A_SetRenderStyle(1.0,STYLE_Add); A_SetRenderStyle(1.0,STYLE_Add);
A_SprayDecal("RocketBlast",150); A_SprayDecal("RocketBlast",150);
A_NoGravity(); A_NoGravity();
A_SetScale(0.75); A_SetScale(0.75);
A_Explode(Random[Eightball](80,100),100); UTMainHandler.DoBlast(self,100,80000);
A_QuakeEx(3,3,3,8,0,250,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.2); A_Explode(dmg,100);
A_QuakeEx(3,3,3,8,0,250,"",QF_RELATIVE|QF_SCALEDOWN,falloff:100,rollIntensity:0.2);
A_PlaySound("utrl/explode",CHAN_VOICE); A_PlaySound("utrl/explode",CHAN_VOICE);
A_AlertMonsters(); A_AlertMonsters();
Spawn("RocketExplLight",pos); Spawn("RocketExplLight",pos);
@ -178,7 +180,7 @@ Class UTRocket : Actor
} }
Wait; Wait;
Death: Death:
TNT1 A 0 A_RocketExplode(); TNT1 A 0 A_RocketExplode(Random[Eightball](90,115));
SSMX ABCDEFGHIJ 2 Bright; SSMX ABCDEFGHIJ 2 Bright;
Stop; Stop;
} }
@ -190,7 +192,6 @@ Class UTGrenade : UTRocket
Default Default
{ {
DamageFunction Random[Eightball](90,120);
DamageType 'GrenadeDeath'; DamageType 'GrenadeDeath';
-NOGRAVITY; -NOGRAVITY;
+USEBOUNCESTATE; +USEBOUNCESTATE;
@ -231,6 +232,9 @@ Class UTGrenade : UTRocket
anglevel = FRandom[Eightball](-16,16); anglevel = FRandom[Eightball](-16,16);
} }
Goto Spawn; Goto Spawn;
Death:
TNT1 A 0 A_RocketExplode(Random[Eightball](90,120));
Goto Super::Death+1;
} }
} }

View file

@ -313,7 +313,8 @@ Class Enforcer : UTWeapon replaces Pistol
if ( d.HitType == TRACE_HitActor ) if ( d.HitType == TRACE_HitActor )
{ {
int dmg = Random[Enforcer](12,17); int dmg = Random[Enforcer](12,17);
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'shot',DMG_USEANGLE,atan2(d.HitDir.y,d.HitDir.x)); dmg = d.HitActor.DamageMobj(invoker,self,dmg,'shot',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x));
UTMainHandler.DoKnockback(d.HitActor,d.HitDir,3000);
if ( d.HitActor.bNOBLOOD ) if ( d.HitActor.bNOBLOOD )
{ {
let p = Spawn("BulletImpact",d.HitLocation); let p = Spawn("BulletImpact",d.HitLocation);

View file

@ -359,16 +359,17 @@ Class FlakSlug : Actor
{ {
Obituary "%o was ripped to shreds by %k's Flak Cannon."; Obituary "%o was ripped to shreds by %k's Flak Cannon.";
DamageType 'FlakDeath'; DamageType 'FlakDeath';
DamageFunction Random[Flak](100,110); Damage 0;
Radius 2; Radius 2;
Height 2; Height 2;
Speed 40; Speed 40;
ProjectileKickback 320;
PROJECTILE; PROJECTILE;
-NOGRAVITY; -NOGRAVITY;
+SKYEXPLODE; +SKYEXPLODE;
+EXPLODEONWATER; +EXPLODEONWATER;
+HITTRACER; +HITTRACER;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
} }
override void PostBeginPlay() override void PostBeginPlay()
{ {
@ -387,8 +388,9 @@ Class FlakSlug : Actor
A_SprayDecal("RocketBlast",150); A_SprayDecal("RocketBlast",150);
A_NoGravity(); A_NoGravity();
A_SetScale(1.2); A_SetScale(1.2);
UTMainHandler.DoBlast(self,80,75000);
A_Explode(Random[Flak](70,80),80); A_Explode(Random[Flak](70,80),80);
A_QuakeEx(4,4,4,8,0,200,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.2); A_QuakeEx(4,4,4,8,0,200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:80,rollIntensity:0.2);
A_PlaySound("flak/explode",CHAN_VOICE); A_PlaySound("flak/explode",CHAN_VOICE);
A_AlertMonsters(); A_AlertMonsters();
if ( !Tracer ) Spawn("SlugSmoke",pos); if ( !Tracer ) Spawn("SlugSmoke",pos);

View file

@ -124,7 +124,8 @@ Class Minigun : UTWeapon
if ( d.HitType == TRACE_HitActor ) if ( d.HitType == TRACE_HitActor )
{ {
int dmg = Random[Minigun](16,20); // fun fact: the Minigun is one of the few weapons that has actual RNG damage in UT int dmg = Random[Minigun](16,20); // fun fact: the Minigun is one of the few weapons that has actual RNG damage in UT
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'shot',DMG_USEANGLE,atan2(d.HitDir.y,d.HitDir.x)); dmg = d.HitActor.DamageMobj(invoker,self,dmg,'shot',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x));
UTMainHandler.DoKnockback(d.HitActor,d.HitDir,dmg*500);
if ( d.HitActor.bNOBLOOD ) if ( d.HitActor.bNOBLOOD )
{ {
let p = Spawn("BulletImpact",d.HitLocation); let p = Spawn("BulletImpact",d.HitLocation);

View file

@ -70,6 +70,7 @@ Class Razor2 : Actor
-BOUNCEAUTOOFF; -BOUNCEAUTOOFF;
+SKYEXPLODE; +SKYEXPLODE;
+CANBOUNCEWATER; +CANBOUNCEWATER;
+NODAMAGETHRUST;
} }
override void PostBeginPlay() override void PostBeginPlay()
{ {
@ -95,6 +96,7 @@ Class Razor2 : Actor
A_PlaySound("ripper/flesh"); A_PlaySound("ripper/flesh");
A_AlertMonsters(); A_AlertMonsters();
} }
UTMainHandler.DoKnockback(target,vel.unit(),15000);
return damage; return damage;
} }
action void A_RazorHit() action void A_RazorHit()
@ -183,12 +185,13 @@ Class Razor2Alt : Razor2
{ {
Default Default
{ {
DamageFunction Random[Ripper](40,60); Damage 0;
DamageType 'RipperAltDealth'; DamageType 'RipperAltDealth';
BounceType "None"; BounceType "None";
ProjectileKickback 350;
-CANBOUNCEWATER; -CANBOUNCEWATER;
+EXPLODEONWATER; +EXPLODEONWATER;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
} }
action void A_RazorExplode() action void A_RazorExplode()
{ {
@ -200,8 +203,9 @@ Class Razor2Alt : Razor2
Spawn("Razor2AltLight",pos); Spawn("Razor2AltLight",pos);
A_AlertMonsters(); A_AlertMonsters();
A_SprayDecal("RazorBlast",20); A_SprayDecal("RazorBlast",20);
UTMainHandler.DoBlast(self,120,87000);
A_Explode(Random[Ripper](30,50),120); A_Explode(Random[Ripper](30,50),120);
A_QuakeEx(3,3,3,10,0,180,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1); A_QuakeEx(3,3,3,10,0,180,"",QF_RELATIVE|QF_SCALEDOWN,falloff:120,rollIntensity:0.1);
int numpt = Random[Ripper](10,20); int numpt = Random[Ripper](10,20);
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch)); Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
for ( int i=0; i<numpt; i++ ) for ( int i=0; i<numpt; i++ )

View file

@ -277,12 +277,12 @@ Class ShockBeam : Actor
Radius 0.1; Radius 0.1;
Height 0; Height 0;
Scale 0.4; Scale 0.4;
ProjectileKickback 250;
+NOGRAVITY; +NOGRAVITY;
+NOCLIP; +NOCLIP;
+DONTSPLASH; +DONTSPLASH;
+FORCEXYBILLBOARD; +FORCEXYBILLBOARD;
+FORCERADIUSDMG; +FORCERADIUSDMG;
+NODAMAGETHRUST;
} }
override void PostBeginPlay() override void PostBeginPlay()
{ {
@ -336,9 +336,10 @@ Class ShockBeam : Actor
{ {
if ( target ) target.TakeInventory('ShockAmmo',2); if ( target ) target.TakeInventory('ShockAmmo',2);
let b = t.Results.HitActor.target; let b = t.Results.HitActor.target;
UTMainHandler.DoBlast(b,300,70000);
b.ExplodeMissile(null,self); b.ExplodeMissile(null,self);
b.A_Explode(Random[ASMD](150,160),300); b.A_Explode(Random[ASMD](150,160),300);
b.A_QuakeEx(6,6,6,60,0,1200,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.2); b.A_QuakeEx(6,6,6,60,0,1200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:0.2);
b.A_SprayDecal("BigShockMark1",100); b.A_SprayDecal("BigShockMark1",100);
b.A_SprayDecal("BigShockMark2",100); b.A_SprayDecal("BigShockMark2",100);
Spawn("ShockRifleWave",b.pos); Spawn("ShockRifleWave",b.pos);
@ -358,6 +359,7 @@ Class ShockBeam : Actor
else else
{ {
t.Results.HitActor.DamageMobj(self,target,Random[ASMD](35,50),'jolted',DMG_USEANGLE,atan2(t.Results.HitVector.y,t.Results.HitVector.x)); t.Results.HitActor.DamageMobj(self,target,Random[ASMD](35,50),'jolted',DMG_USEANGLE,atan2(t.Results.HitVector.y,t.Results.HitVector.x));
UTMainHandler.DoKnockback(t.Results.HitActor,t.Results.HitVector,60000);
let r = Spawn("ShockBeamRing",pos); let r = Spawn("ShockBeamRing",pos);
r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x); r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
r.pitch = asin(-t.Results.HitVector.z); r.pitch = asin(-t.Results.HitVector.z);
@ -391,7 +393,7 @@ Class ShockBeam : Actor
action void A_BeamExplode() action void A_BeamExplode()
{ {
Spawn("ShockBeamLight",pos); Spawn("ShockBeamLight",pos);
A_QuakeEx(2,2,2,5,0,120,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1); A_QuakeEx(2,2,2,5,0,120,"",QF_RELATIVE|QF_SCALEDOWN,falloff:60,rollIntensity:0.1);
A_PlaySound("shock/hit",CHAN_VOICE); A_PlaySound("shock/hit",CHAN_VOICE);
A_AlertMonsters(); A_AlertMonsters();
int numpt = Random[ASMD](20,50); int numpt = Random[ASMD](20,50);
@ -503,6 +505,7 @@ Class SuperShockBeam : Actor
+FORCEXYBILLBOARD; +FORCEXYBILLBOARD;
+FORCERADIUSDMG; +FORCERADIUSDMG;
+EXTREMEDEATH; +EXTREMEDEATH;
+NODAMAGETHRUST;
} }
override void PostBeginPlay() override void PostBeginPlay()
{ {
@ -556,9 +559,10 @@ Class SuperShockBeam : Actor
{ {
if ( target ) target.TakeInventory('EnhancedShockAmmo',1); if ( target ) target.TakeInventory('EnhancedShockAmmo',1);
let b = t.Results.HitActor.target; let b = t.Results.HitActor.target;
UTMainHandler.DoBlast(b,400,70000);
b.ExplodeMissile(null,self); b.ExplodeMissile(null,self);
b.A_Explode(Random[ASMD](15000,16000),400); b.A_Explode(Random[ASMD](15000,16000),400);
b.A_QuakeEx(9,9,9,60,0,2400,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.4); b.A_QuakeEx(9,9,9,60,0,2400,"",QF_RELATIVE|QF_SCALEDOWN,falloff:400,rollIntensity:0.4);
b.A_SprayDecal("BigShockMark1",100); b.A_SprayDecal("BigShockMark1",100);
b.A_SprayDecal("SBigShockMark2",100); b.A_SprayDecal("SBigShockMark2",100);
Spawn("SuperShockRifleWave",b.pos); Spawn("SuperShockRifleWave",b.pos);
@ -578,7 +582,8 @@ Class SuperShockBeam : Actor
} }
else else
{ {
t.Results.HitActor.DamageMobj(self,target,Random[ASMD](3500,5000),'joltedX',DMG_USEANGLE,atan2(t.Results.HitVector.y,t.Results.HitVector.x)); t.Results.HitActor.DamageMobj(self,target,Random[ASMD](3500,5000),'joltedX',DMG_USEANGLE|DMG_THRUSTLESS,atan2(t.Results.HitVector.y,t.Results.HitVector.x));
UTMainHandler.DoKnockback(t.Results.HitActor,t.Results.HitVector,60000);
let r = Spawn("SuperShockBeamRing",pos); let r = Spawn("SuperShockBeamRing",pos);
r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x); r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
r.pitch = asin(-t.Results.HitVector.z); r.pitch = asin(-t.Results.HitVector.z);
@ -612,8 +617,12 @@ Class SuperShockBeam : Actor
action void A_BeamExplode() action void A_BeamExplode()
{ {
Spawn("SuperShockBeamLight",pos); Spawn("SuperShockBeamLight",pos);
A_Explode(Random[ASMD](500,800),90); if ( !CVar.GetCVar('flak_classicsshock').GetBool() )
A_QuakeEx(6,6,6,5,0,200,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.2); {
UTMainHandler.DoBlast(self,90,60000);
A_Explode(Random[ASMD](500,800),90);
}
A_QuakeEx(6,6,6,5,0,200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:90,rollIntensity:0.2);
A_PlaySound("shock/hit",CHAN_VOICE,attenuation:0.5); A_PlaySound("shock/hit",CHAN_VOICE,attenuation:0.5);
A_PlaySound("sshock/blast",CHAN_6,attenuation:0.5); A_PlaySound("sshock/blast",CHAN_6,attenuation:0.5);
A_AlertMonsters(); A_AlertMonsters();
@ -819,6 +828,7 @@ Class ShockBall : Actor
} }
action void A_BallExplode() action void A_BallExplode()
{ {
UTMainHandler.DoBlast(self,70,70000);
A_Explode(Random[ASMD](40,50),70); A_Explode(Random[ASMD](40,50),70);
A_SprayDecal("ShockMarkBig",16); A_SprayDecal("ShockMarkBig",16);
Spawn("ShockExplLight",pos); Spawn("ShockExplLight",pos);
@ -829,7 +839,7 @@ Class ShockBall : Actor
r.scale *= 1.5; r.scale *= 1.5;
A_PlaySound("shock/hit",CHAN_VOICE); A_PlaySound("shock/hit",CHAN_VOICE);
A_PlaySound("shock/ball",CHAN_WEAPON); A_PlaySound("shock/ball",CHAN_WEAPON);
A_QuakeEx(4,4,4,30,0,200,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.15); A_QuakeEx(4,4,4,30,0,200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:70,rollIntensity:0.15);
A_AlertMonsters(); A_AlertMonsters();
int numpt = Random[ASMD](50,100); int numpt = Random[ASMD](50,100);
for ( int i=0; i<numpt; i++ ) for ( int i=0; i<numpt; i++ )
@ -844,16 +854,17 @@ Class ShockBall : Actor
Obituary "%k inflicted mortal damage upon %o with the Shock Rifle"; Obituary "%k inflicted mortal damage upon %o with the Shock Rifle";
RenderStyle "Add"; RenderStyle "Add";
DamageType 'jolted'; DamageType 'jolted';
DamageFunction Random[ASMD](50,60); Damage 0;
Radius 2; Radius 2;
Height 2; Height 2;
Scale 0.4; Scale 0.4;
Speed 20; Speed 20;
ProjectileKickback 250;
PROJECTILE; PROJECTILE;
+FORCEXYBILLBOARD; +FORCEXYBILLBOARD;
+SKYEXPLODE; +SKYEXPLODE;
+EXPLODEONWATER; +EXPLODEONWATER;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
} }
States States
{ {
@ -882,6 +893,7 @@ Class SuperShockBall : Actor
} }
action void A_BallExplode() action void A_BallExplode()
{ {
UTMainHandler.DoBlast(self,120,70000);
A_Explode(Random[ASMD](4000,5000),120); A_Explode(Random[ASMD](4000,5000),120);
A_SprayDecal("ShockMarkBig",16); A_SprayDecal("ShockMarkBig",16);
Spawn("SuperShockExplLight",pos); Spawn("SuperShockExplLight",pos);
@ -893,7 +905,7 @@ Class SuperShockBall : Actor
A_PlaySound("shock/hit",CHAN_VOICE,attenuation:0.5); A_PlaySound("shock/hit",CHAN_VOICE,attenuation:0.5);
A_PlaySound("shock/ball",CHAN_WEAPON,attenuation:0.5); A_PlaySound("shock/ball",CHAN_WEAPON,attenuation:0.5);
A_PlaySound("sshock/blast",CHAN_6,attenuation:0.5); A_PlaySound("sshock/blast",CHAN_6,attenuation:0.5);
A_QuakeEx(8,8,8,30,0,300,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.25); A_QuakeEx(8,8,8,30,0,300,"",QF_RELATIVE|QF_SCALEDOWN,falloff:120,rollIntensity:0.25);
A_AlertMonsters(); A_AlertMonsters();
int numpt = Random[ASMD](50,100); int numpt = Random[ASMD](50,100);
for ( int i=0; i<numpt; i++ ) for ( int i=0; i<numpt; i++ )
@ -908,7 +920,7 @@ Class SuperShockBall : Actor
Obituary "%k electrified %o with the Enhanced Shock Rifle."; Obituary "%k electrified %o with the Enhanced Shock Rifle.";
RenderStyle "Add"; RenderStyle "Add";
DamageType 'joltedX'; DamageType 'joltedX';
DamageFunction Random[ASMD](5000,6000); Damage 0;
Radius 2; Radius 2;
Height 2; Height 2;
Scale 0.5; Scale 0.5;
@ -919,6 +931,8 @@ Class SuperShockBall : Actor
+FORCERADIUSDMG; +FORCERADIUSDMG;
+EXTREMEDEATH; +EXTREMEDEATH;
+EXPLODEONWATER; +EXPLODEONWATER;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
} }
States States
{ {
@ -1101,6 +1115,17 @@ Class ShockRifle : UTWeapon
Class EnhancedShockAmmo : Ammo Class EnhancedShockAmmo : Ammo
{ {
int ticcnt;
override void Tick()
{
Super.Tick();
if ( !Owner ) return;
ticcnt++;
if ( ticcnt < 105 ) return;
ticcnt = 0;
if ( Amount > 0 ) Amount--;
}
Default Default
{ {
Tag "Enhanced Shock Core"; Tag "Enhanced Shock Core";
@ -1132,17 +1157,6 @@ Class ViewSuperShockSpark : ViewShockSpark
Class EnhancedShockRifle : UTWeapon replaces InvulnerabilitySphere Class EnhancedShockRifle : UTWeapon replaces InvulnerabilitySphere
{ {
int ticcnt;
override void Tick()
{
Super.Tick();
if ( !Owner ) return;
ticcnt++;
if ( ticcnt < 105 ) return;
ticcnt = 0;
DepleteAmmo(false,true,1);
}
action void A_SShockFire() action void A_SShockFire()
{ {
Weapon weap = Weapon(invoker); Weapon weap = Weapon(invoker);
@ -1259,6 +1273,7 @@ Class EnhancedShockRifle : UTWeapon replaces InvulnerabilitySphere
ASMF BCDEFGHIJJ 2; ASMF BCDEFGHIJJ 2;
Goto Idle; Goto Idle;
AltFire: AltFire:
ASMI A 0 A_JumpIf(CVar.GetCVar('flak_classicsshock').GetBool(),"Fire");
ASMI A 0 A_JumpIfNoAmmo("DryFire"); ASMI A 0 A_JumpIfNoAmmo("DryFire");
ASMA A 1 A_SShockAlt(); ASMA A 1 A_SShockAlt();
ASMA BCDFGHIJ 2; ASMA BCDFGHIJ 2;

View file

@ -96,8 +96,15 @@ Class SniperRifle : UTWeapon
{ {
int dmg = Random[Sniper](45,60); int dmg = Random[Sniper](45,60);
if ( d.HitLocation.z >= (d.HitActor.pos.z+d.HitActor.height*0.8) ) if ( d.HitLocation.z >= (d.HitActor.pos.z+d.HitActor.height*0.8) )
dmg = d.HitActor.DamageMobj(invoker,self,dmg+70,'Decapitated',DMG_USEANGLE,atan2(d.HitDir.y,d.HitDir.x)); {
else dmg = d.HitActor.DamageMobj(invoker,self,dmg,'shot',DMG_USEANGLE,atan2(d.HitDir.y,d.HitDir.x)); dmg = d.HitActor.DamageMobj(invoker,self,dmg+70,'Decapitated',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x));
UTMainHandler.DoKnockback(d.HitActor,d.HitDir,35000);
}
else
{
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'shot',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x));
UTMainHandler.DoKnockback(d.HitActor,d.HitDir,30000);
}
if ( d.HitActor.bNOBLOOD ) if ( d.HitActor.bNOBLOOD )
{ {
let p = Spawn("BulletImpact",d.HitLocation); let p = Spawn("BulletImpact",d.HitLocation);

View file

@ -925,4 +925,25 @@ Class UTMainHandler : StaticEventHandler
let hnd = UTMainHandler(StaticEventHandler.Find("UTMainHandler")); let hnd = UTMainHandler(StaticEventHandler.Find("UTMainHandler"));
hnd.flashes.push(qf); hnd.flashes.push(qf);
} }
// Doom's explosions aren't fully 3D
static void DoBlast( Actor Source, double ExplosionRadius, double MomentumTransfer )
{
BlockThingsIterator bi = BlockThingsIterator.Create(Source,ExplosionRadius);
while ( bi.Next() )
{
Actor a = bi.Thing;
if ( !a || !a.bSHOOTABLE || !Source.CheckSight(a,0xf) || (a == Source) )
continue;
Vector3 midpoint = a.Vec3Offset(0,0,a.height*0.5);
a.vel += Level.Vec3Diff(Source.pos,midpoint).unit()*(MomentumTransfer/(Thinker.TICRATE*a.mass));
}
}
// Same for this
static void DoKnockback( Actor Victim, Vector3 HitDirection, double MomentumTransfer )
{
if ( !Victim ) return;
Victim.vel += HitDirection*(MomentumTransfer/(Thinker.TICRATE*Victim.Mass));
}
} }

View file

@ -42,7 +42,7 @@ Class ShockWave : Actor
{ {
lifespan = ReactionTime; lifespan = ReactionTime;
A_PlaySound("warhead/explode",CHAN_VOICE,attenuation:ATTN_NONE); A_PlaySound("warhead/explode",CHAN_VOICE,attenuation:ATTN_NONE);
A_QuakeEx(9,9,9,100,0,12000,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.5); A_QuakeEx(9,9,9,100,0,12000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:1200,rollIntensity:0.5);
} }
override void Tick() override void Tick()
{ {
@ -61,7 +61,7 @@ Class ShockWave : Actor
t.Reinit(); t.Reinit();
while ( a = Actor(t.Next()) ) while ( a = Actor(t.Next()) )
{ {
if ( !a.bShootable || !CheckSight(a) || (Distance3D(a) > dmgradius) ) continue; if ( !a.bShootable || !CheckSight(a,0xf) || (Distance3D(a) > dmgradius) ) continue;
Vector3 dir = Vec3To(a); Vector3 dir = Vec3To(a);
double dist = max(1,dir.length()); double dist = max(1,dir.length());
dir = dir/dist+(0,0,0.3); dir = dir/dist+(0,0,0.3);