
class ZBaseActorMetal : SwitchableDecoration
{
	int pcount;
	Vector3 mwoldpos;
	int mwblastdamage;
	int mwfalldamage;
	int mwcount;

	private void Zap(actor victim, color pcolor, double palpha)
	{
		double ztr=victim.default.radius;
		vector3 nodes[4];
		int len=10;
		nodes[0]=victim.pos+(frandom[RIDFX](-ztr,ztr),frandom[RIDFX](-ztr,ztr),frandom[RIDFX](victim.default.height/2,victim.default.height));
		nodes[1]=nodes[0]+(frandom[RIDFX](-len,len),frandom[RIDFX](-len,len),frandom[RIDFX](-len,len));
		nodes[2]=nodes[1]+(frandom[RIDFX](-len,len),frandom[RIDFX](-len,len),frandom[RIDFX](-(len>>1),len));
		nodes[3]=nodes[2]+(frandom[RIDFX](-len,len),frandom[RIDFX](-len,len),frandom[RIDFX](-len*2/3,(len>>1)));
		for(int i=1;i<4;i++){
			vector3 pastnode=nodes[i-1];
			vector3 particlepos=nodes[i]-pastnode;
			int iterations=int(particlepos.length());
			vector3 particlemove=particlepos/iterations;
			particlepos=pastnode-victim.pos;
			for(int i=0;i<iterations;i++){
				victim.A_SpawnParticle(pcolor,
					SPF_RELATIVE|SPF_FULLBRIGHT,(len>>1),frandom[RIDFX](1,5),0,
					particlepos.x,particlepos.y,particlepos.z,
					frandom[RIDFX](-0.1,0.1),frandom[RIDFX](-0.1,0.1),frandom[RIDFX](0.1,0.2),
					frandom[RIDFX](-0.1,0.1),frandom[RIDFX](-0.1,0.1),0.5, palpha
				);
				particlepos+=particlemove+(frandom[RIDFX](-1,1),frandom[RIDFX](-1,1),frandom[RIDFX](-1,1));
			}
		}
	}

	void A_ThrustToTarget(float force = 10)
	{
		if(target) {
			float aangle = self.angle + deltaangle(self.angle,self.angleto(target));
			float ppitch = (target.pos.Z + target.Height/2 - pos.Z) / DistanceBySpeed(target, force*2);

			self.A_ChangeVelocity(cos(aangle)*force, sin(aangle)*force, ppitch );
		}
	}

	action state A_CheckThump(StateLabel label)
	{
		invoker.Zap(self, "d7 d7 d8", 1);
		invoker.Zap(self, "d7 d7 d8", 1);
		invoker.Zap(self, "d7 d7 d8", 1);
		self.A_SpawnProjectile("Duke_Smoke", height/2.0, 0, random[RIDFX](0, 360), 2, random[RIDFX](0, 360));
		self.A_SpawnProjectile("Duke_Smoke", height/2.0, 0, random[RIDFX](0, 360), 2, random[RIDFX](0, 360));
		self.A_SpawnProjectile("Duke_Smoke", height/2.0, 0, random[RIDFX](0, 360), 2, random[RIDFX](0, 360));

		self.A_SpawnProjectile("MuzzleFlashFreezer", height/2.0, 0, random[RIDFX](0, 360), 2, random[RIDFX](0, 360));

		vector2 newpos = pos.xy + (pos.xy - invoker.mwoldpos.xy);

		if ( newpos == pos.xy || !CheckMove(newpos) || ( abs(pos.z-GetZAt())<=1 && GetZAt()==floorz ) || vel.z==0 )
		{
			self.A_SpawnProjectile("Duke_Smoke", height/2.0, 0, random[RIDFX](0, 360), 2, random[RIDFX](0, 360));
			self.A_SpawnProjectile("Duke_Smoke", height/2.0, 0, random[RIDFX](0, 360), 2, random[RIDFX](0, 360));
			self.A_SpawnProjectile("Duke_Smoke", height/2.0, 0, random[RIDFX](0, 360), 2, random[RIDFX](0, 360));

			self.A_SpawnDebris("DukeMechParticle", mult_v: 1.0);
			self.bNOBLOCKMONST = self.default.bNOBLOCKMONST;
			self.bFLOAT = self.default.bFLOAT;
			self.bNOGRAVITY = self.default.bNOGRAVITY;
			if(self.bFLOAT) {invoker.mwcount = 0; invoker.mwfalldamage = -1;}
			self.bDONTHARMCLASS = false;
			self.A_Explode(invoker.mwblastdamage*1.0,96,XF_EXPLICITDAMAGETYPE|XF_NOTMISSILE,0,96,0,0,"none","MightyBoot");
			self.A_Explode(invoker.mwblastdamage*1.0,96,XF_EXPLICITDAMAGETYPE|XF_NOTMISSILE,0,96,0,0,"none","MightyBoot");
			self.A_DamageSelf(invoker.mwblastdamage*2.0,"MightyBoot");
			self.A_DamageSelf(invoker.mwblastdamage*2.0,"MightyBoot");
			self.bDONTHARMCLASS = true;
			if(self.health>0) return ResolveState(label);
		}

		invoker.mwoldpos = pos;
		return null;
	}

