#include "defs.qh"
/*======================================================
	TESLA.QC			Custom TeamFortress v3.1	

	(c) William Kerney		5/21/00
	(c) Craig Hauser			19/3/00
========================================================
Weapons and functions for the Tesla Sentries
======================================================*/
#ifdef foobar
.ammo_shells  = voltage upgrades (0-3) 0 = 200 1 = 600 2 = 1200 3 = unlimitied
.ammo_nails   = amp upgrades (0-3) 0 = 30/1 secs 1 = 60/1 sec 2 = 120/s cont. 3 = 500/s
.ammo_rockets = power upgrades(0-3) 0 = 100 health/50 battery 1 = 200h/120b 2 = 350h/200b 3 = 500h/300b
.health = current health
.ammo_cells = Cells currently in battery, max cells always dynamically calculated
.maxhealth = max health
.tf_items NIT_AUTOID = spydetector upgrade (0-1) 0 = no spy 1 = tesla will attack disguised spies
.tf_items NIT_FLYING_SENTRY = turret upgrade (0-1) 0 = normal 1 = tesla launches into the air and attaches to ceiling
.tf_items NIT_SCANNER = Improved Targeter (0-1) 0 = normal checkclient 1 = radiuscan attacks enemy mines & demons, etc
.currentammo = total upgrades (0-5)
.waitmin = battery drain
Battery Drain = Power = I*V = (i+2)*(v+2) which will range between 4 to 25 cells per shot
Initial Attack Delay -- 0 = 1.5secs 1 = 1.5sec 2 = 1secs 3 = 2secs

//CH
.ammo_shells  = voltage upgrades (0-3) 0 = 200 1 = 600 2 = 1200 3 = 3000
.ammo_nails   = amp upgrades (0-3) 0 = 30/1 secs 1 = 60/1 sec 2 = 120/s cont. 3 = 500/s
.ammo_rockets = power upgrades(0-3) 0 = 100 health/50 battery 1 = 200h/120b 2 = 350h/200b 3 = 500h/300b
.health = health
.ammo_cells = Cells currently in battery
.maxammo_cells = Max cells
.maxhealth = max health
.tf_items NIT_AUTOID = spydetector upgrade (0-1) 0 = no spy 1 = tesla will attack disguised spies
.tf_items NIT_FLYING_SENTRY = turret upgrade (0-1) 0 = normal 1 = tesla launches into the air and attaches to ceiling
.tf_items NIT_SCANNER = Improved Targeter (0-1) 0 = normal checkclient 1 = radiuscan attacks enemy mines & demons, etc
.tf_items NIT_TESLA_CLOAKING = Cloaking device (0-1) 0=nothing 1=Cloaked unless firing does not glow
.tf_items NIT_KEVLAR = Kevlar Armor (0-1) 0=nothing 1=has Kevlar Armor
.tf_items NIT_BLAST = Blast Armor (0-1) 0=nothing 1=has Blast Armor
.has_sentry = Normal upgrades left
.has_tesla = Misc upgrades left
.waitmin = battery drain
Battery Drain = Power = I*V = (i+2)*(v+2) which will range between 4 to 25 cells per shot
Initial Attack Delay -- based on range/1000 (spy detector is range/500) amps and other stuff
#endif

float modelindex_tesla; //CH
// Tesla AI Functions
float() Tesla_FindTarget;
void() Tesla_FoundTarget;
void(entity attacker, float damage) Tesla_Pain;
void() Tesla_Die;
float() Tesla_Fire;
void() Tesla_Idle;
void() Tesla_Touch;

float() ReturnTeslaDelay;
entity(entity scanner, float scanrange) Tesla_RadiusScan;

entity(entity OldTesla) TeslaClone;


//--------- NEW TESLA MODEL (COIL.MDL) FRAMES ----------//
$frame on1 on2 on3 on4 on5 on6 on7
$frame fire1 fire2 fire3 fire4 fire5 fire6
//------------------------------------------------------//
//- I took this model from labyrinth server ------------//

