flak_m/zscript/impacthammer.zsc
Marisa Kirisame fb96c7523e Portal awareness adjustments to various vector operations.
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.
2019-09-28 20:06:51 +02:00

290 lines
8.5 KiB
Text

Class HammerImpact : Actor
{
Default
{
Radius 0.1;
Height 0;
+NOGRAVITY;
+NOCLIP;
+DONTSPLASH;
+NOTELEPORT;
}
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()
{
invoker.chargesize += .75/TICRATE;
invoker.count += 1./TICRATE;
if ( invoker.count > .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),2,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);
if ( !(player.cmd.buttons&BT_ATTACK) )
{
player.SetPSprite(PSP_WEAPON,ResolveState("Release"));
return;
}
FLineTraceData d;
Vector3 x, y, z;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+3*y-4*z);
LineTrace(angle,40,BulletSlope(),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
if ( (invoker.chargesize > 1) && (d.HitType == TRACE_HitActor) )
player.SetPSprite(PSP_WEAPON,ResolveState("Release"));
}
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_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+3*y-4*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(60*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(24*realcharge); // It's a flat damage 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;
}
invoker.chargesize = 0;
invoker.count = 0;
}
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_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+3*y-4*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(20*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(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;
}
}
override void DetachFromOwner()
{
if ( Owner ) Owner.A_StopSound(CHAN_WEAPON);
Super.DetachFromOwner();
}
Default
{
Tag "$T_IMPACTHAMMER";
Obituary "$O_IMPACTHAMMER";
Inventory.PickupMessage "$I_IMPACTHAMMER";
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
{
invoker.chargesize = 0;
invoker.count = 0;
A_WeaponReady();
}
Wait;
Charging:
TNT1 A 1 A_ChargeUp();
Wait;
Fire:
IMPL A 0
{
A_ResetCharge();
A_Overlay(-9999,"Charging");
A_PlaySound("impact/pull",CHAN_WEAPON);
}
IMPL ABCDE 5;
IMPR A 0 A_PlaySound("impact/loop",CHAN_WEAPON,looping:true);
Goto Hold;
Hold:
IMPR ABCDEFGHIJ 1;
Loop;
Release:
IMPF A 0
{
A_Overlay(-9999,null);
if ( self is 'UTPlayer' )
UTPlayer(self).PlayAttacking3();
A_FireBlast();
}
// this is why we need a model animation overhaul
IMPF A 2;
IMPF B 1;
IMPF C 2;
IMPF D 1;
IMPF E 2;
IMPF F 1;
IMPF G 2;
IMPF H 1;
IMPF I 2;
IMPF J 1;
IMPF K 2;
IMPF L 1;
IMPF M 2;
IMPF N 1;
IMPF O 2;
IMPF P 1;
Goto Idle;
AltFire:
IMPF A 1 A_FireAltBlast();
IMPF BCDEFGHIJKLMNOP 1;
Goto Idle;
Deselect:
IMPD A 2 A_StopSound(CHAN_WEAPON);
IMPD BCDE 2;
IMPD E 1 A_Lower(int.max);
Wait;
}
}