Class RipperAmmo : Ammo
{
	Default
	{
		Tag "Razor Blades";
		Inventory.PickupMessage "You picked up Razor Blades.";
		Inventory.Amount 25;
		Inventory.MaxAmount 75;
		Ammo.BackpackAmount 50;
		Ammo.BackpackMaxAmount 75;
		Ammo.DropAmount 10;
	}
	States
	{
	Spawn:
		BHOP A -1;
		Stop;
	}
}

Class Razor2Trail : Actor
{
	Default
	{
		RenderStyle "Add";
		+NOGRAVITY;
		+NOCLIP;
		+DONTSPLASH;
		+NOTELEPORT;
	}
	override void Tick()
	{
		if ( !target || target.InStateSequence(target.CurState,target.ResolveState("Death")) )
		{
			Destroy();
			return;
		}
		SetOrigin(target.pos,true);
		A_SetAngle(target.angle,SPF_INTERPOLATE);
		A_SetPitch(target.pitch,SPF_INTERPOLATE);
		A_SetRoll(target.roll,SPF_INTERPOLATE);
		alpha = target.vel.length()/target.speed;
	}
	States
	{
	Spawn:
		RAZB A -1 Bright;
		Stop;
	}
}

Class Razor2 : Actor
{
	Default
	{
		Radius 2;
		Height 0;
		Speed 50;
		DamageFunction Random[Ripper](20,30);
		DamageType "Ripper";
		Obituary "%k ripped a chunk of meat out of %o with the Ripper.";
		BounceType "Doom";
		BounceCount 7;
		BounceFactor 1.0;
		WallBounceFactor 1.0;
		PROJECTILE;
		+USEBOUNCESTATE;
	}
	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.8 ) DamageType = 'Decapitated';
		return -1;
	}
	override int DoSpecialDamage( Actor target, int damage, Name damagetype )
	{
		if ( pos.z > target.pos.z+target.height*0.8 ) damage *= 2;
		if ( !target.bNOBLOOD )
		{
			target.SpawnBlood(pos,AngleTo(target),damage);
			A_PlaySound("ripper/flesh");
			A_AlertMonsters();
		}
		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<numpt; i++ )
		{
			Vector3 pvel = (-x+(FRandom[Ripper](-.8,.8),FRandom[Ripper](-.8,.8),FRandom[Ripper](-.8,.8))).unit()*FRandom[Ripper](0.1,1.2);
			let s = Spawn("UTSmoke",pos);
			s.vel = pvel;
			s.SetShade(Color(1,1,1)*Random[Ripper](128,192));
		}
		numpt = Random[Ripper](4,12);
		for ( int i=0; i<numpt; i++ )
		{
			Vector3 pvel = (FRandom[Ripper](-1,1),FRandom[Ripper](-1,1),FRandom[Ripper](-1,1)).unit()*FRandom[Ripper](2,8);
			let s = Spawn("UTSpark",pos);
			s.vel = pvel;
		}
		numpt = Random[Ripper](4,8);
		for ( int i=0; i<numpt; i++ )
		{
			Vector3 pvel = (FRandom[Ripper](-1,1),FRandom[Ripper](-1,1),FRandom[Ripper](-1,1)).unit()*FRandom[Ripper](2,8);
			let s = Spawn("UTChip",pos);
			s.vel = pvel;
		}
	}
	States
	{
	Spawn:
		RAZB A -1;
		Stop;
	Bounce:
		RAZB A 0
		{
			Vector3 dir = vel.unit();
			A_SetAngle(atan2(dir.y,dir.x));
			A_SetPitch(asin(-dir.z));
			A_RazorHit();
		}
		Goto Spawn;
	Death:
		TNT1 A 0
		{
			angle += 180;
			pitch *= -1;
			A_RazorHit();
		}
	XDeath:
		TNT1 A 1 A_StopSound(CHAN_VOICE);
		Stop;
	}
}

Class Razor2AltLight : DynamicLight
{
	double lifetime;
	Default
	{
		DynamicLight.Type "Point";
		Args 255,240,224,90;
	}
	override void PostBeginPlay()
	{
		Super.PostBeginPlay();
		lifetime = 1.0;
	}
	override void Tick()
	{
		Super.Tick();
		if ( globalfreeze || level.frozen ) return;
		args[LIGHT_RED] = 255*lifetime;
		args[LIGHT_GREEN] = 240*lifetime;
		args[LIGHT_BLUE] = 224*lifetime;
		lifetime -= 0.05;
		if ( lifetime <= 0 ) Destroy();
	}
}

