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;
user bool flak_noswitchdeemer = true; // don't switch to redeemer when out of ammo
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 View Shader", "flak_deemershader", "YesNo"
Option "No Redeemer Autoswitch", "flak_noswitchdeemer", "YesNo"
Option "Classic Enh. Shock Rifle", "flak_classicsshock", "YesNo"
StaticText " "
Option "Enable Translocator", "flak_translocator", "YesNo"
Command "Apply Changes", "event refreshtrans"

View file

@ -411,7 +411,8 @@ Class BioGel : Actor
s.args[3] = int(s.args[3]*Scale.x);
invoker.deadtimer = -2;
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);
int numpt = Min(300,int(Scale.x*30))+Random[GES](-10,10);
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.";
DamageType 'Slime';
DamageFunction int(Random[GES](10,15)*max(1,(Scale.x-1)**2));
Damage 0;
RenderStyle "Add";
Radius 3;
Height 3;
Scale 2;
Speed 18;
ProjectileKickback 120;
Gravity 0.5;
PROJECTILE;
-NOGRAVITY;
@ -452,6 +452,7 @@ Class BioGel : Actor
+FORCERADIUSDMG;
+FORCEXYBILLBOARD;
+MOVEWITHSECTOR;
+NODAMAGETHRUST;
}
States
{

View file

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

View file

@ -124,7 +124,8 @@ Class Minigun : UTWeapon
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
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 )
{
let p = Spawn("BulletImpact",d.HitLocation);

View file

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

View file

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

View file

@ -96,8 +96,15 @@ Class SniperRifle : UTWeapon
{
int dmg = Random[Sniper](45,60);
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 )
{
let p = Spawn("BulletImpact",d.HitLocation);

View file

@ -925,4 +925,25 @@ Class UTMainHandler : StaticEventHandler
let hnd = UTMainHandler(StaticEventHandler.Find("UTMainHandler"));
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;
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()
{
@ -61,7 +61,7 @@ Class ShockWave : Actor
t.Reinit();
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);
double dist = max(1,dir.length());
dir = dir/dist+(0,0,0.3);