flak_m/zscript/impacthammer.zsc
Marisa Kirisame eaf19d3007 1.1.3 mini-update:
- Added hacky ammo displays.
 - Removed swingers.
 - Updated patron credits.
2021-01-24 14:32:13 +01:00

294 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;
override int, int, bool, bool GetClipAmount()
{
return (chargesize>0)?min(10,int(chargesize/.15)):-1, -1, false, false;
}
action void A_ResetCharge()
{
invoker.chargesize = 0;
invoker.count = 0;
invoker.FireEffect(); // intentional UT behavior
}
action void A_ChargeUp()
{
if ( Health <= 0 )
{
player.SetPSprite(-9999,ResolveState("Null"));
return;
}
invoker.chargesize += .75/TICRATE;
invoker.count += 1./TICRATE;
if ( invoker.count > .2 )
{
invoker.count = 0;
A_AlertMonsters(gameinfo.gametype&GAME_Strife?100:0);
}
A_QuakeEx(clamp(int(invoker.chargesize),0,2),clamp(int(invoker.chargesize),0,2),clamp(int(invoker.chargesize),0,2),2,0,96,"",QF_RELATIVE,rollIntensity:clamp(invoker.chargesize*0.3,0,0.3));
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_StopSound(CHAN_WEAPONMISC);
A_StartSound("impact/release",CHAN_WEAPON);
invoker.FireEffect();
A_AlertMonsters(gameinfo.gametype&GAME_Strife?100:0);
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 ( gameinfo.gametype&GAME_Strife ) d.HitActor.DaggerAlert(self);
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_StartSound("impact/fire",CHAN_WEAPON);
invoker.FireEffect();
A_AlertMonsters(gameinfo.gametype&GAME_Strife?100:0);
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;
if ( gameinfo.gametype&GAME_Strife ) d.HitActor.DaggerAlert(self);
}
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;
}
}
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_StartSound("impact/pull",CHAN_WEAPON);
}
IMPL ABCDE 5;
IMPR A 0 A_StartSound("impact/loop",CHAN_WEAPONMISC,CHANF_LOOPING);
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;
}
}