	override void PostBeginPlay()
	{
		mwfalldamage = -1;
		mwcount = -1;

		Super.PostBeginPlay();
	}
	override int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags, double angle)
    	{
	    if(inflictor && inflictor.GetClass() is 'Doom_ArchvileFireShield') damage = 0;

	    if(source || inflictor)
	    {
		if(!source && inflictor) source = inflictor;

        	if(mod == 'Bullet' || mod == 'Chaingun' || mod == 'FireChaingun')
        	{
			self.A_SpawnDebris("DukeMechParticle", mult_v: 1.0);
			self.A_PlaySound("metal/hit");
			self.A_Pain();
			if(self.mass<100000) {
				if(self.default.height<60) {
					float knockbackangle = self.angle + deltaangle(self.angle,self.angleto(source));
					float knockback = 2.0;
					float knockbackz = 0.0;
					self.A_ChangeVelocity(-cos(knockbackangle)*knockback, -sin(knockbackangle)*knockback, knockbackz/5.0 );
				} else if(self.default.radius<30) {
					float knockbackangle = self.angle + deltaangle(self.angle,self.angleto(source));
					float knockback = 0.5;
					float knockbackz = 0.0;
					self.A_ChangeVelocity(-cos(knockbackangle)*knockback, -sin(knockbackangle)*knockback, knockbackz/5.0 );
				}
			}
        	}
        	else if(mod == 'Shotgun' || mod == 'ExplosiveShotgun')
        	{
			self.A_SpawnDebris("DukeMechParticle", mult_v: 1.0);
			self.A_PlaySound("metal/hit",random[RIDMONSTER](1,7));
			self.A_Pain();
			if(self.mass<100000) {
				if(self.default.height<60) {
					float knockbackangle = self.angle + deltaangle(self.angle,self.angleto(source));
					float knockback = 1.0;
					float knockbackz = 3.5;
					self.A_ChangeVelocity(-cos(knockbackangle)*knockback, -sin(knockbackangle)*knockback, knockbackz/5.0 );
				} else if(self.default.radius<30) {
					float knockbackangle = self.angle + deltaangle(self.angle,self.angleto(source));
					float knockback = 0.5;
					float knockbackz = 2.5;
					self.A_ChangeVelocity(-cos(knockbackangle)*knockback, -sin(knockbackangle)*knockback, knockbackz/5.0 );
				}
			}
        	}
        	else if(mod == 'SSG')
        	{
			self.A_SpawnDebris("DukeMechParticle", mult_v: 1.0);
			self.A_PlaySound("metal/hit",random[RIDMONSTER](1,7));
			self.A_Pain();
			if(self.mass<100000) {
				if(self.default.height<60) {
					float knockbackangle = self.angle + deltaangle(self.angle,self.angleto(source));
					float knockback = 0.5;
					float knockbackz = 2.0;
					self.A_ChangeVelocity(-cos(knockbackangle)*knockback, -sin(knockbackangle)*knockback, knockbackz/5.0 );
				} else if(self.default.radius<30) {
					float knockbackangle = self.angle + deltaangle(self.angle,self.angleto(source));
					float knockback = 0.25;
					float knockbackz = 1.0;
					self.A_ChangeVelocity(-cos(knockbackangle)*knockback, -sin(knockbackangle)*knockback, knockbackz/5.0 );
				}
			}
        	}
        	else if(mod == 'Plasma')
        	{
			self.A_SpawnDebris("DukeMechParticle", mult_v: 1.0);
			self.speed = self.speed - (self.speed*0.1);

        	}
        	else if(mod == 'MicrowaveBlast')
        	{
			mwoldpos = self.pos;
			mwfalldamage = 0;
			self.bNOBLOCKMONST = true;
			self.bFLOAT = false;
			self.bNOGRAVITY = false;
			self.bSKULLFLY=false;

			self.speed = self.default.speed;
			pcount = 0;
			self.bFRIGHTENED = false;
			mwcount = -1;

			let amwfx = Spawn("ExpanderMicrowaveBlastFire", (self.pos.x,self.pos.y,self.pos.z+self.height/2.0) );
			amwfx.A_SetScale(0.015*damage);

			self.A_Pain();
			if(self.default.height<60 && self.mass<100000) {
				float knockbackangle = self.angle + deltaangle(self.angle,self.angleto(inflictor));
				float knockback = 1.0 * damage;
				float knockbackz = 1.0 * (damage + max(0,2*((self.pos.z+self.height/2.0) - inflictor.pos.z)));
				mwblastdamage = knockback;
				self.A_ChangeVelocity(-cos(knockbackangle)*knockback, -sin(knockbackangle)*knockback, knockbackz/5.0 );
			} else if(self.default.radius<30 && self.mass<100000) {
				float knockbackangle = self.angle + deltaangle(self.angle,self.angleto(inflictor));
				float knockback = 0.5 * damage;
				float knockbackz = 0.5 * (damage + max(0,2*((self.pos.z+self.height/2.0) - inflictor.pos.z)));
				mwblastdamage = knockback;
				self.A_ChangeVelocity(-cos(knockbackangle)*knockback, -sin(knockbackangle)*knockback, knockbackz/5.0 );
			} else {
				float knockbackangle = self.angle + deltaangle(self.angle,self.angleto(inflictor));
				float knockback = 0.25 * damage;
				float knockbackz = 0.25 * (damage + max(0,2*((self.pos.z+self.height/2.0) - inflictor.pos.z)));
				mwblastdamage = knockback;
				self.A_ChangeVelocity(-cos(knockbackangle)*knockback, -sin(knockbackangle)*knockback, knockbackz/5.0 );
			}
        	}
        	else if(mod == 'MightyBoot')
        	{
			float bpowerdiv = 1.0;
			if(source.species!="Dukes") { bpowerdiv = 2.0; }

			self.A_PlaySound("metal/hit");
			self.A_Pain();
			if(self.mass<100000) {
				if(self.default.height<60) {
					float knockbackangle = self.angle + deltaangle(self.angle,self.angleto(source));
					float knockback = 6.0 / bpowerdiv;
					float knockbackz = 0.0;
					self.A_ChangeVelocity(-cos(knockbackangle)*knockback, -sin(knockbackangle)*knockback, knockbackz/5.0 );
				} else if(self.default.radius<30) {
					float knockbackangle = self.angle + deltaangle(self.angle,self.angleto(source));
					float knockback = 1.5 / bpowerdiv;
					float knockbackz = 0.0;
					self.A_ChangeVelocity(-cos(knockbackangle)*knockback, -sin(knockbackangle)*knockback, knockbackz/5.0 );
				}
			}
        	}
        	else if(mod == 'RocketExplosion' || mod == 'Explosion' || mod == 'ShellExplosion')
        	{
			self.A_SpawnDebris("DukeMechParticle", mult_v: 1.0);
        	}

	    }

	    return super.DamageMobj(inflictor, source, damage, mod, flags, angle);
	}

	override bool Slam(Actor victim)
    	{
		if(victim && victim is "DeadDukeNukem")
		{
			return true;
		}

		if(victim && victim is "Inventory")
		{
			return true;
		}

	        return super.Slam(victim);
	}

	override void Die(Actor source, Actor inflictor, int dmgflags)
	{
		self.bDONTHARMCLASS = false;

		super.Die(source, inflictor, dmgflags);
	}

	override void Tick()
	{
		let inv = self.FindInventory("DukeDamagePickup");
		if (inv!=null && inv.Amount>0) {
			self.A_TakeInventory("DukeDamagePickup",1);
		}

		if (self.health>0 && self.bINVULNERABLE == false) {
			if (self.speed < self.default.speed) {
				self.speed = self.speed + 0.03;
				if (pcount<10) {
					self.A_SpawnItemEx("PlasmaSparkSmall",frandom[RIDFX](-radius/2.0,radius/2.0),frandom[RIDFX](-radius/2.0,radius/2.0),frandom[RIDFX](5,height/8.0*7.0),0,0,0,0,32, 254);
				} else if (pcount == 10) {
					self.A_SpawnItemEx("PlasmaSpark",frandom[RIDFX](-radius/2.0,radius/2.0),frandom[RIDFX](-radius/2.0,radius/2.0),frandom[RIDFX](5,height/8.0*7.0),0,0,0,0,32, 200);
					if ( self.health<=self.WoundHealth) {
						self.A_DamageSelf(100,"Plasma");
					} else {
						if (random[RIDMONSTERPROB](1,256)>64) {self.A_DamageSelf(1,"PlasmaSpark"); self.A_Wander();}
						else {self.A_DamageSelf(1);}
					}
				} else if (pcount<21) {
					self.A_SpawnItemEx("PlasmaSpark",frandom[RIDFX](-radius/2.0,radius/2.0),frandom[RIDFX](-radius/2.0,radius/2.0),frandom[RIDFX](5,height/8.0*7.0),0,0,0,0,32, 200);
				} else {
					pcount = -1;
				}
				pcount++;
			} else if (self.speed > self.default.speed) {
				self.speed = self.default.speed;
				pcount = 0;
				self.bFRIGHTENED = false;
			} else {
				pcount = 0;
				self.bFRIGHTENED = false;
			}

			if(mwcount>-1) {
				mwcount++;
				if ( mwcount > 240 ) {
					mwcount = -1;
				}
				else if (mwcount%3==0) {
					Zap(self, "d7 d7 d8", 1);
					self.A_SpawnItemEx("ExplosionSmokeFast22",Random[RIDFX](-radius,radius),Random[RIDFX](-radius,radius),Random[RIDFX](5,height),0,0,1,0,32, 200);
				}
				else if (mwcount%10==0) {
					if ( self.health<=self.WoundHealth) {
						self.A_DamageSelf(100,"Extreme");
					} else {
						if (random[RIDMONSTERPROB](1,256)>160) {self.A_DamageSelf(1,"PlasmaSpark");}
						else {self.A_DamageSelf(1);}
					}
				}
			}
		}

        	Super.Tick();

		if(mwfalldamage>-1) {
			if ( ( abs(pos.z-GetZAt())<=1 && GetZAt()==floorz ) || ( mwfalldamage>0 && vel.z==0 ) ) {
				self.A_SpawnProjectile("Duke_Smoke", height/2.0, 0, random[RIDFX](0, 360), 2, random[RIDFX](0, 360));
				self.A_SpawnProjectile("Duke_Smoke", height/2.0, 0, random[RIDFX](0, 360), 2, random[RIDFX](0, 360));
				self.A_SpawnProjectile("Duke_Smoke", height/2.0, 0, random[RIDFX](0, 360), 2, random[RIDFX](0, 360));

				if(self.health>0) {
					self.bNOBLOCKMONST = self.default.bNOBLOCKMONST;
					self.bFLOAT = self.default.bFLOAT;
					self.bNOGRAVITY = self.default.bNOGRAVITY;
				}
				mwcount = 0;
				if(mwfalldamage>=20) {self.A_SpawnDebris("DukeMechParticle", mult_v: 1.0); self.A_DamageSelf(mwfalldamage*1.0,"MightyBoot"); self.A_DamageSelf(mwfalldamage*1.0,"MightyBoot");}
				mwfalldamage=-1;
			} else if (vel.z<0) {
				Zap(self, "d7 d7 d8", 1);
				self.A_SpawnProjectile("Duke_Smoke", height/2.0, 0, random[RIDFX](0, 360), 2, random[RIDFX](0, 360));
				mwfalldamage++;
			}
		}
	}

}

