Class RazorAmmo : Ammo { Default { Tag "$T_RIPPERAMMO"; Inventory.Icon "I_RazorA"; Inventory.PickupMessage "$I_RIPPERAMMO"; Inventory.Amount 25; Inventory.MaxAmount 75; Ammo.BackpackAmount 15; Ammo.BackpackMaxAmount 150; Ammo.DropAmount 15; } States { Spawn: BHOP A 8 A_CheckProximity(1,"PlayerPawn",80,1,CPXF_ANCESTOR|CPXF_CHECKSIGHT); Wait; BHOP AA 16; BHOP B 8 A_CheckProximity(1,"PlayerPawn",80,0,CPXF_ANCESTOR|CPXF_CHECKSIGHT|CPXF_EXACT); Goto Spawn+3; BHOP BB 16; Goto Spawn; } } Class RazorBlade : Actor { Vector3 gvel, accel; double oldgangle, gangle, oldgpitch, gpitch; Default { Radius 2; Height 2; Speed 25; DamageFunction (int((30+special1*10)*((DamageType=='Decapitated')?3.5:1.0))); DamageType 'Shredded'; Obituary "$O_RAZORJACK"; BounceType "Hexen"; ReactionTime 5; BounceFactor 1.0; WallBounceFactor 1.0; PROJECTILE; +USEBOUNCESTATE; +SKYEXPLODE; +CANBOUNCEWATER; +NODAMAGETHRUST; +DONTBOUNCEONSHOOTABLES; +ROLLSPRITE; +NOFRICTION; } override void PostBeginPlay() { Super.PostBeginPlay(); let t = Spawn("RazorBladeTrail",pos); t.target = self; frame = special1; if ( special1 > 0 ) { vel *= 1.+.06+special1; A_StartSound("razorjack/hum",CHAN_VOICE,CHANF_LOOPING,1.,3.,3.125+special1*.2); } else A_StartSound("razorjack/hum",CHAN_VOICE,CHANF_LOOPING,1.,3.,3.125); Vector3 dir = vel.unit(); A_SetAngle(atan2(dir.y,dir.x)); A_SetPitch(asin(-dir.z)); frame = 0; gvel = vel; oldgangle = gangle = angle; oldgpitch = gpitch = pitch; } override int SpecialMissileHit( Actor victim ) { if ( pos.z > victim.pos.z+victim.height*0.81 ) DamageType = 'Decapitated'; return -1; } override int DoSpecialDamage( Actor target, int damage, Name damagetype ) { if ( !target.bNOBLOOD ) { target.SpawnBlood(pos,AngleTo(target),damage); A_StartSound("razorjack/flesh"); A_AlertMonsters(); } UTMainHandler.DoKnockback(target,vel.unit(),15000); return damage; } void A_RazorAltOrient() { if ( !bAMBUSH || !target || !target.player || (target.Health <= 0) ) return; if ( sting_razoraim ) { FLineTraceData d; target.LineTrace(target.angle,10000,target.pitch,0,target.player.viewheight,data:d); Vector3 SeekingDir = level.Vec3Diff(pos,d.HitLocation).unit(); double MagnitudeVel = Vel.length(); SeekingDir = (SeekingDir*0.1*MagnitudeVel+Vel).unit(); vel = MagnitudeVel * SeekingDir; accel = SeekingDir * 25.; vel += accel/TICRATE; vel = vel.unit()*clamp(MagnitudeVel,10,15); } else { double dangle, dpitch; dangle = deltaangle(oldgangle,target.angle); dpitch = deltaangle(oldgpitch,target.pitch); gangle += dangle; gpitch += dpitch; vel += dt_Utility.Vec3FromAngle(gangle,gpitch)*15./TICRATE; double spd = vel.length(); vel = vel*clamp(spd,10,15)/spd; gvel = vel; oldgangle = target.angle; oldgpitch = target.pitch; } Vector3 dir = vel.unit(); A_SetAngle(atan2(dir.y,dir.x)); A_SetPitch(asin(-dir.z)); } action void A_RazorHit() { A_StartSound("razorjack/hit"); A_AlertMonsters(); A_SprayDecal("WallCrack",-20); int numpt = Random[Ripper](5,10); Vector3 x = dt_Utility.Vec3FromAngle(angle,pitch); for ( int i=0; i