- Various fixes for the Combined Patch. - Some safeguards for force field and sentries so they don't bug the hell out if receiving crushing or ice damage.
242 lines
6.6 KiB
Text
242 lines
6.6 KiB
Text
Class UMiniAmmo : Ammo
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_MINIAMMO";
|
|
Inventory.Icon "I_ShellA";
|
|
Inventory.PickupMessage "";
|
|
Inventory.Amount 50;
|
|
Inventory.MaxAmount 200;
|
|
Ammo.BackpackAmount 25;
|
|
Ammo.BackpackMaxAmount 400;
|
|
Ammo.DropAmount 20;
|
|
}
|
|
override String PickupMessage()
|
|
{
|
|
if ( PickupMsg.Length() > 0 ) return Super.PickupMessage();
|
|
return String.Format("%s%d%s",StringTable.Localize("$I_MINIAMMOL"),Amount,StringTable.Localize("$I_MINIAMMOR"));
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
MAMO A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UMinigun : UnrealWeapon
|
|
{
|
|
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);
|
|
if ( !Dampener.Active(self) ) A_AlertMonsters();
|
|
A_SoundVolume(CHAN_WEAPON,Dampener.Active(self)?.1:1.);
|
|
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,2,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,2,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*3-z*3);
|
|
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);
|
|
UTBulletTrail.DoTrail(self,origin,dir,10000,alt?5:3);
|
|
if ( d.HitType == TRACE_HitActor )
|
|
{
|
|
int dmg = Random[Minigun](8,14); // fun fact: the Minigun is one of the few weapons that has actual RNG damage in Unreal
|
|
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.;
|
|
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,3,-3);
|
|
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*4+y*3-z*12);
|
|
let c = Spawn("UCasing",origin);
|
|
c.angle = angle;
|
|
c.pitch = pitch;
|
|
c.vel = x*FRandom[Junk](-1.5,1.5)-y*FRandom[Junk](2,4)+z*FRandom[Junk](-2,1);
|
|
}
|
|
|
|
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);
|
|
invoker.bcnt = 5;
|
|
A_Refire("Hold");
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_MINIGUN";
|
|
Inventory.PickupMessage "$I_MINIGUN";
|
|
Weapon.UpSound "umini/select";
|
|
Weapon.SlotNumber 0;
|
|
Weapon.SelectionOrder 500;
|
|
Weapon.SlotPriority 1;
|
|
Weapon.AmmoType "UMiniAmmo";
|
|
Weapon.AmmoUse 1;
|
|
Weapon.AmmoType2 "UMiniAmmo";
|
|
Weapon.AmmoUse2 1;
|
|
Weapon.AmmoGive 50;
|
|
UTWeapon.DropAmmo 25;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
MGNP A -1;
|
|
Stop;
|
|
MGNP B -1;
|
|
Stop;
|
|
Select:
|
|
MGNS A 1 A_Raise(int.max);
|
|
Wait;
|
|
Ready:
|
|
MGNS ABCDEFGHIJKLMNOPQRSTUVW 1 A_WeaponReady(WRF_NOFIRE);
|
|
Idle:
|
|
MGNI A 1
|
|
{
|
|
A_CheckReload();
|
|
A_WeaponReady();
|
|
}
|
|
Wait;
|
|
FireDummy:
|
|
TNT1 A 1
|
|
{
|
|
if ( Health <= 0 ) return ResolveState("Null");
|
|
let weap = Weapon(invoker);
|
|
if ( !(player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK)) || (weap.Ammo1.Amount <= 0) )
|
|
{
|
|
A_StopSound(CHAN_WEAPON);
|
|
player.SetPSprite(PSP_WEAPON,invoker.FindState("Release"));
|
|
return ResolveState("Null");
|
|
}
|
|
return ResolveState(null);
|
|
}
|
|
Wait;
|
|
Fire:
|
|
AltFire:
|
|
MGNW A 0 A_PlaySound("umini/wind",CHAN_WEAPON,Dampener.Active(self)?.1:1.);
|
|
MGNW ABCDEFGHIJKLMNO 1;
|
|
MGNW O 0
|
|
{
|
|
invoker.bcnt = 5;
|
|
A_Refire(1);
|
|
}
|
|
Goto Release;
|
|
Hold:
|
|
MGNF A 0
|
|
{
|
|
A_Overlay(-9999,"FireDummy");
|
|
A_PlaySound("umini/fire",CHAN_WEAPON,Dampener.Active(self)?.1:1.,true);
|
|
}
|
|
MGNF ABCDEFGHIJKLMNO 1 A_FireBullet(false);
|
|
MGNF A 0 A_JumpIf(player.cmd.buttons&BT_ALTATTACK,1);
|
|
Goto Hold+1;
|
|
AltHold:
|
|
MGNA A 0
|
|
{
|
|
A_Overlay(-9999,"FireDummy");
|
|
A_PlaySound("umini/altfire",CHAN_WEAPON,Dampener.Active(self)?.1:1.,true);
|
|
}
|
|
MGNA ABCDEFGHIJKLMNOPQRST 1 A_FireBullet(true);
|
|
Goto AltHold+1;
|
|
Release:
|
|
MGNU A 0 A_PlaySound("umini/unwind",CHAN_WEAPON,Dampener.Active(self)?.1:1.);
|
|
MGNU ABCDEFGHIJKLMNO 2 A_MinigunRefire();
|
|
Goto Idle;
|
|
Deselect:
|
|
MGND A 0 A_StopSound(CHAN_WEAPON);
|
|
MGND ABCDEFGHIJ 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;
|
|
}
|
|
}
|