Got rid of the deprecated Matrix4.GetAxes method. Next step is to get rid of more stuff by migrating to libeye. Mirrored Translocator model so it shows the actually detailed side. At some point in UT's development it got flipped around for some reason. Weapon code cleanup (most noticeable on states). Backported scope shader from Doomreal. Added optional "dummied out" Sniper zoom sounds from a dubious source.
272 lines
6.7 KiB
Text
272 lines
6.7 KiB
Text
Class MiniAmmo : Ammo
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_MINIAMMO";
|
|
Inventory.PickupMessage "";
|
|
Inventory.Amount 50;
|
|
Inventory.MaxAmount 200;
|
|
Ammo.BackpackAmount 100;
|
|
Ammo.BackpackMaxAmount 400;
|
|
Ammo.DropAmount 20;
|
|
}
|
|
override String PickupMessage()
|
|
{
|
|
return String.Format("%s%d%s",StringTable.Localize("$I_MINIAMMOL"),Amount,StringTable.Localize("$I_MINIAMMOR"));
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
MAMO A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class MinigunLight : EnforcerLight
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
args[LIGHT_INTENSITY] = Random[Minigun](120,180);
|
|
}
|
|
}
|
|
|
|
Class MinigunTracer : Actor
|
|
{
|
|
Vector3 dest;
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOCLIP;
|
|
+NOGRAVITY;
|
|
+DONTSPLASH;
|
|
+INTERPOLATEANGLES;
|
|
+NOTELEPORT;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( isFrozen() ) return;
|
|
Vector3 dir = level.Vec3Diff(pos,dest);
|
|
if ( dir.length() < 160 )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
dir = dir.unit();
|
|
SetOrigin(level.Vec3Offset(pos,dir*160),true);
|
|
angle = atan2(dir.y,dir.x);
|
|
pitch = asin(-dir.z);
|
|
roll += 60;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TRAC A -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class Minigun : UTWeapon
|
|
{
|
|
int bcnt, tcnt;
|
|
|
|
action void A_FireBullet( bool alt = false )
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap ) return;
|
|
if ( weap.Ammo1.Amount <= 0 ) return;
|
|
A_Overlay(-2,"MuzzleFlash",true);
|
|
A_OverlayFlags(-2,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true);
|
|
A_OverlayRenderstyle(-2,STYLE_Add);
|
|
invoker.bcnt++;
|
|
if ( (alt && (invoker.bcnt < 2)) || (!alt && (invoker.bcnt < 4)) ) return;
|
|
invoker.bcnt = 0;
|
|
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
|
invoker.FireEffect();
|
|
UTMainHandler.DoFlash(self,Color(32,255,255,0),1);
|
|
A_AlertMonsters();
|
|
if ( alt )
|
|
{
|
|
A_QuakeEx(2,2,2,8,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.12);
|
|
UTMainHandler.DoSwing(self,(FRandom[Minigun](-1,1),FRandom[Minigun](-1,1)),0.5,0,1,SWING_Spring,0,3);
|
|
}
|
|
else
|
|
{
|
|
A_QuakeEx(1,1,1,8,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.08);
|
|
UTMainHandler.DoSwing(self,(FRandom[Minigun](-1,1),FRandom[Minigun](-1,1)),0.3,0,1,SWING_Spring,0,3);
|
|
}
|
|
let l = Spawn("MinigunLight",pos);
|
|
l.target = self;
|
|
if ( !alt ) MinigunLight(l).cnt--;
|
|
Vector3 x, y, z, x2, y2, z2;
|
|
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+y*2-z*2);
|
|
double a = FRandom[Minigun](0,360), s = FRandom[Minigun](0,alt?0.05:0.02);
|
|
[x2, y2, z2] = dt_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
|
Vector3 dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
|
|
FLineTraceData d;
|
|
LineTrace(atan2(dir.y,dir.x),10000,asin(-dir.z),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
|
|
if ( d.HitType == TRACE_HitActor )
|
|
{
|
|
int dmg = Random[Minigun](9,18); // 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|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x));
|
|
double mm = 500;
|
|
if ( FRandom[Minigun](0,1) < 0.2 ) mm *= 2.5;
|
|
UTMainHandler.DoKnockback(d.HitActor,d.HitDir,dmg*mm);
|
|
if ( d.HitActor.bNOBLOOD )
|
|
{
|
|
let p = Spawn("BulletImpact",d.HitLocation);
|
|
p.scale *= 0.75;
|
|
p.angle = atan2(d.HitDir.y,d.HitDir.x)+180;
|
|
p.pitch = asin(d.HitDir.z);
|
|
}
|
|
else
|
|
{
|
|
d.HitActor.TraceBleed(dmg,self);
|
|
d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg);
|
|
}
|
|
}
|
|
else if ( d.HitType != TRACE_HitNone )
|
|
{
|
|
Vector3 hitnormal = -d.HitDir;
|
|
if ( d.HitType == TRACE_HitFloor )
|
|
{
|
|
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.top.Normal;
|
|
else hitnormal = d.HitSector.floorplane.Normal;
|
|
}
|
|
else if ( d.HitType == TRACE_HitCeiling )
|
|
{
|
|
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.bottom.Normal;
|
|
else hitnormal = d.HitSector.ceilingplane.Normal;
|
|
}
|
|
else if ( d.HitType == TRACE_HitWall )
|
|
{
|
|
hitnormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
|
|
if ( !d.LineSide ) hitnormal *= -1;
|
|
}
|
|
let p = Spawn("BulletImpact",d.HitLocation+hitnormal*0.01);
|
|
p.scale *= 0.75;
|
|
p.angle = atan2(hitnormal.y,hitnormal.x);
|
|
p.pitch = asin(-hitnormal.z);
|
|
if ( d.HitLine ) d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation);
|
|
}
|
|
if ( !Random[Minigun](0,1) )
|
|
{
|
|
let t = Spawn("MinigunTracer",level.Vec3Offset(origin,x*20));
|
|
t.angle = atan2(dir.y,dir.x);
|
|
t.pitch = asin(-dir.z);
|
|
MinigunTracer(t).dest = d.HitLocation;
|
|
}
|
|
for ( int i=0; i<2; i++ )
|
|
{
|
|
let s = Spawn("UTViewSmoke",origin);
|
|
UTViewSmoke(s).ofs = (10,2,-2);
|
|
s.scale *= 1.5;
|
|
s.alpha *= 0.6;
|
|
UTViewSmoke(s).vvel += (FRandom[Minigun](0.2,0.8),FRandom[Minigun](-0.3,0.3),FRandom[Minigun](-0.3,0.3));
|
|
s.target = self;
|
|
}
|
|
origin = level.Vec3Offset(origin,x*8+y*5-z*5);
|
|
let c = Spawn("UTCasing",origin);
|
|
c.vel = x*FRandom[Junk](-1.5,1.5)+y*FRandom[Junk](2,4)+z*FRandom[Junk](2,3);
|
|
c.Scale *= 0.5;
|
|
}
|
|
|
|
action void A_MinigunRefire()
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap || !player ) return;
|
|
if ( weap.Ammo1.Amount <= 0 )
|
|
{
|
|
A_ClearRefire();
|
|
return;
|
|
}
|
|
weap.bAltFire = !!(player.cmd.buttons&BT_ALTATTACK);
|
|
A_Refire("Hold");
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_MINIGUN";
|
|
Obituary "$O_MINIGUN";
|
|
Inventory.PickupMessage "$I_MINIGUN";
|
|
Weapon.UpSound "minigun/select";
|
|
Weapon.SlotNumber 7;
|
|
Weapon.SelectionOrder 3;
|
|
Weapon.AmmoType "MiniAmmo";
|
|
Weapon.AmmoUse 1;
|
|
Weapon.AmmoType2 "MiniAmmo";
|
|
Weapon.AmmoUse2 1;
|
|
Weapon.AmmoGive 50;
|
|
Weapon.Kickback 180;
|
|
UTWeapon.DropAmmo 20;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
MGNP A -1;
|
|
Stop;
|
|
MGNP B -1;
|
|
Stop;
|
|
Select:
|
|
MGNS A 1 A_Raise(int.max);
|
|
Wait;
|
|
Ready:
|
|
MGNS ABCDEFGHIJKLMNOPQRST 1 A_WeaponReady(WRF_NOFIRE);
|
|
Idle:
|
|
MGNI A 1
|
|
{
|
|
A_CheckReload();
|
|
A_WeaponReady();
|
|
}
|
|
Wait;
|
|
FireDummy:
|
|
TNT1 A 1
|
|
{
|
|
let weap = Weapon(invoker);
|
|
if ( !(player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK)) || (weap.Ammo1.Amount <= 0) )
|
|
{
|
|
player.SetPSprite(PSP_WEAPON,invoker.FindState("Unwind"));
|
|
return ResolveState("Null");
|
|
}
|
|
return ResolveState(null);
|
|
}
|
|
Wait;
|
|
Fire:
|
|
AltFire:
|
|
MGNI A 3 { invoker.bcnt = 5; }
|
|
Hold:
|
|
MGNF A 0
|
|
{
|
|
A_PlaySound("minigun/fire",CHAN_WEAPON,1.0,true);
|
|
A_Overlay(-9999,"FireDummy");
|
|
}
|
|
MGNF ABCDEFGHIJKLMNOPQRS 1 A_FireBullet();
|
|
MGNF A 0 A_JumpIf(invoker.bAltFire,1);
|
|
Goto Hold+1;
|
|
AltHold:
|
|
MGNF B 0 A_PlaySound("minigun/altfire",CHAN_WEAPON,1.0,true);
|
|
MGNF ADGJMPSCFILORBEHKNQ 1 A_FireBullet(true);
|
|
Goto AltHold+1;
|
|
Unwind:
|
|
MGNU A 0 A_PlaySound("minigun/unwind",CHAN_WEAPON);
|
|
MGNU ABCDEFGHIJKLMNOPQRSTUVWXYZ 1 A_MinigunRefire();
|
|
MGU2 ABCDEFGHIJKLM 1 A_MinigunRefire();
|
|
Goto Idle;
|
|
Deselect:
|
|
MGND A 1 A_StopSound(CHAN_WEAPON);
|
|
MGND BCDEFGHIJ 1;
|
|
MGND J 1 A_Lower(int.max);
|
|
Wait;
|
|
MuzzleFlash:
|
|
MMUZ # 2 Bright
|
|
{
|
|
let psp = player.FindPSprite(OverlayID());
|
|
psp.frame = Random[Minigun](0,8);
|
|
}
|
|
Stop;
|
|
}
|
|
}
|