- Fix inventory items not removing themselves when fully drained and no more copies are held. - Fixed Minigun playing the unwind animation on player death. - Fixed main hand Automag still firing when out of ammo dual wielding. - Corrected name clash between two explosion sounds. - Fixed suits still protecting from elemental damage when depleted. - Add option to wear all suits simultaneously. - Stunner now consumes Stinger ammo to recharge, this is more in line with the Unreal Bible. - Max damage per explosion capped to 100 for Stinger. Prevents ludicrous map-clearing explosions with an amplified asmd combo. - Shoot-through lines can now be activated by hitscan/beam weapons thanks to new DT "bullet trail" feature. No more softlocks in custom maps. - Added option to make Peacemaker missiles not seek owner and allies. - Peacemaker missiles start seeking targets much earlier, making it more viable indoors. - Autocannon has had its damage increased again. - Adjusted swingers for many weapons to feel a bit more natural. Still far from perfect. - Reverted changes to Flamethrower projectile density, and simply made it have less dynamic lights. - Adjustments to armors. Suit elemental resistances now take priority (as intended). [please redownload your DT devbuild for full effect] - Added ring effect for 6-rocket tight wad. Completely forgot this was a thing. - Fixed flashlight not clearing its dynlights when depleted and still having copies.
511 lines
12 KiB
Text
511 lines
12 KiB
Text
Class UFireLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "FlamG";
|
|
Args 0,0,0,60;
|
|
}
|
|
}
|
|
|
|
Class UFireTrail : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+DONTSPLASH;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
Scale 0.5;
|
|
Alpha 0.2;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target || !target.bMISSILE )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FGFL A -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UFireball : Actor
|
|
{
|
|
Vector3 Acceleration;
|
|
double spreadf, maxspeed;
|
|
int ns, nsp;
|
|
|
|
property SpreadFactor : spreadf;
|
|
property NumSmokes : ns;
|
|
property NumSparks : nsp;
|
|
|
|
Default
|
|
{
|
|
DamageType 'Fire';
|
|
DamageFunction 20;
|
|
Radius 4;
|
|
Height 4;
|
|
Speed 15;
|
|
PROJECTILE;
|
|
+SKYEXPLODE;
|
|
+EXPLODEONWATER;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+FORCEXYBILLBOARD;
|
|
UFireball.SpreadFactor 0.2;
|
|
UFireball.NumSmokes 1;
|
|
UFireball.NumSparks 2;
|
|
DeathSound "flamegun/exp";
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
maxspeed = 30.;
|
|
if ( bAMBUSH ) return;
|
|
let l = Spawn("UFireTrail",pos);
|
|
l.target = self;
|
|
Acceleration = vel.unit()*50;
|
|
A_PlaySound("eightball/fly",CHAN_VOICE,.6,true,3.,pitch:1.5);
|
|
}
|
|
action void A_Spread()
|
|
{
|
|
vel += invoker.Acceleration/TICRATE;
|
|
vel += (FRandom[EWizFX](-1,1),FRandom[EWizFX](-1,1),FRandom[EWizFX](-1,1))*FRandom[EWizFX](.5,1.)*invoker.spreadf;
|
|
Vector3 dir = vel.unit();
|
|
if ( vel.length() > invoker.maxspeed ) vel = dir*invoker.maxspeed;
|
|
angle = atan2(dir.y,dir.x);
|
|
pitch = asin(-dir.z);
|
|
if ( waterlevel > 0 )
|
|
{
|
|
int numpt = Random[ExploS](10,15);
|
|
if ( bAMBUSH ) numpt /= 3;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (dir*3+(FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1))).unit()*FRandom[ExploS](1,4);
|
|
let s = Spawn("UTSmoke",pos);
|
|
s.vel = pvel;
|
|
s.alpha *= 0.6;
|
|
s.scale *= FRandom[ExploS](0.9,2.0);
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](64,128));
|
|
}
|
|
Destroy();
|
|
return;
|
|
}
|
|
for ( int i=0; i<invoker.ns; i++ )
|
|
{
|
|
if ( Random[FlameGun](0,2) ) continue;
|
|
let s = Spawn("UTSmoke",pos);
|
|
s.vel = (FRandom[FlameGun](-0.2,0.2),FRandom[FlameGun](-0.2,0.2),FRandom[FlameGun](-0.2,0.2));
|
|
s.vel += vel*0.2;
|
|
s.scale *= 0.5;
|
|
}
|
|
for ( int i=0; i<invoker.nsp; i++ )
|
|
{
|
|
if ( Random[FlameGun](0,6) ) continue;
|
|
let s = Spawn("UTSpark",pos);
|
|
s.vel = (FRandom[FlameGun](-0.2,0.2),FRandom[FlameGun](-0.2,0.2),FRandom[FlameGun](-0.2,0.2));
|
|
s.ClearBounce();
|
|
s.gravity *= 0.1;
|
|
s.A_SetTranslation('FlamGSpark');
|
|
}
|
|
}
|
|
action void A_FireballExplo()
|
|
{
|
|
A_SetRenderStyle(1.,STYLE_Add);
|
|
A_NoGravity();
|
|
if ( bAMBUSH )
|
|
{
|
|
A_Explode(GetMissileDamage(0,0),20);
|
|
UTMainHandler.DoBlast(self,20,3000);
|
|
}
|
|
else
|
|
{
|
|
Spawn("UFireLight",pos);
|
|
A_Explode(GetMissileDamage(0,0),60);
|
|
UTMainHandler.DoBlast(self,60,9000);
|
|
A_PlaySound(DeathSound,CHAN_VOICE,attenuation:1.5,pitch:FRandom[ExploS](0.8,1.2));
|
|
}
|
|
A_SprayDecal("SmallRocketBlast");
|
|
Scale *= FRandom[ExploS](0.6,0.9);
|
|
Vector3 dir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
|
int numpt = Random[ExploS](10,15);
|
|
if ( bAMBUSH ) numpt /= 3;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (dir*3+(FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1))).unit()*FRandom[ExploS](2,8);
|
|
let s = Spawn("UTSmoke",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[ExploS](0.9,1.5);
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](64,128));
|
|
}
|
|
numpt = Random[ExploS](6,12);
|
|
if ( bAMBUSH ) numpt /= 3;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,6);
|
|
let s = Spawn("UTSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[ExploS](10,20);
|
|
if ( bAMBUSH ) numpt /= 3;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,12);
|
|
let s = Spawn("UTChip",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[ExploS](0.9,1.3);
|
|
}
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !isFrozen() && InStateSequence(CurState,FindState("Spawn")) )
|
|
A_Spread();
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FIRB ABCDEFGHIJK 2 Bright;
|
|
Loop;
|
|
Death:
|
|
TNT1 A 0 A_FireballExplo();
|
|
FGEX ABCDEFGH 2 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UFireball2 : UFireball
|
|
{
|
|
Default
|
|
{
|
|
Radius 8;
|
|
Height 8;
|
|
DamageFunction 50;
|
|
Speed 3;
|
|
Scale 1.5;
|
|
UFireball.SpreadFactor 0.35;
|
|
UFireball.NumSmokes 6;
|
|
UFireball.NumSparks 12;
|
|
DeathSound "flamegun/exp2";
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
Acceleration = vel.unit()*150;
|
|
maxspeed = 50.;
|
|
A_PlaySound("eightball/fly",CHAN_VOICE,1.,true,1.5,pitch:.85);
|
|
}
|
|
action void A_FireballExplo2()
|
|
{
|
|
scale *= 2.;
|
|
A_Explode(GetMissileDamage(0,0),90);
|
|
UTMainHandler.DoBlast(self,90,12000);
|
|
Vector3 dir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
|
int numpt = Random[ExploS](10,15);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (dir*3+(FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1))).unit()*FRandom[ExploS](4,9);
|
|
let s = Spawn("UTSmoke",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[ExploS](1.9,2.5);
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](32,64));
|
|
}
|
|
Vector3 HitNormal = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
|
if ( BlockingLine )
|
|
{
|
|
HitNormal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
|
|
if ( CurSector == BlockingLine.frontsector ) HitNormal *= -1;
|
|
}
|
|
else if ( BlockingFloor )
|
|
{
|
|
// find closest 3d floor for its normal
|
|
F3DFloor ff = null;
|
|
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
|
|
ff = BlockingFloor.Get3DFloor(i);
|
|
break;
|
|
}
|
|
if ( ff ) HitNormal = -ff.top.Normal;
|
|
else HitNormal = BlockingFloor.floorplane.Normal;
|
|
}
|
|
else if ( BlockingCeiling )
|
|
{
|
|
// find closest 3d floor for its normal
|
|
F3DFloor ff = null;
|
|
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
|
|
ff = BlockingCeiling.Get3DFloor(i);
|
|
break;
|
|
}
|
|
if ( ff ) HitNormal = -ff.bottom.Normal;
|
|
else HitNormal = BlockingCeiling.ceilingplane.Normal;
|
|
}
|
|
for ( int i=0; i<20; i++ )
|
|
{
|
|
dir = (HitNormal*1.1+(FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1))).unit();
|
|
let s = Spawn("UFireballEmber",level.Vec3Offset(pos,HitNormal*2));
|
|
s.vel = dir*s.speed*FRandom[ExploS](0.6,1.8);
|
|
s.angle = atan2(dir.y,dir.x);
|
|
s.pitch = asin(-dir.z);
|
|
s.target = target;
|
|
s.bHITOWNER = true;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Death:
|
|
TNT1 A 0 A_FireballExplo2();
|
|
Goto Super::Death;
|
|
}
|
|
}
|
|
|
|
Class UFireballEmber : UFireball
|
|
{
|
|
Default
|
|
{
|
|
DamageFunction 5;
|
|
+AMBUSH;
|
|
-NOGRAVITY;
|
|
Gravity 0.3;
|
|
Speed 8;
|
|
UFireball.SpreadFactor 0.5;
|
|
UFireball.NumSmokes 1;
|
|
UFireball.NumSparks 1;
|
|
DeathSound "";
|
|
}
|
|
States
|
|
{
|
|
Death:
|
|
TNT1 A 0
|
|
{
|
|
Scale *= 0.4;
|
|
}
|
|
Goto Super::Death;
|
|
}
|
|
}
|
|
|
|
Class FlameGun : UnrealWeapon
|
|
{
|
|
bool bCharging;
|
|
|
|
Default
|
|
{
|
|
Tag "$T_FLAMEGUN";
|
|
Inventory.PickupMessage "$I_FLAMEGUN";
|
|
Weapon.UpSound "flamegun/select";
|
|
Weapon.SlotNumber 5;
|
|
Weapon.SelectionOrder 1200;
|
|
Weapon.SlotPriority 0.9;
|
|
Weapon.AmmoType "FlameAmmo";
|
|
Weapon.AmmoUse 10;
|
|
Weapon.AmmoType2 "FlameAmmo";
|
|
Weapon.AmmoUse2 20;
|
|
Weapon.AmmoGive 100;
|
|
UTWeapon.DropAmmo 50;
|
|
}
|
|
override bool TryPickup( in out Actor toucher )
|
|
{
|
|
if ( !sting_proto ) return false; // not allowed
|
|
return Super.TryPickup(toucher);
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( sting_proto ) return;
|
|
if ( !Owner )
|
|
{
|
|
let r = Spawn("RocketLauncher",pos,ALLOW_REPLACE);
|
|
r.spawnangle = spawnangle;
|
|
r.spawnpoint = spawnpoint;
|
|
r.angle = angle;
|
|
r.pitch = pitch;
|
|
r.roll = roll;
|
|
r.special = special;
|
|
r.args[0] = args[0];
|
|
r.args[1] = args[1];
|
|
r.args[2] = args[2];
|
|
r.args[3] = args[3];
|
|
r.args[4] = args[4];
|
|
r.ChangeTid(tid);
|
|
r.SpawnFlags = SpawnFlags&~MTF_SECRET;
|
|
r.HandleSpawnFlags();
|
|
r.SpawnFlags = SpawnFlags;
|
|
r.bCountSecret = SpawnFlags&MTF_SECRET;
|
|
r.vel = vel;
|
|
r.master = master;
|
|
r.target = target;
|
|
r.tracer = tracer;
|
|
r.bDropped = bDropped;
|
|
Destroy();
|
|
}
|
|
else
|
|
{
|
|
Owner.RemoveInventory(self);
|
|
Destroy();
|
|
}
|
|
}
|
|
action void A_FlameGunFire( bool bAlt = false )
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap ) return;
|
|
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
|
A_PlaySound(bAlt?"flamegun/alt":"flamegun/fire",CHAN_WEAPON,Dampener.Active(self)?.2:1.);
|
|
invoker.FireEffect();
|
|
UTMainHandler.DoFlash(self,Color(32,96,255,0),1);
|
|
if ( bAlt )
|
|
{
|
|
A_QuakeEx(2,2,2,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
|
|
UTMainHandler.DoSwing(self,(FRandom[FlameGun](-0.6,-0.5),FRandom[FlameGun](-0.3,0.3)),4,-1,5,SWING_Spring,3,2.5);
|
|
}
|
|
else
|
|
{
|
|
A_QuakeEx(1,1,1,2,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
|
|
UTMainHandler.DoSwing(self,(FRandom[FlameGun](-0.3,-0.2),FRandom[FlameGun](-0.2,0.2)),4,-1,3,SWING_Spring,2,2);
|
|
}
|
|
if ( !Dampener.Active(self) ) A_AlertMonsters();
|
|
Vector3 x, y, z, x2, y2, z2, dir;
|
|
double a, s;
|
|
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+3*y-z);
|
|
[x2, y2, z2] = dt_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
|
for ( int i=0; i<(bAlt?1:3); i++ )
|
|
{
|
|
a = FRandom[FlameGun](0,360);
|
|
s = FRandom[FlameGun](0,bAlt?0.:.06);
|
|
dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
|
|
let p = Spawn(bAlt?"UFireball2":"UFireball",origin);
|
|
p.angle = atan2(dir.y,dir.x);
|
|
p.pitch = asin(-dir.z);
|
|
p.vel = dir*p.speed;
|
|
p.target = self;
|
|
}
|
|
int numpt = Random[FlameGun](10,15);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
let s = Spawn("UTViewSpark",origin);
|
|
UTViewSpark(s).ofs = (10,3,-1);
|
|
UTViewSpark(s).vvel = (FRandom[FlameGun](3,12),FRandom[FlameGun](-2,2),FRandom[FFlameGun](-2,2));
|
|
s.target = self;
|
|
s.A_SetTranslation('FlamGSpark');
|
|
}
|
|
for ( int i=0; i<8; i++ )
|
|
{
|
|
let s = Spawn("UTViewSmoke",origin);
|
|
UTViewSmoke(s).ofs = (10,3,-1);
|
|
UTViewSmoke(s).vvel = (FRandom[FlameGun](0,1.2),FRandom[FlameGun](-.3,.3),FRandom[FlameGun](-.3,.3));
|
|
s.target = self;
|
|
s.scale *= 1.6;
|
|
s.alpha *= 0.5;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FGNP A -1;
|
|
Stop;
|
|
FGNP B -1;
|
|
Stop;
|
|
Select:
|
|
FGNS A 1 A_Raise(int.max);
|
|
Wait;
|
|
Ready:
|
|
FGNS ABCDEFGHIJ 2 A_WeaponReady(WRF_NOFIRE);
|
|
Goto Idle;
|
|
Dummy:
|
|
TNT1 A 1
|
|
{
|
|
A_CheckReload();
|
|
int flags = (waterlevel>=2)?WRF_NOFIRE:0;
|
|
if ( invoker.Ammo1.Amount < 30 )
|
|
flags |= WRF_NOSECONDARY;
|
|
A_WeaponReady(flags);
|
|
}
|
|
Wait;
|
|
Idle:
|
|
FGNI A 0 A_Overlay(-9999,"Dummy");
|
|
FGNI ABCDEFG 12;
|
|
FGNI A 0 A_Jump(40,"Twiddle");
|
|
Goto Idle+1;
|
|
Twiddle:
|
|
#### # 2 A_PlaySound("flamegun/idle",CHAN_6,Dampener.Active(self)?.1:1.);
|
|
FGNT ABCDEFGHIJKLM 3;
|
|
Goto Idle+1;
|
|
Fire:
|
|
#### # 1 A_Overlay(-9999,"Null");
|
|
FGNF A 2
|
|
{
|
|
invoker.special1 = 0;
|
|
A_PlaySound("flamegun/start",CHAN_6,Dampener.Active(self)?.1:1.);
|
|
if ( !Dampener.Active(self) ) A_AlertMonsters();
|
|
}
|
|
Hold:
|
|
FGNF B 1 A_FlameGunFire();
|
|
FGNF CDEFG 1;
|
|
FGNF H 0
|
|
{
|
|
invoker.special1++;
|
|
if ( invoker.CheckAmmo(0,false,true) && (waterlevel < 2) && (invoker.special1 < 3) )
|
|
A_Refire("Refire");
|
|
}
|
|
FGNF H 0 A_ClearRefire();
|
|
FGNF HIJ 2;
|
|
FGNT A 0
|
|
{
|
|
if ( invoker.CheckAmmo(0,false,true) && (waterlevel < 2) && (invoker.special1 < 3) )
|
|
A_Refire("Fire");
|
|
}
|
|
FGNT A 0
|
|
{
|
|
invoker.special1 = 0;
|
|
A_PlaySound("flamegun/end",CHAN_6,Dampener.Active(self)?.1:1.);
|
|
A_ClearRefire();
|
|
}
|
|
FGNT ABCDEFGHIJKLM 2;
|
|
Goto Idle;
|
|
Refire:
|
|
FGNF H 2 A_PlaySound("flamegun/start",CHAN_6,Dampener.Active(self)?.1:1.);
|
|
Goto Hold;
|
|
AltFire:
|
|
#### # 1 A_Overlay(-9999,"Null");
|
|
FGNF A 1
|
|
{
|
|
A_PlaySound("flamegun/charge",CHAN_WEAPON,Dampener.Active(self)?.1:1.);
|
|
if ( !Dampener.Active(self) ) A_AlertMonsters();
|
|
}
|
|
FGNF A 1
|
|
{
|
|
invoker.special1++;
|
|
A_WeaponOffset(FRandom[FlameGun](-.1,.1)*invoker.special1,32+FRandom[FlameGun](-.1,.1)*invoker.special1);
|
|
return A_JumpIf(invoker.special1>40,"AltRelease");
|
|
}
|
|
Wait;
|
|
AltRelease:
|
|
FGNF B 2
|
|
{
|
|
invoker.special1 = 0;
|
|
A_WeaponOffset(0,32);
|
|
A_FlameGunFire(true);
|
|
}
|
|
FGNF CDEFGHIJ 2;
|
|
FGNT ABCDEFGHIJKLM 2;
|
|
Goto Idle;
|
|
Deselect:
|
|
FGND A 1 A_Overlay(-9999,"Null");
|
|
FGND BCDEFGHIJ 1;
|
|
FGND J 1 A_Lower(int.max);
|
|
Wait;
|
|
}
|
|
}
|