Class Razor2Alt : Razor2
{
	Default
	{
		DamageFunction Random[Ripper](25,34);
		DamageType "RipperAltDealth";
		BounceType "None";
	}
	action void A_RazorExplode()
	{
		A_SetRenderStyle(1.0,STYLE_Add);
		bFORCEXYBILLBOARD = true;
		Scale *= 0.5;
		A_StopSound(CHAN_VOICE);
		A_PlaySound("ripper/althit");
		Spawn("Razor2AltLight",pos);
		A_AlertMonsters();
		A_SprayDecal("RazorBlast",20);
		A_Explode(Random[Ripper](20,34),180);
		int numpt = Random[Ripper](10,20);
		Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
		for ( int i=0; i<numpt; i++ )
		{
			Vector3 pvel = (-x+(FRandom[Ripper](-.8,.8),FRandom[Ripper](-.8,.8),FRandom[Ripper](-.8,.8))).unit()*FRandom[Ripper](0.1,1.2);
			let s = Spawn("UTSmoke",pos);
			s.vel = pvel;
			s.SetShade(Color(1,1,1)*Random[Ripper](128,192));
		}
		numpt = Random[Ripper](8,16);
		for ( int i=0; i<numpt; i++ )
		{
			Vector3 pvel = (FRandom[Ripper](-1,1),FRandom[Ripper](-1,1),FRandom[Ripper](-1,1)).unit()*FRandom[Ripper](2,8);
			let s = Spawn("UTSpark",pos);
			s.vel = pvel;
		}
		numpt = Random[Ripper](8,12);
		for ( int i=0; i<numpt; i++ )
		{
			Vector3 pvel = (FRandom[Ripper](-1,1),FRandom[Ripper](-1,1),FRandom[Ripper](-1,1)).unit()*FRandom[Ripper](2,8);
			let s = Spawn("UTChip",pos);
			s.vel = pvel;
		}
	}
	override int DoSpecialDamage( Actor target, int damage, Name damagetype )
	{
		return damage;
	}
	States
	{
	Death:
	XDeath:
		TNT1 A 0 A_RazorExplode();
		REXP ABCDEFG 2 Bright;
		Stop;
	}
}

Class Ripper2 : UTWeapon
{
	Default
	{
		Tag "Ripper";
		Inventory.PickupMessage "You got the Ripper.";
		Weapon.UpSound "ripper/select";
		Weapon.SlotNumber 6;
		Weapon.SelectionOrder 4;
		Weapon.AmmoType "RipperAmmo";
		Weapon.AmmoUse 1;
		Weapon.AmmoType2 "RipperAmmo";
		Weapon.AmmoUse2 1;
		Weapon.AmmoGive 15;
	}
	action void A_RazorFire( bool alt = false )
	{
		Weapon weap = Weapon(invoker);
		if ( !weap ) return;
		if ( weap.Ammo1.Amount <= 0 ) return;
		if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
		if ( alt ) A_PlaySound("ripper/altfire",CHAN_WEAPON);
		else A_PlaySound("ripper/fire",CHAN_WEAPON);
		invoker.FireEffect();
		UTMainHandler.DoFlash(self,Color(8,0,255,255),1);
		A_AlertMonsters();
		if ( alt ) A_QuakeEx(3,3,3,8,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
		else A_QuakeEx(2,2,2,5,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.08);
		Vector3 x, y, z;
		[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
		Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+8.0*y-7.0*z;
		Actor p;
		if ( alt ) p = Spawn("Razor2Alt",origin);
		else p = Spawn("Razor2",origin);
		p.angle = angle;
		p.pitch = BulletSlope();
		p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
		p.target = self;
	}
	States
	{
	Spawn:
		RZRP A -1;
		Stop;
		RZRP B -1;
		Stop;
	Select:
		RZRS A 1 A_Raise(int.max);
		Wait;
	Ready:
		RZRS ABCDEFGHIJKLMNOPQRSTUVWXYZ 1;
		RZS2 ABCD 1;
	Idle:
		RZRI ABCDEFGHIJKLMNOPQRS 2
		{
			A_CheckReload();
			A_WeaponReady();
		}
		Loop;
	Fire:
		RZRF A 0 A_RazorFire();
		RZRF ABCDEFGHIJKLMNO 1;
		Goto Idle;
	AltFire:
		RZRF A 0 A_RazorFire(true);
		RZRF ABCDEFG 3;
		RZRF HIJKLMNO 1;
		Goto Idle;
	Deselect:
		RZRD ABCDEF 2;
		RZRD F 1 A_Lower(int.max);
		Wait;
	}
}
