Class UDamage : PowerupGiver replaces Berserk
{
	Default
	{
		Tag "Damage Amplifier";
		Inventory.PickupMessage "You got the Damage Amplifier!";
		+COUNTITEM;
		+INVENTORY.AUTOACTIVATE;
		+INVENTORY.ALWAYSPICKUP;
		+INVENTORY.BIGPOWERUP;
		Inventory.MaxAmount 0;
		Powerup.Type "DamageAmplifier";
		Inventory.PickupSound "udamage/pickup";
		Inventory.RespawnTics 4200;
	}
	override void PostBeginPlay()
	{
		Super.PostBeginPlay();
		A_CheckSkin();
	}
	action void A_CheckSkin()
	{
		bool isbeta = CVar.GetCVar('flak_betaudamage').GetBool();
		if ( isbeta && (CurState == ResolveState("Spawn")) ) SetState(ResolveState("Spawn")+1);
		else if ( !isbeta && (CurState == ResolveState("Spawn")+1) ) SetState(ResolveState("Spawn"));
	}
	States
	{
	Spawn:
		UDAM A 5 A_CheckSkin();
		Loop;
		UDAM B 5 A_CheckSkin();
		Loop;
	}
}

Class DamageAmpLight : DynamicLight
{
	Default
	{
		DynamicLight.Type "Point";
		Args 238,0,255,80;
	}
	override void Tick()
	{
		Super.Tick();
		if ( !target || !master )
		{
			Destroy();
			return;
		}
		SetOrigin(target.pos,true);
		args[LIGHT_INTENSITY] = Random[ASMD](10,12)*8;
		bDORMANT = Powerup(master).isBlinking();
	}
}

Class DamageAmplifier : Powerup
{
	Actor l;

	Default
	{
		Powerup.Duration -60;
		Powerup.Color "EE00FF", 0.15;
	}

	override void InitEffect()
	{
		Super.InitEffect();
		l = Spawn("DamageAmpLight",Owner.pos);
		l.target = Owner;
		l.master = self;
	}

	override void DoEffect()
	{
		Super.DoEffect();
		if ( (EffectTics == 175) || (EffectTics == 140) || (EffectTics == 105) || (EffectTics == 70) || (EffectTics == 35) )
			Owner.A_PlaySound("udamage/drain",CHAN_6,1.0,false,0.25);
	}

	override void EndEffect()
	{
		Super.EndEffect();
		PrintPickupMessage(true,"Damage Amplifier has worn off.");
	}

	override bool isBlinking()
	{
		return ((EffectTics <= 175) && (EffectTics%35 >= 30));
	}

	void FireEffect()
	{
		if ( EffectTics < 350 ) Owner.A_PlaySound("udamage/fire2",CHAN_5,1.0,false,0.25);
		else Owner.A_PlaySound("udamage/fire1",CHAN_5,1.0,false,0.25);
		UTMainHandler.DoFlash(Owner,Color(96,238,0,255),10);
	}

	override void ModifyDamage( int damage, Name damageType, out int newdamage, bool passive )
	{
		if ( passive || (damage <= 0) ) return;
		newdamage = max(1,ApplyDamageFactors(GetClass(),damageType,damage,damage*3));
		if ( !(Owner.player.ReadyWeapon is 'UTWeapon') ) FireEffect();
	}
}

