mirror of
https://git.code.sf.net/p/quake/prozac-qfcc
synced 2024-11-23 12:42:39 +00:00
986 lines
31 KiB
C++
986 lines
31 KiB
C++
#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 = self.effects - (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 = 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 = 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 = 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 = newmis.flags - (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; // newmis.flags - (newmis.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;
|
|
};
|
|
|
|
|