Class RipperAmmo : Ammo { Default { Tag "Razor Blades"; Inventory.PickupMessage "You picked up Razor Blades."; Inventory.Amount 10; Inventory.MaxAmount 40; Ammo.BackpackAmount 20; Ammo.BackpackMaxAmount 80; Ammo.DropAmount 5; } States { Spawn: BHOP A -1; Stop; } } Class Razor2Trail : Actor { Default { RenderStyle "Add"; +NOGRAVITY; +NOCLIP; +DONTSPLASH; +NOTELEPORT; Radius 0.1; Height 0; } override void Tick() { if ( !target || target.InStateSequence(target.CurState,target.ResolveState("Death")) ) { Destroy(); return; } SetOrigin(target.pos,true); angle = target.angle; pitch = target.pitch; alpha = target.vel.length()/target.speed; } States { Spawn: RAZB A -1 Bright; Stop; } } Class Razor2 : Actor { Default { Radius 2; Height 2; Speed 25; DamageFunction (Random[Ripper](20,25)*((DamageType=='Decapitated')?3:1.0)); DamageType 'Shredded'; Obituary "%k ripped a chunk of meat out of %o with the Ripper."; BounceType "Hexen"; ReactionTime 7; BounceFactor 1.0; WallBounceFactor 1.0; PROJECTILE; +USEBOUNCESTATE; +SKYEXPLODE; +CANBOUNCEWATER; +NODAMAGETHRUST; } override void PostBeginPlay() { Super.PostBeginPlay(); let t = Spawn("Razor2Trail",pos); t.target = self; A_PlaySound("ripper/hum",CHAN_VOICE,1.0,true,3.0); Vector3 dir = vel.unit(); A_SetAngle(atan2(dir.y,dir.x)); A_SetPitch(asin(-dir.z)); } 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_PlaySound("ripper/flesh"); A_AlertMonsters(); } UTMainHandler.DoKnockback(target,vel.unit(),15000); return damage; } action void A_RazorHit() { A_PlaySound("ripper/hit"); A_AlertMonsters(); A_SprayDecal("WallCrack",-20); int numpt = Random[Ripper](5,10); Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch)); for ( int i=0; i