// Backpack that only gives ammo for valid weapons
Class UTBackpack : BackpackItem replaces Backpack
{
	override Inventory CreateCopy( Actor other )
	{
		// Find every unique type of ammoitem. Give it to the player if
		// he doesn't have it already, and double its maximum capacity.
		for ( int i=0; i<AllActorClasses.Size(); i++ )
		{
			let type = (class<Ammo>)(AllActorClasses[i]);
			if ( !type || (type.GetParentClass() != 'Ammo') ) continue;
			// check that it's for a valid weapon
			bool isvalid = false;
			for ( int j=0; j<AllActorClasses.Size(); j++ )
			{
				let type2 = (class<Weapon>)(AllActorClasses[j]);
				if ( !type2 ) continue;
				let rep = GetReplacement(type2);
				if ( (rep != type2) && !(rep is "DehackedPickup") ) continue;
				readonly<Weapon> weap = GetDefaultByType(type2);
				if ( !other.player || !other.player.weapons.LocateWeapon(type2) || weap.bCheatNotWeapon ) continue;
				if ( (weap.AmmoType1 == type) || (weap.AmmoType2 == type) )
				{
					isvalid = true;
					break;
				}
			}
			if ( !isvalid ) continue;
			let ammoitem = Ammo(other.FindInventory(type));
			int amount = GetDefaultByType(type).BackpackAmount;
			// extra ammo in baby mode and nightmare mode
			if ( !bIgnoreSkill ) amount = int(amount*G_SkillPropertyFloat(SKILLP_AmmoFactor));
			if ( amount < 0 ) amount = 0;
			if ( !ammoitem )
			{
				// The player did not have the ammoitem. Add it.
				ammoitem = Ammo(Spawn(type));
				ammoitem.Amount = bDepleted?0:amount;
				if ( ammoitem.BackpackMaxAmount > ammoitem.MaxAmount )
					ammoitem.MaxAmount = ammoitem.BackpackMaxAmount;
				if ( ammoitem.Amount > ammoitem.MaxAmount )
					ammoitem.Amount = ammoitem.MaxAmount;
				ammoitem.AttachToOwner(other);
			}
			else
			{
				// The player had the ammoitem. Give some more.
				if ( ammoitem.MaxAmount < ammoitem.BackpackMaxAmount )
					ammoitem.MaxAmount = ammoitem.BackpackMaxAmount;
				if ( !bDepleted && (ammoitem.Amount < ammoitem.MaxAmount) )
				{
					ammoitem.Amount += amount;
					if ( ammoitem.Amount > ammoitem.MaxAmount )
						ammoitem.Amount = ammoitem.MaxAmount;
				}
			}
		}
		return Inventory.CreateCopy(other);
	}
	override bool HandlePickup (Inventory item)
	{
		// Since you already have a backpack, that means you already have every
		// kind of ammo in your inventory, so we don't need to look at the
		// entire PClass list to discover what kinds of ammo exist, and we don't
		// have to alter the MaxAmount either.
		if ( item is 'BackpackItem' )
		{
			for ( let probe = Owner.Inv; probe; probe = probe.Inv )
			{
				if ( probe.GetParentClass() != 'Ammo' ) continue;
				if ( probe.Amount >= probe.MaxAmount && !sv_unlimited_pickup ) continue;
				int amount = Ammo(probe).Default.BackpackAmount;
				// extra ammo in baby mode and nightmare mode
				if ( !bIgnoreSkill )
					amount = int(amount*G_SkillPropertyFloat(SKILLP_AmmoFactor));
				probe.Amount += amount;
				if ( (probe.Amount > probe.MaxAmount) && !sv_unlimited_pickup )
					probe.Amount = probe.MaxAmount;
			}
			// The pickup always succeeds, even if you didn't get anything
			item.bPickupGood = true;
			return true;
		}
		return false;
	}
	Default
	{
		Tag "Backpack";
		Inventory.PickupMessage "You got a Backpack.";
		Inventory.RespawnTics 2100;
	}
	States
	{
	Spawn:
		BPAK A -1;
		Stop;
	}
}

Class PowerUTInvisibility : PowerInvisibility
{
	Default
	{
		Powerup.Duration -50;
		Powerup.Strength 95;
		Powerup.Mode "Translucent";
		Powerup.Color "FFFFFF", 0.15;
	}
	override void EndEffect()
	{
		Super.EndEffect();
		PrintPickupMessage(true,"Invisibility has worn off.");
	}
}

Class UTInvisibility : PowerupGiver replaces BlurSphere
{
	Default
	{
		Tag "Invisibility";
		+COUNTITEM;
		+INVENTORY.AUTOACTIVATE;
		+INVENTORY.ALWAYSPICKUP;
		+INVENTORY.BIGPOWERUP;
		Inventory.MaxAmount 0;
		Powerup.Type "PowerUTInvisibility";
		Inventory.PickupMessage "You have Invisibility.";
		Inventory.PickupSound "invis/pickup";
		Inventory.RespawnTics 4200;
	}
	override void PostBeginPlay()
	{
		Super.PostBeginPlay();
		tracer = Spawn("UTInvisibilityX",pos);
		tracer.angle = angle;
		tracer.target = self;
	}
	States
	{
	Spawn:
		INVS A -1 Bright;
		Stop;
	}
}