void() Tesla_Check_Frags =
{
	switch (self.has_teleporter) {
		case 0:
			if (self.frags >= 10) {
				Tesla_Add_Rand_Upgrade(self, self.real_owner);
				self.has_teleporter = 1;
			}
			break;
		case 1:
			if (self.frags >= 20) {
				Tesla_Add_Rand_Upgrade(self, self.real_owner);
				self.has_teleporter = 2;
			}
			break;
		case 2:
			if (self.frags >= 30) {
				Tesla_Add_Rand_Upgrade(self, self.real_owner);
				self.has_teleporter = 3;
			}
			break;
		case 3:
			if (self.frags >= 40) {
				Tesla_Add_Rand_Upgrade(self, self.real_owner);
				self.has_teleporter = 4;
			}
			break;
		case 4:
			if (self.frags >= 50) {
				Tesla_Add_Rand_Upgrade(self, self.real_owner);
				bprint(PRINT_HIGH, self.real_owner.netname);
				bprint(PRINT_HIGH, " is a master of tesla placement, his tesla has at least 50 kills!!\n");
				self.has_teleporter = 5;
			}
			break;
		case 5:
			if (self.frags >= 60) {
				Tesla_Add_Rand_Upgrade(self, self.real_owner);
				self.has_teleporter = 6;
			}
			break;
		case 6:
			if (self.frags >= 70) {
				Tesla_Add_Rand_Upgrade(self, self.real_owner);
				self.has_teleporter = 7;
			}
			break;
		case 7:
			if (self.frags >= 80) {
				Tesla_Add_Rand_Upgrade(self, self.real_owner);
				self.has_teleporter = 8;
			}
			break;
		case 8:
			if (self.frags >= 90) {
				Tesla_Add_Rand_Upgrade(self, self.real_owner);
				self.has_teleporter = 9;
			}
			break;
		case 9:
			if (self.frags >= 100) {
				Tesla_Add_Rand_Upgrade(self, self.real_owner);
				bprint(PRINT_HIGH, self.real_owner.netname);
				bprint(PRINT_HIGH, " is a true legend at tesla placement, his tesla has at least 100 kills!!\n");
				self.has_teleporter = 10;
			}
			break;
	}
};
void() Tesla_Lose_Glow =
{
	if ((self.tf_items & NIT_TESLA_CLOAKING && (self.effects & EF_DIMLIGHT)) || self.job == 3)
	{
		if (self.is_haxxxoring == 0)
        {
            self.modelindex = modelindex_null;
            spawnFOG(self.origin);
            sound (self, CHAN_MISC, "misc/r_tele3.wav", 1, ATTN_NORM);
            if (self.job == 3) self.job = 1;
        }
	}
	self.effects &= ~EF_DIMLIGHT;
};
void() Tesla_Give_Glow =
{
	if (self.tf_items & NIT_TESLA_CLOAKING && !(self.effects & EF_DIMLIGHT))
	{
		if (self.is_haxxxoring == 0)
        {
            spawnFOG(self.origin);
            sound (self, CHAN_MISC, "misc/r_tele4.wav", 1, ATTN_NORM);

            self.pain_finished=1;
        }
	}
	self.effects |= EF_DIMLIGHT;
};

void() TeslaThink;

//-------------------------------------------------------------------------//
//- OfN - A new main think sub is needed for the new tesla model animation //
//-------------------------------------------------------------------------//
void()	tsla_on1	=[	$on1,		tsla_on2	] {self.job=1; TeslaThink();};
void()	tsla_on2	=[	$on1,		tsla_on3	] {TeslaThink();};
void()	tsla_on3	=[	$on2,		tsla_on4	] {TeslaThink();};
void()	tsla_on4	=[	$on2,		tsla_on5	] {TeslaThink();};
void()	tsla_on5	=[	$on3,		tsla_on6	] {TeslaThink();};
void()	tsla_on6	=[	$on3,		tsla_on7	] {TeslaThink();};
void()	tsla_on7	=[	$on4,		tsla_on8	] {TeslaThink();};
void()	tsla_on8	=[	$on4,		tsla_on9	] {TeslaThink();};
void()	tsla_on9	=[	$on5,		tsla_on10	] {TeslaThink();};
void()	tsla_on10	=[	$on5,		tsla_on11	] {TeslaThink();};
void()	tsla_on11   =[	$on6,		tsla_on12	] {TeslaThink();};
void()	tsla_on12	=[	$on6,		tsla_on13	] {TeslaThink();};
void()	tsla_on13	=[	$on7,		tsla_on14	] {TeslaThink();};
void()	tsla_on14	=[	$on7,		tsla_on1	] {TeslaThink();};
//--------------------------------------------------------------//
void()	tsla_fire1	=[	$fire1,		tsla_fire2	] {self.job=2; TeslaThink();};
void()	tsla_fire2	=[	$fire1,		tsla_fire3	] {TeslaThink();};
void()	tsla_fire3	=[	$fire2,		tsla_fire4	] {TeslaThink();};
void()	tsla_fire4	=[	$fire2,		tsla_fire5	] {TeslaThink();};
void()	tsla_fire5	=[	$fire3,		tsla_fire6	] {TeslaThink();};
void()	tsla_fire6	=[	$fire3,		tsla_fire7	] {TeslaThink();};
void()	tsla_fire7	=[	$fire4,		tsla_fire8	] {TeslaThink();};
void()	tsla_fire8	=[	$fire4,		tsla_fire9	] {TeslaThink();};
void()	tsla_fire9	=[	$fire5,		tsla_fire10	] {TeslaThink();};
void()	tsla_fire10	=[	$fire5,		tsla_fire11	] {TeslaThink();};
void()	tsla_fire11	=[	$fire6,		tsla_fire12	] {TeslaThink();};
void()	tsla_fire12	=[	$fire6,		tsla_fire1	] {TeslaThink();};


