- Added hacky ammo displays. - Removed swingers. - Updated patron credits.
294 lines
8.5 KiB
Text
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;
|
|
}
|
|
}
|