Sentry no longer causes a freeze if it runs out of ammo while still having a target. Sentry now has to be recalled by using the item. Hijacking a sentry now immediately assigns it to your inventory. You can hijack rogue sentries (not owned by anyone). Better placement check for forcefield and sentry spawning, no more "no room" messages when it can definitely fit. Increased flak slug explosion sprite size, as it felt too small. Eightball loads faster (slightly faster than vanilla but can't do anything about that). ASMD combo no longer spawns amped explosions when it shouldn't. Added a new flag to UnrealInventory, bDRAWSPECIAL, so the HUD displays the special1 as an amount. This is useful for items like the Sentry that use this variable to count ammo. Increased rotation range for the Sentry so it's harder for enemies to sneak behind it from the sides. Added debris to the explosions of flares and voice boxes.
364 lines
9.7 KiB
Text
364 lines
9.7 KiB
Text
Class UFlakBox : Ammo
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_FLAKAMMO";
|
|
Inventory.Icon "I_FlakAm";
|
|
Inventory.PickupMessage "";
|
|
Inventory.Amount 10;
|
|
Inventory.MaxAmount 50;
|
|
Ammo.BackpackAmount 5;
|
|
Ammo.BackpackMaxAmount 100;
|
|
Ammo.DropAmount 5;
|
|
}
|
|
override String PickupMessage()
|
|
{
|
|
if ( PickupMsg.Length() > 0 ) return Super.PickupMessage();
|
|
return String.Format("%s%d%s",StringTable.Localize("$I_FLAKAMMOL"),Amount,StringTable.Localize("$I_FLAKAMMOR"));
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FAMO A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UFlakAmmo : UFlakBox
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_FLAKAMMO2";
|
|
Inventory.Icon "I_FlakAm";
|
|
Inventory.PickupMessage "$I_FLAKAMMO2";
|
|
Inventory.Amount 1;
|
|
Ammo.DropAmount 1;
|
|
+INVENTORY.IGNORESKILL;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FAMO B -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
// subclass to save time, much of the behavior is the same anyway
|
|
Class UFlakChunk : FlakChunk
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
Actor.PostBeginPlay();
|
|
// no trail, spin much slower
|
|
lifetime = 0;
|
|
rollvel = FRandom[Flak](5,10)*RandomPick[Flak](-1,1);
|
|
pitchvel = FRandom[Flak](5,10)*RandomPick[Flak](-1,1);
|
|
yawvel = FRandom[Flak](5,10)*RandomPick[Flak](-1,1);
|
|
scale *= Frandom[Flak](0.8,1.2);
|
|
SetState(ResolveState("Spawn")+Random[Flak](0,3));
|
|
}
|
|
override void Tick()
|
|
{
|
|
oldvel = vel;
|
|
Actor.Tick();
|
|
if ( isFrozen() ) return;
|
|
// no slowing down in water, only set to falling
|
|
if ( waterlevel > 0 )
|
|
{
|
|
bNOGRAVITY = false;
|
|
bAMBUSH = true;
|
|
}
|
|
lifetime += lifespeed;
|
|
// no frame changes, smoke based on speed + age
|
|
if ( (waterlevel <= 0) && !bAMBUSH && !(GetAge()%2) )
|
|
{
|
|
let s = Spawn("UTSmoke",pos);
|
|
s.vel = (FRandom[Flak](-0.1,0.1),FRandom[Flak](-0.1,0.1),FRandom[Flak](-0.1,0.1));
|
|
s.alpha = (scale.x*clamp((120-GetAge())/120.+(vel.length()/20.),0.5,2.0))/0.5;
|
|
s.SetShade("AAAAAA");
|
|
}
|
|
else if ( waterlevel > 0 )
|
|
{
|
|
let s = Spawn("UTBubble",pos);
|
|
s.vel = (FRandom[Flak](-0.1,0.1),FRandom[Flak](-0.1,0.1),FRandom[Flak](-0.1,0.1));
|
|
s.scale *= scale.x*0.5;
|
|
}
|
|
if ( InStateSequence(CurState,FindState("Death")) ) return;
|
|
roll += rollvel;
|
|
pitch += pitchvel;
|
|
angle += pitchvel;
|
|
}
|
|
Default
|
|
{
|
|
DamageFunction 17; // exactly 1 point higher than UT
|
|
Scale 0.5;
|
|
}
|
|
States
|
|
{
|
|
Bounce:
|
|
#### # 0
|
|
{
|
|
A_HandleBounce();
|
|
// override spin velocity changes from parent class
|
|
rollvel = FRandom[Flak](5,10)*RandomPick[Flak](-1,1);
|
|
pitchvel = FRandom[Flak](5,10)*RandomPick[Flak](-1,1);
|
|
yawvel = FRandom[Flak](5,10)*RandomPick[Flak](-1,1);
|
|
}
|
|
Goto Idle;
|
|
}
|
|
}
|
|
|
|
// Also subclassed to save time, only the explosion needs to change
|
|
Class UFlakSlug : FlakSlug
|
|
{
|
|
action void A_UFlakExplode()
|
|
{
|
|
bForceXYBillboard = true;
|
|
A_SetRenderStyle(1.0,STYLE_Add);
|
|
A_SprayDecal("RocketBlast",50);
|
|
A_NoGravity();
|
|
A_SetScale(2.2);
|
|
UTMainHandler.DoBlast(self,120,75000);
|
|
A_Explode(70,120);
|
|
A_QuakeEx(4,4,4,8,0,170,"",QF_RELATIVE|QF_SCALEDOWN,falloff:120,rollIntensity:0.2);
|
|
A_PlaySound("flak/explode",CHAN_VOICE);
|
|
A_AlertMonsters();
|
|
if ( !Tracer ) Spawn("SlugSmoke",pos);
|
|
Spawn("SlugLight",pos);
|
|
Vector3 x, y, z;
|
|
double a, s;
|
|
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
|
|
Actor p;
|
|
Vector3 spawnofs;
|
|
if ( BlockingMobj ) spawnofs = level.Vec3Diff(pos,BlockingMobj.Vec3Offset(0,0,BlockingMobj.height/2)).unit()*8;
|
|
else if ( BlockingFloor ) spawnofs = BlockingFloor.floorplane.Normal*8;
|
|
else if ( BlockingCeiling ) spawnofs = BlockingCeiling.ceilingplane.Normal*8;
|
|
else if ( BlockingLine )
|
|
{
|
|
spawnofs = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit()*8;
|
|
if ( !BlockingLine.sidedef[1] || (CurSector == BlockingLine.frontsector) )
|
|
spawnofs *= -1;
|
|
}
|
|
for ( int i=0; i<5; i++ )
|
|
{
|
|
p = Spawn("UFlakChunk",Vec3Offset(spawnofs.x,spawnofs.y,spawnofs.z));
|
|
p.bHITOWNER = true;
|
|
a = FRandom[Flak](0,360);
|
|
s = FRandom[Flak](0,0.1);
|
|
Vector3 dir = (x+y*cos(a)*s+z*sin(a)*s).unit();
|
|
p.angle = atan2(dir.y,dir.x);
|
|
p.pitch = -asin(dir.z);
|
|
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*(p.speed+FRandom[Flak](-3,3));
|
|
p.target = target;
|
|
}
|
|
int numpt = Random[Flak](8,12);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Flak](-1,1),FRandom[Flak](-1,1),FRandom[Flak](-1,1)).unit()*FRandom[Flak](2,8);
|
|
let s = Spawn("UTSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Flak](15,30);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Flak](-1,1),FRandom[Flak](-1,1),FRandom[Flak](-1,1)).unit()*FRandom[Flak](6,16);
|
|
let s = Spawn("UTChip",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[Flak](0.9,1.8);
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Death:
|
|
FEXP A 0 A_UFlakExplode();
|
|
FEXP ABCDEFGHIJ 2 BRIGHT;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UFlakCannon : UnrealWeapon
|
|
{
|
|
action void A_Loading( bool first = false )
|
|
{
|
|
if ( first ) A_PlaySound("flak/load",CHAN_WEAPON,Dampener.Active(self)?.1:1.);
|
|
else A_PlaySound("flak/reload",CHAN_6,Dampener.Active(self)?.06:.6);
|
|
}
|
|
action void A_FireChunks()
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap ) return;
|
|
if ( weap.Ammo1.Amount <= 0 ) return;
|
|
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
|
A_PlaySound("flak/fire",CHAN_WEAPON,Dampener.Active(self)?.2:1.);
|
|
A_Overlay(PSP_FLASH,"Flash");
|
|
A_OverlayFlags(PSP_FLASH,PSPF_RenderStyle,true);
|
|
A_OverlayRenderstyle(PSP_FLASH,STYLE_Add);
|
|
invoker.FireEffect();
|
|
UTMainHandler.DoFlash(self,Color(48,255,96,0),1);
|
|
UTMainHandler.DoSwing(self,(FRandom[Flak](-0.3,-0.8),FRandom[Flak](-0.5,0.5)),4,-1.5,2,SWING_Spring,2,2);
|
|
if ( !Dampener.Active(self) ) A_AlertMonsters();
|
|
A_QuakeEx(1,1,1,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.05);
|
|
Vector3 x, y, z;
|
|
double a, s;
|
|
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+5.0*y-4.0*z;
|
|
[x, y, z] = dt_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
|
Vector3 offsets[8]; // vanilla adds these to each chunk
|
|
offsets[0] = (0,0,0);
|
|
offsets[1] = -z;
|
|
offsets[2] = 2*y+z;
|
|
offsets[3] = -y;
|
|
offsets[4] = 2*y-z;
|
|
offsets[5] = (0,0,0);
|
|
offsets[6] = y-z;
|
|
offsets[7] = 2*y+z;
|
|
Actor p;
|
|
for ( int i=0; i<8; i++ )
|
|
{
|
|
p = Spawn("UFlakChunk",level.Vec3Offset(origin,offsets[i]));
|
|
a = FRandom[Flak](0,360);
|
|
s = FRandom[Flak](0,0.1);
|
|
Vector3 dir = (x+y*cos(a)*s+z*sin(a)*s).unit();
|
|
p.angle = atan2(dir.y,dir.x);
|
|
p.pitch = -asin(dir.z);
|
|
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*(p.speed+FRandom[Flak](-3,3));
|
|
p.target = self;
|
|
}
|
|
int numpt = Random[Flak](20,30);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
let s = Spawn("UTViewSpark",origin);
|
|
UTViewSpark(s).ofs = (10,5,-4);
|
|
UTViewSpark(s).vvel = (FRandom[Flak](3,12),FRandom[Flak](-4,4),FRandom[Flak](-4,4));
|
|
s.target = self;
|
|
}
|
|
for ( int i=0; i<10; i++ )
|
|
{
|
|
let s = Spawn("UTViewSmoke",origin);
|
|
UTViewSmoke(s).ofs = (10,5,-4);
|
|
UTViewSmoke(s).vvel = (FRandom[Flak](0,1.2),FRandom[Flak](-.4,.4),FRandom[Flak](-.4,.4));
|
|
s.target = self;
|
|
s.scale *= 1.6;
|
|
s.alpha *= 0.5;
|
|
}
|
|
}
|
|
action void A_FireSlug()
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap ) return;
|
|
if ( weap.Ammo1.Amount <= 0 ) return;
|
|
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
|
A_PlaySound("flak/altfire",CHAN_WEAPON,Dampener.Active(self)?.2:1.);
|
|
A_Overlay(PSP_FLASH,"Flash");
|
|
A_OverlayFlags(PSP_FLASH,PSPF_RenderStyle,true);
|
|
A_OverlayRenderstyle(PSP_FLASH,STYLE_Add);
|
|
invoker.FireEffect();
|
|
UTMainHandler.DoFlash(self,Color(32,255,96,0),1);
|
|
UTMainHandler.DoSwing(self,(FRandom[Flak](-0.4,-0.8),FRandom[Flak](0.4,0.8)),4,-1,3,SWING_Spring,3,5);
|
|
if ( !Dampener.Active(self) ) A_AlertMonsters();
|
|
A_QuakeEx(2,2,2,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
|
|
Vector3 x, y, z;
|
|
double a, s;
|
|
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+5.0*y-4.0*z;
|
|
Actor p = Spawn("UFlakSlug",origin);
|
|
p.angle = angle;
|
|
p.pitch = BulletSlope();
|
|
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
|
|
p.target = self;
|
|
int numpt = Random[Flak](10,15);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
let s = Spawn("UTViewSpark",origin);
|
|
UTViewSpark(s).ofs = (10,5,-4);
|
|
UTViewSpark(s).vvel = (FRandom[Flak](3,12),FRandom[Flak](-4,4),FRandom[Flak](-4,4));
|
|
s.target = self;
|
|
}
|
|
for ( int i=0; i<8; i++ )
|
|
{
|
|
let s = Spawn("UTViewSmoke",origin);
|
|
UTViewSmoke(s).ofs = (10,5,-4);
|
|
UTViewSmoke(s).vvel = (FRandom[Flak](0,1.2),FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8));
|
|
s.target = self;
|
|
s.scale *= 1.6;
|
|
s.alpha *= 0.5;
|
|
}
|
|
}
|
|
Default
|
|
{
|
|
Tag "$T_FLAKCANNON";
|
|
Inventory.PickupMessage "$I_FLAKCANNON";
|
|
Weapon.UpSound "flak/select";
|
|
Weapon.SlotNumber 6;
|
|
Weapon.SelectionOrder 4;
|
|
Weapon.AmmoType "UFlakBox";
|
|
Weapon.AmmoUse 1;
|
|
Weapon.AmmoType2 "UFlakBox";
|
|
Weapon.AmmoUse2 1;
|
|
Weapon.AmmoGive 10;
|
|
UTWeapon.DropAmmo 5;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FPCK A -1;
|
|
Stop;
|
|
FPCK B -1;
|
|
Stop;
|
|
Select:
|
|
FLKS A 1 A_Raise(int.max);
|
|
Wait;
|
|
Ready:
|
|
FLKS ABCDFGHIKLMNPQRSUVWXZ 1 A_WeaponReady(WRF_NOFIRE);
|
|
FLS2 ABC 1 A_WeaponReady(WRF_NOFIRE);
|
|
FLKL A 1 A_Loading(true);
|
|
FLKL BCEFGIJKMNO 1;
|
|
Goto Idle;
|
|
Loading:
|
|
FLKL A 1
|
|
{
|
|
A_CheckReload();
|
|
if ( invoker.Ammo1.Amount > 0 ) A_Loading();
|
|
}
|
|
FLKL BCEFGIJKMNO 1;
|
|
Goto Idle;
|
|
Idle:
|
|
FLKI A 1 A_WeaponReady();
|
|
Wait;
|
|
Fire:
|
|
FLKF A 1 A_FireChunks();
|
|
FLKF BCDEFGHI 1;
|
|
FLKF J 5;
|
|
FLKE A 1 A_PlaySound("flak/click",CHAN_6,Dampener.Active(self)?.05:.5);
|
|
FLKE BCDEFGHIJKLMN 1;
|
|
FLKE S 4;
|
|
Goto Loading;
|
|
AltFire:
|
|
FLKA A 1 A_FireSlug();
|
|
FLKA BCDEFGHIJK 1;
|
|
FLKA K 10;
|
|
Goto Loading;
|
|
Deselect:
|
|
FLKD A 0 A_JumpIfNoAmmo("Deselect2");
|
|
FLKD ABCDEF 1;
|
|
FLKD F 1 A_Lower(int.max);
|
|
Wait;
|
|
Deselect2:
|
|
FLD2 ABCDEF 1;
|
|
FLD2 F 1 A_Lower(int.max);
|
|
Wait;
|
|
Flash:
|
|
FMUZ A 3 Bright
|
|
{
|
|
let l = Spawn("FlakLight",pos);
|
|
l.target = self;
|
|
}
|
|
Stop;
|
|
/*Flash:
|
|
FLFF ABCDEFGHIJ 1 Bright;
|
|
Stop;
|
|
AltFlash:
|
|
FLFA ABCDEF 1 Bright;
|
|
Stop;*/
|
|
}
|
|
}
|