void() TeslaThink =
{    
    if (self.pain_finished == 1) // replace tesla entity if it was cloaked
    {
        local entity TSelf;
        TSelf=TeslaClone(self);
        dremove(self);
        self=TSelf;
        self.pain_finished=0;
        self.nextthink=time;
        return;
    }
    
    self.nextthink = time + 0.05;
   
    if (self.has_holo <= time && self.no_grenades_1 == FALSE)
    {
        self.no_grenades_1 = TRUE; 
        Tesla_Idle();
    }
   
    if (self.job == 1 && self.effects & EF_DIMLIGHT)
    {
        tsla_fire1();
        return;
    }
    else if (self.job == 2 && !(self.effects & EF_DIMLIGHT))
    {
        tsla_on1();
        return;
    }
};

//Main loop for tesla - OfN - was
void() Tesla_Idle =
{
    if (self.is_malfunctioning & SCREWUP_ONE)
    {
        self.has_holo = time + 0.25; //FIXED - unhacked teslas work again
        self.no_grenades_1 = FALSE;
        return;
    }
	
	if (self.tf_items & NIT_TELEPORTER) //CH
		Tesla_Check_Frags();
		
	//self.waitmax holds if we have a target
	if (self.waitmax) //If we have target, shoot it
	        self.waitmax = Tesla_Fire();
    
	if (!self.waitmax)
	{
		self.attack_finished = 1;
        //Try to reacquire target
		Tesla_Lose_Glow ();
		self.has_holo = time + 0.25;
		self.no_grenades_1 = FALSE;
		if (Tesla_FindTarget())
			self.waitmax = TRUE;
	}
	
	if (self.attack_finished < 1)
		self.attack_finished = self.attack_finished + 0.1;
	
	//self.think = Tesla_Idle; //WK Unecessary but keeps us in the loop
};

float() Tesla_FindTarget =
{
	local entity client;

	//WK Hack to get floating tesla working
	if (self.tf_items & NIT_TURRET)
		self.origin_z = self.origin_z - 40;//40;
	//else
	//	self.origin_z = self.origin_z + 24;

	self.oldenemy = NIL; //CH for sbar

	if (self.ammo_shells == 0)
		client = Tesla_RadiusScan (self, 400);
	else if (self.ammo_shells == 1)
		client = Tesla_RadiusScan (self, 800);
	else if (self.ammo_shells == 2)
		client = Tesla_RadiusScan (self, 1200);
	else
		client = Tesla_RadiusScan (self, 3500); //I dont think that anyone would be this far away

	//WK Unhack our hack
	if (self.tf_items & NIT_TURRET)
		self.origin_z = self.origin_z + 40;//+ 40;
	//else
	//	self.origin_z = self.origin_z - 24;

	if (client != self)
	{
		// Found a Target
		/*if (self.enemy == client) //Recovering lock
			return Tesla_Fire();*/ // SB not any more you're not

		self.enemy = client;
		self.oldenemy = self.enemy; //CH for sbar
	
		Tesla_FoundTarget ();

		return TRUE;
	}
	return FALSE;
};

void() Tesla_FoundTarget =
{
	// Cannon Powerup Sound?
	if (self.ammo_cells > self.waitmin)
		sound (self, CHAN_VOICE, "weapons/guerilla_set.wav", 1, ATTN_NORM);

	//Glow
	Tesla_Give_Glow();

	self.goalentity = self.enemy;

	//self.nextthink = time + ReturnTeslaDelay();
    self.has_holo = time + ReturnTeslaDelay(); //- OfN -
    self.no_grenades_1 = FALSE;
};

void(entity attacker, float damage) Tesla_Pain =
{
	if (self.health < 0)
		return;

	// Update the owner's status bar
	self.real_owner.StatusRefreshTime = time + 0.2;
//CH special sbar  for eng.
	self.real_owner.StatusBarScreen = 4;

	local string st = infokey (NIL, "sentry_revenge");

	if (!st)
		st = infokey (NIL, "sr");

	if (!self.waitmax && (st == "yes" || st == "1" || st == "on"))
	{
	    self.enemy = attacker;
	    self.waitmax = TRUE;
	    Tesla_FoundTarget();
	}
};

void() Tesla_Die =
{
	sprint(self.real_owner, PRINT_HIGH, "Your tesla gun was destroyed.\n");
	self.real_owner.has_tesla = self.real_owner.has_tesla - 1;
	if (self.real_owner.has_tesla < 0)
		self.real_owner.has_tesla = 0;
//CH REAL tesla gibs
	ThrowGib("progs/tesgib1.mdl", -70);
	ThrowGib("progs/tesgib2.mdl", -70);
	ThrowGib("progs/tesgib3.mdl", -70);
    ThrowGib("progs/tesgib4.mdl", self.skin);
    ThrowGib("progs/tesgib4.mdl", self.skin);

	WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
	WriteByte (MSG_MULTICAST, TE_EXPLOSION);
	WriteCoord (MSG_MULTICAST, self.origin_x);
	WriteCoord (MSG_MULTICAST, self.origin_y);
	WriteCoord (MSG_MULTICAST, self.origin_z);
	multicast (self.origin, MULTICAST_PHS);
    dremove(self);
};

