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 25;
|
|
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;
|
|
}
|
|
}
|