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; i0)?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 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