float (vector where) DoorsAt = 
{
	traceline (where, where, FALSE, self);
	if (trace_ent.classname == "door" || trace_ent.classname == "plat")
		return TRUE;
	else
		return FALSE;
};

float() Tesla_Fire =
{
	local float damage = 0;
	local float cheater = FALSE;
	local vector below;

	if (self.tf_items & NIT_TURRET)
	{
		below = '0 0 1';	// So as not to hit tesla.
		below_z = below_z + self.size_z; // Below should be 1 unit below the tesla.

		// Check a varity of locations for a door. 5 and -5 should be the with of tesla
		if (DoorsAt(self.origin - below + '0 0 0'))
			cheater = TRUE;
		if (DoorsAt(self.origin - below + '8 0 0'))
			cheater = TRUE;
		if (DoorsAt(self.origin - below + '-8 0 0'))
			cheater = TRUE;
		if (DoorsAt(self.origin - below + '0 8 0'))
			cheater = TRUE;
		if (DoorsAt(self.origin - below + '0 -8 0'))
			cheater = TRUE;

		if (cheater){
			sprint(self.real_owner,PRINT_HIGH,"The door's wiring conflicts with your tesla's!\n");
			TF_T_Damage(self,NIL,NIL,self.health+100,0,0);
			return FALSE;
		}
	}
	//WK Stop gun from shooting at dead spies
	if (!self.enemy)
		return FALSE;
	if (!self.enemy)
		return FALSE;
	if (self.enemy == self)
		return FALSE;
	if (self.enemy.health <= 0)
		return FALSE;
	if (infokey(NIL,"ceasefire")=="on") //CH
		return FALSE;
	if (self.enemy.classname == "player")
	{
		if (self.enemy.has_disconnected)
		{
			self.enemy = NIL;
			return FALSE;
		}
		if (!(self.tf_items & NIT_AUTOID))
		{
			if (self.enemy.is_feigning)
				return FALSE;
#if 0 // pharse handles these two, we can still hit thieves and spies if they attack us. feign still fools us tho
			if (self.enemy.is_undercover) //haha, even to their own team? yeah right. No thanks
				return FALSE;

			if (self.enemy.job & JOB_THIEF && self.enemy.job & JOB_ACTIVE) // pharse handles this
				return FALSE;
#endif
		}
	}
	//CH rechecks if target is out of range,  has a little extra room added.
	// SB +100 for each one, values were incorrect before
    local float maxrange;
    maxrange = 500;

    if (self.ammo_shells == 0)
		maxrange = 500;
	else if (self.ammo_shells == 1) //+300 no
		maxrange = 900;
	else if (self.ammo_shells == 2) //+500 no
		maxrange = 1300;
	else if (self.ammo_shells == 3) //+800 no
		maxrange = 4100;

	/*if (self.ammo_shells == 0 && vlen(self.origin - self.enemy.origin) >= 500)
		return FALSE;
	else if (self.ammo_shells == 1 && vlen(self.origin - self.enemy.origin) >= 900) //+300 no
		return FALSE;
	else if (self.ammo_shells == 2 && vlen(self.origin - self.enemy.origin) >= 1300) //+500 no
		return FALSE;
	else if (self.ammo_shells == 3 && vlen(self.origin - self.enemy.origin) >= 4100) //+800 no
		return FALSE;*/

    if (vlen(self.origin - self.enemy.origin) >= maxrange) //+800 no
		return FALSE;

	self.oldenemy = self.enemy; //CH for sbar

	//WK Hack to get floating sentry working - reset before all the returns
	if (self.tf_items & NIT_TURRET) self.origin_z = self.origin_z - 40;// 40
	//else self.origin_z = self.origin_z + 24;
	
	if (!visible2(self.enemy, self))
	{
		if (self.tf_items & NIT_TURRET) self.origin_z = self.origin_z + 40; // 40
		//else self.origin_z = self.origin_z - 24;
		return FALSE;
	}

	self.ammo_cells = self.ammo_cells - self.waitmin; //Waitmin is precalculated cost
	if (self.ammo_cells < 0)
	{
		self.ammo_cells = 0;
		if (self.tf_items & NIT_TURRET) self.origin_z = self.origin_z + 40; // 40
		//else self.origin_z = self.origin_z - 24;
		self.enemy = NIL;
		return FALSE;
	}

	Tesla_Give_Glow(); //FIXED

	if (self.is_malfunctioning & SCREWUP_THREE)
	{
		local float damg;
		damg = random() * 100 + 200 * self.ammo_nails; // the bigger they come, the harder they fall
		deathmsg = DMSG_LIGHTNING;
		WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
		WriteByte (MSG_MULTICAST, TE_EXPLOSION);
		WriteCoord (MSG_MULTICAST, self.origin_x);
		WriteCoord (MSG_MULTICAST, self.origin_y);
		WriteCoord (MSG_MULTICAST, self.origin_z);
		T_RadiusDamage(self, self, damg, NIL);
		if (self.tf_items & NIT_TURRET) self.origin_z = self.origin_z + 40; // 40
		//else self.origin_z = self.origin_z - 24;
		return FALSE;
	}
		
	deathmsg = DMSG_LIGHTNING;

 // OfN - Check for force field

    traceline (self.origin, self.enemy.origin, FALSE, self);

        WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
        WriteByte (MSG_MULTICAST, TE_LIGHTNING2);
        WriteEntity (MSG_MULTICAST, self);
        WriteCoord (MSG_MULTICAST, self.origin_x);
        WriteCoord (MSG_MULTICAST, self.origin_y);
        if (self.tf_items & NIT_TURRET)
            WriteCoord (MSG_MULTICAST, self.origin_z + 10);
        else
            WriteCoord (MSG_MULTICAST, self.origin_z + 30);        
        WriteCoord (MSG_MULTICAST, trace_endpos_x);
        WriteCoord (MSG_MULTICAST, trace_endpos_y);
        WriteCoord (MSG_MULTICAST, trace_endpos_z);
        multicast (self.origin, MULTICAST_PHS);
        
	if (trace_ent.classname == "force_field")
	{
          FieldExplosion(trace_ent,trace_endpos,trace_ent);
          PutFieldWork(trace_ent);
	}

	sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
	if (vlen(self.enemy.origin - self.origin) >= 800 && vlen(trace_endpos - self.enemy.origin) <= 100) //Only play end sound if far away
		sound (self.enemy, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM); //CH at start and end of arc

    /*if (self.ammo_nails == 0) damage = 40;
	if (self.ammo_nails == 1) damage = 80;
	if (self.ammo_nails == 2) damage = 160;
	if (self.ammo_nails == 3) damage = 320;*/

    if (self.ammo_nails == 0) damage = 40;
	if (self.ammo_nails == 1) damage = 80;
	if (self.ammo_nails == 2) damage = 130;
	if (self.ammo_nails == 3) damage = 240;


    if (self.num_mines & IMPROVED_FOUR) damage = damage * 1.15; //- OfN - Improved circuit hack - was 1.2 - TOO LOW NOW?

	if (self.is_malfunctioning & SCREWUP_TWO) damage = 1;
	//TF_T_Damage (self.enemy, self, self.real_owner, damage, TF_TD_NOTTEAM, TF_TD_ELECTRICITY);
	

        //TF_T_Damage (self.enemy, self, self, damage, TF_TD_NOTTEAM, TF_TD_ELECTRICITY);

	local vector org = self.origin;
	if (self.tf_items & NIT_TURRET)
	   org_z += 10;
	else
	   org_z += 30;

	LightningDamage(org, self.enemy.origin, self, damage);

	//self.nextthink = time + ReturnTeslaDelay();
    //self.has_holo = time + ReturnTeslaDelay(); //?? wTF
    
    	self.attack_finished = 1;
    
    self.has_holo = time + ReturnTeslaDelay(); //- OfN -
    self.no_grenades_1 = FALSE;

	// Warn owner that it's low on ammo
	if (self.ammo_cells == 0 && (random() < 0.1))
		sprint(self.real_owner, PRINT_HIGH, "Tesla is out of cells.\n");
	else if (self.ammo_cells <= self.waitmin)
		sprint(self.real_owner, PRINT_HIGH, "Tesla is low on cells.\n");

	if (self.tf_items & NIT_TURRET) self.origin_z = self.origin_z + 40; //40
	//else self.origin_z = self.origin_z - 24;

	//self.attack_finished = 1;

	if (self.enemy.health <= 0)
	{
		self.enemy = NIL;
		return FALSE;
	}
	return TRUE;
	
};

