Prefixed mk_math classes for cross-compat with any other mods that use them. Fixed incorrect uses of gametic. Fixed crash caused by incorrect ordering of PendingWeapon checks.
299 lines
9 KiB
Text
299 lines
9 KiB
Text
Class HammerImpact : Actor
|
|
{
|
|
Default
|
|
{
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_SprayDecal("ImpactMark",20);
|
|
int numpt = Random[Impact](20,40);
|
|
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (-x+(FRandom[Impact](-.8,.8),FRandom[Impact](-.8,.8),FRandom[Impact](-.8,.8))).unit()*FRandom[Impact](0.1,1.2);
|
|
let s = Spawn("UTSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,1,1)*Random[Impact](128,192));
|
|
}
|
|
numpt = Random[Impact](4,12);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Impact](-1,1),FRandom[Impact](-1,1),FRandom[Impact](-1,1)).unit()*FRandom[Impact](2,8);
|
|
let s = Spawn("UTSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Impact](4,16);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Impact](-1,1),FRandom[Impact](-1,1),FRandom[Impact](-1,1)).unit()*FRandom[Impact](2,8);
|
|
let s = Spawn("UTChip",pos);
|
|
s.vel = pvel;
|
|
}
|
|
Destroy();
|
|
}
|
|
}
|
|
|
|
Class ImpactHammer : UTWeapon
|
|
{
|
|
double chargesize, count;
|
|
|
|
action void A_ResetCharge()
|
|
{
|
|
invoker.chargesize = 0;
|
|
invoker.count = 0;
|
|
invoker.FireEffect(); // intentional UT behavior
|
|
}
|
|
action void A_ChargeUp( int amt = 1 )
|
|
{
|
|
invoker.chargesize += (0.75*amt)/TICRATE;
|
|
invoker.count += double(amt)/TICRATE;
|
|
if ( invoker.count > 0.2 )
|
|
{
|
|
invoker.count = 0;
|
|
A_AlertMonsters();
|
|
}
|
|
A_QuakeEx(clamp(int(invoker.chargesize*3),0,3),clamp(int(invoker.chargesize*3),0,3),clamp(int(invoker.chargesize*3),0,3),amt+1,0,96,"",QF_RELATIVE,rollIntensity:clamp(invoker.chargesize*0.3,0,0.3));
|
|
UTMainHandler.DoSwing(self,(FRandom[Impact](-1,1),FRandom[Impact](-1,1)),invoker.chargesize*0.1,0,1,SWING_Spring);
|
|
}
|
|
action void A_FireBlast()
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap ) return;
|
|
A_PlaySound("impact/release",CHAN_WEAPON);
|
|
invoker.FireEffect();
|
|
UTMainHandler.DoSwing(self,(FRandom[Impact](-0.3,-1.5),FRandom[Impact](-1.2,-0.4)),3,-0.8,3,SWING_Spring,3,2);
|
|
A_AlertMonsters();
|
|
Vector3 x, y, z;
|
|
[x, y, z] = dt_Matrix4.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+3.0*y-4.0*z;
|
|
double realcharge = min(1.5,invoker.chargesize);
|
|
FLineTraceData d;
|
|
LineTrace(angle,60,BulletSlope(),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
|
|
if ( d.HitType == TRACE_HitActor )
|
|
{
|
|
int dmg = int(Random[Impact](90,120)*realcharge);
|
|
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'impact',DMG_THRUSTLESS);
|
|
d.HitActor.vel = x*(8000/d.HitActor.mass)*realcharge;
|
|
if ( d.HitActor.bNOBLOOD )
|
|
{
|
|
let p = Spawn("HammerImpact",d.HitLocation-d.HitDir*4);
|
|
p.angle = atan2(d.HitDir.y,d.HitDir.x);
|
|
p.pitch = asin(-d.HitDir.z);
|
|
}
|
|
else
|
|
{
|
|
d.HitActor.TraceBleed(dmg,invoker);
|
|
d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg);
|
|
}
|
|
}
|
|
else if ( d.HitType != TRACE_HitNone )
|
|
{
|
|
realcharge = max(1.0,realcharge);
|
|
int dmg = int(Random[Impact](16,24)*realcharge); // It's a flat damage of 36 on UT, but I think it's more fair for it to scale
|
|
dmg = DamageMobj(invoker,self,dmg,'impact',DMG_THRUSTLESS);
|
|
TraceBleed(dmg,invoker);
|
|
vel -= x*(1200/mass)*realcharge;
|
|
let p = Spawn("HammerImpact",d.HitLocation-d.HitDir*4);
|
|
p.angle = atan2(d.HitDir.y,d.HitDir.x);
|
|
p.pitch = asin(-d.HitDir.z);
|
|
if ( d.HitType == TRACE_HitWall ) d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation-d.HitDir*4);
|
|
}
|
|
A_QuakeEx(int(realcharge*6),int(realcharge*6),int(realcharge*6),16,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:realcharge*0.2);
|
|
realcharge = max(1.0,realcharge);
|
|
int numpt = Random[Impact](5,10);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (x+(FRandom[Impact](-.4,.4),FRandom[Impact](-.4,.4),FRandom[Impact](-.4,.4))).unit()*FRandom[Impact](1,3)*realcharge;
|
|
let s = Spawn("UTSmoke",origin);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,1,1)*Random[Impact](128,192));
|
|
}
|
|
numpt = Random[Impact](4,8);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (x+(FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5))).unit()*FRandom[Impact](2,16)*realcharge;
|
|
let s = Spawn("UTChip",origin);
|
|
s.vel = pvel;
|
|
s.scale *= 0.4;
|
|
}
|
|
}
|
|
action void A_FireAltBlast()
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap ) return;
|
|
A_PlaySound("impact/fire",CHAN_WEAPON);
|
|
invoker.FireEffect();
|
|
UTMainHandler.DoSwing(self,(FRandom[Impact](-0.3,-1.5),FRandom[Impact](-1.2,-0.4)),2,-0.6,2,SWING_Spring,1,2);
|
|
A_AlertMonsters();
|
|
A_QuakeEx(2,2,2,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
|
|
Vector3 x, y, z;
|
|
[x, y, z] = dt_Matrix4.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+3.0*y-4.0*z;
|
|
FLineTraceData d;
|
|
LineTrace(angle,120,BulletSlope(),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
|
|
double dscale = d.Distance/120.;
|
|
if ( d.HitType == TRACE_HitActor )
|
|
{
|
|
int dmg = int(Random[Impact](25,35)*dscale);
|
|
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'impact',DMG_THRUSTLESS);
|
|
d.HitActor.vel = x*(4000/d.HitActor.mass)*dscale;
|
|
}
|
|
else if ( d.HitType != TRACE_HitNone )
|
|
{
|
|
int dmg = int(Random[Impact](16,24)*dscale);
|
|
dmg = DamageMobj(invoker,self,dmg,'impact',DMG_THRUSTLESS);
|
|
vel -= x*(600/mass)*dscale;
|
|
if ( d.HitType == TRACE_HitWall ) d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation-d.HitDir*4);
|
|
}
|
|
// push aside projectiles
|
|
let t = ThinkerIterator.Create("Actor");
|
|
Actor m;
|
|
while ( m = Actor(t.Next()) )
|
|
{
|
|
if ( !m.bMISSILE ) continue;
|
|
double rdist = level.Vec3Diff(origin,m.pos).length();
|
|
Vector3 rdir = level.Vec3Diff(origin,m.pos).unit();
|
|
if ( LineTrace(atan2(rdir.y,rdir.x),rdist,asin(-rdir.z),TRF_THRUACTORS|TRF_ABSPOSITION,origin.z,origin.x,origin.y) || (rdist > 400) || (rdir dot x < 0.9) ) continue;
|
|
m.speed = m.vel.length();
|
|
if ( m.vel dot y > 0 ) m.vel = m.speed*(m.vel+(560-rdist)*y*0.01).unit();
|
|
else m.vel = m.speed*(m.vel-(560-rdist)*y*0.01).unit();
|
|
if ( m.target == self ) continue;
|
|
if ( m.bSEEKERMISSILE ) m.tracer = m.target;
|
|
m.target = self;
|
|
}
|
|
int numpt = Random[Impact](5,10);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (x+(FRandom[Impact](-.4,.4),FRandom[Impact](-.4,.4),FRandom[Impact](-.4,.4))).unit()*FRandom[Impact](1,3);
|
|
let s = Spawn("UTSmoke",origin);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,1,1)*Random[Impact](128,192));
|
|
}
|
|
numpt = Random[Impact](4,8);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (x+(FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5))).unit()*FRandom[Impact](2,16);
|
|
let s = Spawn("UTChip",origin);
|
|
s.vel = pvel;
|
|
s.scale *= 0.4;
|
|
}
|
|
}
|
|
action void A_ImpactRefire( statelabel flash = null )
|
|
{
|
|
FLineTraceData d;
|
|
Vector3 x, y, z;
|
|
[x, y, z] = dt_Matrix4.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+3.0*y-4.0*z;
|
|
LineTrace(angle,40,BulletSlope(),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
|
|
if ( (invoker.chargesize > 1) && (d.HitType == TRACE_HitActor) )
|
|
{
|
|
A_ClearRefire();
|
|
return;
|
|
}
|
|
A_Refire(flash);
|
|
}
|
|
override void DetachFromOwner()
|
|
{
|
|
if ( Owner ) Owner.A_StopSound(CHAN_WEAPON);
|
|
Super.DetachFromOwner();
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "Impact Hammer";
|
|
Obituary "%o was smeared by %k's piston.";
|
|
Inventory.PickupMessage "You got the Impact Hammer.";
|
|
Weapon.UpSound "impact/select";
|
|
Weapon.SlotNumber 1;
|
|
Weapon.SelectionOrder 9;
|
|
+WEAPON.MELEEWEAPON;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
IMPP A -1;
|
|
Stop;
|
|
IMPP B -1;
|
|
Stop;
|
|
Select:
|
|
IMPS A 1 A_Raise(int.max);
|
|
Wait;
|
|
Ready:
|
|
IMPS ABCDEFGHIJKLMNOPQ 1 A_WeaponReady(WRF_NOFIRE);
|
|
Idle:
|
|
IMPI A 1 A_WeaponReady();
|
|
Wait;
|
|
Fire:
|
|
IMPL A 0
|
|
{
|
|
A_ResetCharge();
|
|
A_PlaySound("impact/pull",CHAN_WEAPON);
|
|
}
|
|
IMPL A 5 A_ChargeUp(5);
|
|
IMPL B 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPL B 5 A_ChargeUp(5);
|
|
IMPL C 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPL C 5 A_ChargeUp(5);
|
|
IMPL D 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPL D 5 A_ChargeUp(5);
|
|
IMPL E 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPL E 5 A_ChargeUp(5);
|
|
IMPL E 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPL E 0 A_PlaySound("impact/loop",CHAN_WEAPON,looping:true);
|
|
Hold:
|
|
IMPR A 1 A_ChargeUp();
|
|
IMPR B 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPR B 1 A_ChargeUp();
|
|
IMPR C 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPR C 1 A_ChargeUp();
|
|
IMPR D 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPR D 1 A_ChargeUp();
|
|
IMPR E 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPR E 1 A_ChargeUp();
|
|
IMPR F 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPR F 1 A_ChargeUp();
|
|
IMPR G 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPR G 1 A_ChargeUp();
|
|
IMPR H 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPR H 1 A_ChargeUp();
|
|
IMPR I 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPR I 1 A_ChargeUp();
|
|
IMPR J 0 A_ImpactRefire(1);
|
|
Goto Release;
|
|
IMPR J 1 A_ChargeUp();
|
|
IMPR A 0 A_ImpactRefire("Hold");
|
|
Goto Release;
|
|
Release:
|
|
IMPF A 0 A_FireBlast();
|
|
IMPF AABCCDEEFGGHIIJKKLMMNOOP 1;
|
|
Goto Idle;
|
|
AltFire:
|
|
IMPF A 0 A_FireAltBlast();
|
|
IMPF ABCDEFGHIJKLMNOP 1;
|
|
Goto Idle;
|
|
Deselect:
|
|
IMPD A 0 A_StopSound(CHAN_WEAPON);
|
|
IMPD ABCDE 2;
|
|
IMPD E 1 A_Lower(int.max);
|
|
Wait;
|
|
}
|
|
}
|