Class UTInvisibilityX : Actor
{
	Default
	{
		RenderStyle "Add";
		+NOGRAVITY;
		+NOCLIP;
		+DONTSPLASH;
	}
	override void Tick()
	{
		Super.Tick();
		if ( !target )
		{
			Destroy();
			return;
		}
		SetOrigin(target.pos,true);
		A_SetAngle(target.angle,SPF_INTERPOLATE);
		bInvisible = target.bInvisible;
	}
	States
	{
	Spawn:
		INVS A -1 Bright;
		Stop;
	}
}

Class UTMapRevealer : MapRevealer replaces Allmap
{
	Default
	{
		+COUNTITEM;
		+INVENTORY.FANCYPICKUPSOUND;
		+INVENTORY.ALWAYSPICKUP;
		Inventory.MaxAmount 0;
		Inventory.PickupSound "trans/pickup";
		Inventory.PickupMessage "You got the Computer Map.";
	}
	States
	{
	Spawn:
		TRNS A -1;
		Stop;
	}
}

Class UTJumpBoots : Inventory replaces RadSuit
{
	Default
	{
		Tag "AntiGrav Boots";
		+INVENTORY.AUTOACTIVATE;
		+INVENTORY.ALWAYSPICKUP;
		Inventory.Amount 3;
		Inventory.MaxAmount 3;
		Inventory.PickupMessage "You picked up the AntiGrav boots.";
		Inventory.PickupSound "boot/pickup";
		Inventory.RespawnTics 1050;
	}
	override bool Use( bool pickup )
	{
		if ( pickup )
		{
			Owner.GiveInventory("PowerJumpBoots_HighJump",1);
			Owner.GiveInventory("PowerJumpBoots_IronFeet",1);
		}
		return false;
	}
	override void Tick()
	{
		Super.Tick();
		if ( !Owner || !Owner.player ) return;
		if ( owner.player.jumptics == -1 )
		{
			Amount--;
			Owner.A_PlaySound("boot/jump",CHAN_BODY);
			if ( Amount <= 0 )
			{
				PrintPickupMessage(true,"The AntiGrav Boots have drained.");
				DepleteOrDestroy();
			}
		}
	}
	override void DetachFromOwner()
	{
		Super.DetachFromOwner();
		Owner.TakeInventory("PowerJumpBoots_HighJump",1);
		Owner.TakeInventory("PowerJumpBoots_IronFeet",1);
	}
	override void OwnerDied()
	{
		Super.OwnerDied();
		DepleteOrDestroy();
	}
	States
	{
	Spawn:
		JBUT A -1;
		Stop;
	}
}

Class PowerJumpBoots_HighJump : PowerHighJump
{
	Default
	{
		Powerup.Strength 3;
		Powerup.Duration int.max;
	}
}
Class PowerJumpBoots_IronFeet : PowerIronFeet
{
	Default
	{
		Powerup.Duration int.max;
		Powerup.Color "00 00 00", 0.0;
	}
	override void AbsorbDamage( int damage, Name damageType, out int newdamage )
	{
	}
	override void DoEffect()
	{
		Powerup.DoEffect();
	}
}

Class Searchlight : Inventory replaces Infrared
{
	Actor lt[3];
	int ticcnt;
	Default
	{
		Tag "Searchligh";
		+COUNTITEM;
		+INVENTORY.UNTOSSABLE;
		+INVENTORY.FANCYPICKUPSOUND;
		+INVENTORY.AUTOACTIVATE;
		+INVENTORY.ALWAYSPICKUP;
		Inventory.Amount 200;
		Inventory.MaxAmount 200;
		Inventory.InterHubAmount 0;
		Inventory.PickupMessage "You picked up the Searchlight.";
	}

	override bool Use( bool pickup )
	{
		if ( !lt[0] ) lt[0] = Spawn("mkLight");
		lt[0].target = owner;
		lt[0].master = self;
		if ( !lt[1] ) lt[1] = Spawn("mkLight2");
		lt[1].target = owner;
		lt[1].master = self;
		if ( !lt[2] ) lt[2] = Spawn("mkLight3");
		lt[2].target = owner;
		lt[2].master = self;
		return Super.Use(pickup);
	}
	override void DetachFromOwner()
	{
		Super.DetachFromOwner();
		if ( lt[0] ) lt[0].Destroy();
		if ( lt[1] ) lt[1].Destroy();
		if ( lt[2] ) lt[2].Destroy();
	}
	override void DoEffect()
	{
		Super.DoEffect();
		if ( !Owner ) return;
		if ( ticcnt++ < TICRATE ) return;
		ticcnt = 0;
		if ( --Amount <= 0 )
		{
			PrintPickupMessage(true,"Searchlight batteries have died.");
			DepleteOrDestroy();
		}
	}
	States
	{
	Spawn:
		SLIT A -1;
		Stop;
	}
}