//WK Sentry Touch function
//Will kill bad guy 
void() Tesla_Touch =
{
	local vector below;
	local float cheater;
	cheater = FALSE;

	//WK Check for blockage
	if (entpointcontents(self) == CONTENTS_SKY)
	{
		sprint(self.real_owner, PRINT_HIGH, "Your sentry gun flew away.\n");
		Tesla_Die();
		return;
	}

    if (other.classname=="player" && !(self.tf_items & NIT_TURRET) && (self.tf_items & NIT_TESLA_CLOAKING) && self.no_grenades_2 < time && self.job == 1 && Teammate(self.team_no,other.team_no))
    {
        if (self.real_owner == other)
            sprint(other,PRINT_HIGH,"Your cloaked tesla here!\n"); 
        else
            sprint(other,PRINT_HIGH,"There is a cloaked friendly tesla here!\n");

        self.no_grenades_2 = time + 2;
    }

	if (other.takedamage && !(self.tf_items & NIT_TURRET))  // OfN - fixme: doesn't check for enemy disguised spies
	{
		deathmsg = DMSG_BUG_ZAPPER;
        
        if (IsMonster(other))
        {
            if (!Teammate(other.real_owner.team_no, self.real_owner.team_no))
            {
                TF_T_Damage (other, self, self, 400, TF_TD_NOTTEAM, TF_TD_ELECTRICITY);
        		return;
            }
            
            return;
        }

		if (!Teammate(other.team_no, self.real_owner.team_no) && (other.is_undercover != 1)) // <== FIXME
			//TF_T_Damage (other, self, self.real_owner, 400, TF_TD_NOTTEAM, TF_TD_ELECTRICITY);
			TF_T_Damage (other, self, self, 400, TF_TD_NOTTEAM, TF_TD_ELECTRICITY);
		return;
	}
	//I'm in midflight and hit something
	if (self.tf_items & NIT_TURRET && self.movetype == MOVETYPE_FLY) 
	{
		//WK Check to see if we are blocked
		if (entpointcontents(self) == CONTENTS_SKY)
		{
			sprint(self.real_owner, PRINT_HIGH, "Your tesla flew away.\n");
			Tesla_Die();
			return;
		}
		below = '0 0 1';	// So as not to hit tesla.
		below_z = below_z + self.size_z;

		// Check a varity of locations for a door. 5 and -5 should be the with of tesla
		if (DoorsAt(self.origin - below + '0 0 0'))
			cheater = TRUE;
		if (DoorsAt(self.origin - below + '8 0 0'))
			cheater = TRUE;
		if (DoorsAt(self.origin - below + '-8 0 0'))
			cheater = TRUE;
		if (DoorsAt(self.origin - below + '0 8 0'))
			cheater = TRUE;
		if (DoorsAt(self.origin - below + '0 -8 0'))
			cheater = TRUE;

		if (cheater){
			sprint(self.real_owner,PRINT_HIGH,"The door's wiring conflicts with your tesla's!\n");
			TF_T_Damage(self,NIL,NIL,self.health+100,0,0);
			return;
		}

		if (!other)
		{ //The eagle has landed!
		//	sprint(self.real_owner, PRINT_HIGH, "The eagle has landed!\n");
			self.solid = SOLID_BBOX;
			self.flags |= FL_ONGROUND;
			self.movetype = MOVETYPE_STEP;
			self.origin_z = self.origin_z + 40;

            self.is_haxxxoring=0; // this flag is for cloaked teslas be able to cloak again

            if (self.job == 1)
            {
                self.effects |= EF_DIMLIGHT; // hack to make lose_glow to run properly to make disappear again the tesla
                Tesla_Lose_Glow();
            }

			return;
		}
		else if (other.classname == "player")
		{
			deathmsg = DMSG_BUG_ZAPPER;
			//TF_T_Damage (other, self, self.real_owner, 400, TF_TD_NOTTEAM, TF_TD_ELECTRICITY);
			TF_T_Damage (other, self, self, 400, TF_TD_NOTTEAM, TF_TD_ELECTRICITY);

            self.velocity_z = 200; //- OfN reset velocity, not stop
		}
		else
		{
			deathmsg = DMSG_BUG_ZAPPER;
			//TF_T_Damage (other, self, self.real_owner, 400, TF_TD_NOTTEAM, TF_TD_ELECTRICITY);
			if (!Teammate(other.real_owner.team_no,self.real_owner.team_no))
				TF_T_Damage (other, self, self, 400, TF_TD_NOTTEAM, TF_TD_ELECTRICITY);
			//sprint(self.real_owner, PRINT_HIGH, "The eagle has died.\n");
			Tesla_Die();
		}
	}
};
//========
//CH this sets the 'charge time' needed in order to fire at the target.
//Using the idea that a certain charge has to be generated in order for the current to arc to the enemy
//The time it takes to make this charge would be based on distance and amp plus some extras
//Thus fast firing close and slower as you get away and or the more amps to generate.
//This code works nicely to do that :)
float() ReturnTeslaDelay =
{
	local float r;
	local float tesladelay;
  
	if (self.ammo_nails == 0) //Initial delay based on AMPS
		tesladelay = 0.5;
	else if (self.ammo_nails == 1) //So its not as fast,  but still fast
		tesladelay = 0.75;
	else if (self.ammo_nails == 2)
		tesladelay = 1;
	else
		tesladelay = 1.5;

	if (self.enemy.cutf_items & CUTF_JAMMER) // if we have jammer - Share and Enjoy!
		tesladelay = tesladelay + 0.5;
		
	r = vlen(self.enemy.origin - self.origin);
	if (self.tf_items & NIT_AUTOID) //spy detect takes twice as long, as it does more in depth search
		tesladelay = tesladelay + (r / 500);
	else
		tesladelay = tesladelay + (r / 1000);

	// Invisible people take longer for sentries to lock onto, MAY HAPPEN
	if (self.enemy.modelindex == modelindex_null)
		tesladelay = tesladelay + 2;	// Must acquire a heat signal
	else if (self.enemy.modelindex == modelindex_eyes)
		tesladelay = tesladelay + 1;	// Some visual, so its a little easier

	//Improved targetter decreases lock time to 5/8
	//WK Changed to 7/8ths
	// Changed back again, what a lame item
	if (self.tf_items & NIT_SCANNER)
		tesladelay = (tesladelay * 5) / 8;

    if (self.num_mines & IMPROVED_FOUR) tesladelay = tesladelay * 0.85; //was 0.8

	tesladelay = tesladelay * self.attack_finished; // SB so we don't fire instantly at old targ...
	// SB this also means we don't have to fully charge for new target
	self.attack_finished = 0;
	
	return tesladelay;
};
//=========================================================================
// Returns a list of players within a radius around the origin, like findradius,
// except that some parsing of the list can be done based on the parameters passed in.
// Make sure you check that the return value is not NULL b4 using it.
entity(entity scanner, float scanrange) Tesla_RadiusScan =
{
	local entity head;
	local float gotatarget;

	head = findradius(scanner.origin, scanrange);

	while (head)
	{
		gotatarget = 0;
		if (vlen(head.origin - scanner.origin) <= scanrange && head != scanner && visible2(head,scanner))
		{
			if (head.classname == "player")
            #ifdef MAD_TESLA
                gotatarget = 1;
            #else
                gotatarget = Pharse_Client(head, scanner, 1, 0, 1, 1);
            #endif
			else if (scanner.tf_items & NIT_SCANNER && scanner.team_no > 0) //Improved targeter
			{
				if (head.classname == "monster_demon1")
				{
					if (!Teammate(head.real_owner.team_no,scanner.team_no))
						gotatarget = 1;
				}
				if (head.classname == "monster_army")
				{
					if (!Teammate(head.real_owner.team_no,scanner.team_no))
						gotatarget = 1;
				}
				if (head.classname == "monster_shambler")
				{
					if (!Teammate(head.real_owner.team_no,scanner.team_no))
						gotatarget = 1;
				}
                if (head.classname == "monster_wizard") //- OfN
				{
					if (!Teammate(head.real_owner.team_no,scanner.team_no))
						gotatarget = 1;
				}
				else if (head.classname == "grenade" && head.netname == "land_mine")
				{
					if (!Teammate(head.owner.team_no, scanner.team_no))
						gotatarget = 1;
				}
				else if (!Teammate(head.team_no,scanner.team_no))
				{
					if (IsBuilding(head) && head.classname != "building_sentrygun_base")
						gotatarget = 1;
				}
			}		
		}
		if (gotatarget)
			return head;

		head = head.chain;
	}
	return scanner;
};