class ZActorMetalBackswitch : ZBaseActorMetal
{
	bool armed;
	int count;

	Default
	{
		+USESPECIAL
		Activation THINGSPEC_ThingActs | THINGSPEC_ThingTargets;
	}

	override void PostBeginPlay()
	{
		self.A_SetSpecial(130, 0);

		Super.PostBeginPlay();
	}

	override void Activate(Actor activator)
	{
		Actor a = self;
		if(a.health<1) return;
		if(armed || activator==null || activator.target==null) return;
		let p = activator.target;
		double distance = a.distance3DSquared(p);

		if(absangle(a.angle,a.angleto(p))>115 && distance<80*80) {
			self.bUSESPECIAL = false;
			self.bFRIGHTENED = true;
			armed = true;
		}
	}

	override void Tick()
	{
        	if (armed && self.health>0) {
			if (count>60) {
				armed = false;
				self.A_Die();
			}
			else if (count%3==0) {
				self.A_PlaySound("LaserTripBomb/Detecte",11);
			}
			count++;
		}
       
        	Super.Tick();   
	}

}

class ZActorMetalDodgeMissile : ZBaseActorMetal
{
	int clock;

	override void Tick()
	{
	    if(clock==0) {
		    if (d3d_sentrydronedodge==1) {
	        	if ( InStateSequence(CurState, ResolveState("Missile")) || InStateSequence(CurState, ResolveState("See")) || InStateSequence(CurState, ResolveState("MissileEnd")) || InStateSequence(CurState, ResolveState("Pain")) ) {
				ActorIterator Finder = Level.CreateActorIterator(4500,"Actor");
				Actor mo;
				while ( (mo = Actor(Finder.Next())) )
				{
					if (!mo || mo == self || !mo.bMISSILE) { continue; }
					if (!CheckSight(mo)) { continue; }
					double mo_distance = self.distance2DSquared(mo);
					if (mo_distance > 350*350) { continue; }	
					if (absangle(self.angle,self.angleto(mo))>135) { continue; }
					self.tracer = mo;
					if (tracer.target) self.A_Face(tracer.target);
					if(deltaangle(self.angle,self.angleto(tracer))>=0)
						self.SetStateLabel("Dodge1");
					else
						self.SetStateLabel("Dodge2");
					break;
				}
			}
		    }
	    }
	    clock++;
	    if(clock==5) clock=0;
       
	    Super.Tick();   
	}

}