/* hello, Soundless Mound copypasted lights */
Class mkLight : DynamicLight
{
	Default
	{
		DynamicLight.Type "Point";
		+DynamicLight.SPOT;
		+DynamicLight.ATTENUATE;
		+DynamicLight.DONTLIGHTSELF;
		args 255,224,160,350;
		DynamicLight.SpotInnerAngle 20;
		DynamicLight.SpotOuterAngle 35;
	}
	override void Tick()
	{
		Super.Tick();
		if ( !target || !Inventory(master) )
		{
			Destroy();
			return;
		}
		if ( target.player ) SetOrigin((target.pos.x,target.pos.y,target.player.viewz),true);
		else SetOrigin(target.vec3Offset(0,0,target.height*0.75),true);
		A_SetAngle(target.angle,SPF_INTERPOLATE);
		A_SetPitch(target.pitch,SPF_INTERPOLATE);
		args[LIGHT_RED] = GetDefaultByType(GetClass()).args[LIGHT_RED]*clamp(Inventory(master).amount/40.,0.,1.);
		args[LIGHT_GREEN] = GetDefaultByType(GetClass()).args[LIGHT_GREEN]*clamp(Inventory(master).amount/40.,0.,1.);
		args[LIGHT_BLUE] = GetDefaultByType(GetClass()).args[LIGHT_BLUE]*clamp(Inventory(master).amount/40.,0.,1.);
		bDORMANT = (target.health <= 0);
		if ( Inventory(target) && target.bInvisible ) bDORMANT = true;
		// alert monsters hit by the light
		if ( GetClass() != "mkLight" ) return;
		if ( !bDORMANT && target.player && (target.health > 0) )
		{
			BlockThingsIterator bt = BlockThingsIterator.Create(target,args[LIGHT_INTENSITY]);
			while ( bt.Next() )
			{
				if ( !bt.Thing || (Distance3D(bt.Thing) > args[LIGHT_INTENSITY]) ) continue;
				Vector3 aimdir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
				Vector3 reldir = Vec3To(bt.Thing).unit();
				if ( (acos(aimdir dot reldir) < SpotOuterAngle+5) && bt.Thing.CheckSight(target) ) bt.Thing.LastHeard = target;
			}
		}
	}
}

Class mkLight2 : mkLight
{
	Default
	{
		args 128,112,96,450;
		DynamicLight.SpotInnerAngle 0;
		DynamicLight.SpotOuterAngle 50;
	}
}

Class mkLight3 : DynamicLight
{
	Default
	{
		DynamicLight.Type "Point";
		+DynamicLight.ATTENUATE;
		args 32,28,24,0;
	}
	override void Tick()
	{
		Super.Tick();
		if ( !target || Inventory(target) || !Inventory(master) )
		{
			Destroy();
			return;
		}
		args[LIGHT_RED] = GetDefaultByType(GetClass()).args[LIGHT_RED]*clamp(Inventory(master).amount/40,0.,1.);
		args[LIGHT_GREEN] = GetDefaultByType(GetClass()).args[LIGHT_GREEN]*clamp(Inventory(master).amount/40,0.,1.);
		args[LIGHT_BLUE] = GetDefaultByType(GetClass()).args[LIGHT_BLUE]*clamp(Inventory(master).amount/40,0.,1.);
		SetOrigin(target.vec3Offset(0,0,target.height*0.5),true);
	}
}