//==========================================================//
//- Ofn - ugly hack i know... ------------------------------//
//- This is needed for the cloaking tesla to work ----------//

entity(entity OldTesla) TeslaClone =
{
    newmis = spawn();

    //here the updates of any entity pointers (demon_two and building for players, plus goalentity and enemy for grunts)
    OldTesla.solid=SOLID_NOT;

    local entity te;
    local vector tmp1, tmp2;

    //now hack inside hack! =)
    te = find(NIL, classname, "player");
    while (te)
	{
        if (te.is_haxxxoring) // if we r currently hacking...
        {
            if (te.demon_two.martyr_enemy==OldTesla) // ...this tesla
                te.demon_two.martyr_enemy=newmis; //UPDATE IT

        }
        else if (te.demon_two == OldTesla) // if we r targetting this tesla for a hack
        {
            te.demon_two = newmis; // UPDATE POINTER
        }


        if (te.building == OldTesla) // if we r fixing (menu) this tesla..
            te.building = newmis; // update it

		te = find(te, classname, "player");
	}

    te = find(NIL, classname, "monster_army");
    while (te)
	{
        if (te.goalentity == OldTesla)
            te.goalentity = newmis;
        if (te.enemy == OldTesla)
            te.enemy = newmis;        

		te = find(te, classname, "monster_army");
	}

    //solid_not also

    //newmis.origin = self.origin + v_forward;
    newmis.origin = OldTesla.origin;

    tmp1 = '-16 -16 -25';
    //tmp2 = '16 16 48'; //WK 62 is better, but crashes?
    tmp2 = '16 16 23';

    //newmis.mdl = "progs/newtesla.mdl";
    newmis.mdl = "progs/coil.mdl";
    newmis.netname = "tesla";
    //newmis.origin = newmis.origin + '0 0 25';
    newmis.origin = OldTesla.origin;

    newmis.owner = OldTesla.owner;
    newmis.real_owner = OldTesla.real_owner;//self;

	newmis.think = OldTesla.think;
    newmis.nextthink = time + 0.05;

	newmis.colormap = OldTesla.colormap;
	newmis.weapon = BUILD_TESLA;
	//newmis.angles_y = anglemod(self.angles_y + 180);
    newmis.angles = OldTesla.angles;

	//newmis.velocity = '0 0 8';
    newmis.velocity = OldTesla.velocity; // AVOIDS TURRET LAUNCHING BUG?
	newmis.movetype = OldTesla.movetype;// MOVETYPE_TOSS;    

	newmis.solid = SOLID_BBOX; // ;
	setmodel (newmis, newmis.mdl);
	setsize (newmis, tmp1, tmp2);
	setorigin (newmis, newmis.origin);

    //if (objtobuild==BUILD_TESLA) newmis.skin = self.team_no;
    //if (self.team_no==3) newmis.skin=0;
    //else if (self.team_no==4) newmis.skin=3;

    newmis.skin = OldTesla.skin; //

	//newmis.flags &= ~FL_ONGROUND;
    newmis.flags = OldTesla.flags;

    ///////////////////////////

    newmis.classname = "building_tesla";
    newmis.netname = "tesla";
    newmis.takedamage = OldTesla.takedamage; //DAMAGE_AIM;
    //newmis.solid = SOLID_BBOX;
    newmis.th_die = OldTesla.th_die; //Tesla_Die; 		// Death function
    newmis.th_pain = OldTesla.th_pain; //Tesla_Pain; // BUG WAS DIE!!
    //self.ammo_cells = self.ammo_cells - BUILD_COST_TESLA;

    newmis.health = OldTesla.health; //BUILD_HEALTH_TESLA;
    newmis.movetype = OldTesla.movetype; //MOVETYPE_TOSS;
    newmis.colormap = OldTesla.colormap; //self.colormap;	// Set the Base Color
    //newmis.velocity = '0 0 -8';
    newmis.avelocity = '0 0 0';
    newmis.flags = OldTesla.flags; // &= ~FL_ONGROUND;
    newmis.team_no = OldTesla.team_no;
    
    //- OfN -
    //newmis.think = OldTesla.think;
    
    //newmis.nextthink = time + 0.1;
    newmis.has_holo = OldTesla.has_holo; // next Tesla_Idle run
    newmis.job = OldTesla.job; // this flag will determine which frame animation is currently on
    
    //newmis.job_finished = time; // change for frame animation purposes, instead of increasing its nextthing during charging
    newmis.job_finished = OldTesla.job_finished;

    newmis.no_grenades_1 = OldTesla.no_grenades_1; //FALSE; // first think reset
    newmis.no_grenades_2 = OldTesla.no_grenades_2; //0; // cloak touch delay reset

    newmis.touch = Tesla_Touch;
    newmis.enemy = OldTesla.enemy; //NIL;
    newmis.oldenemy = OldTesla.oldenemy; //NIL; //CH for sbar

    //Set all initial tesla values here
    newmis.maxammo_shells = OldTesla.maxammo_shells; //Voltage == 0
    newmis.maxammo_nails = OldTesla.maxammo_nails; //Amps == 0
    newmis.maxammo_rockets = OldTesla.maxammo_rockets; //Battery == 0
    newmis.max_health = OldTesla.max_health;//150;
    newmis.ammo_cells = OldTesla.ammo_cells; //MAXCELLS0; //Initial ammo allocation
    newmis.maxammo_cells = OldTesla.maxammo_cells; //MAXCELLS0; //Initial maxammo
    newmis.tf_items = OldTesla.tf_items; //NIT_CERAMIC; //Start with shock armor
    newmis.armorclass = OldTesla.armorclass; //AT_SAVEELECTRICITY; //Shock armor

    newmis.has_sentry = OldTesla.has_sentry;
    newmis.has_tesla = OldTesla.has_tesla;
    newmis.has_teleporter = OldTesla.has_teleporter; //0; //CH for frag related upgrades
    

    newmis.ammo_shells = OldTesla.ammo_shells;
    newmis.ammo_nails = OldTesla.ammo_nails;
    newmis.ammo_rockets = OldTesla.ammo_rockets;

    newmis.health = OldTesla.health; 
    //newmis.health = newmis.max_health;
    newmis.waitmin = OldTesla.waitmin; //(newmis.ammo_shells + 2) * (newmis.ammo_nails + 2);
    newmis.waitmax = OldTesla.waitmax; //FALSE; //No target yet

    newmis.frags = OldTesla.frags; //0; //CH how many people has your sent killed?
    newmis.lip   = OldTesla.lip; //0; //WK How many tinkers have been done
    //modelindex_tesla = newmis.modelindex; //CH

    newmis.num_mines=OldTesla.num_mines; //0; // OfN - reset HACKER improvements
    newmis.is_malfunctioning = OldTesla.is_malfunctioning;
    
    //newmis.waitmax=FALSE;

    newmis.pain_finished=0;

    newmis.effects=OldTesla.effects;
    newmis.is_haxxxoring=OldTesla.is_haxxxoring;

    return newmis;
};