prozac-qfcc/scout.qc

1037 lines
26 KiB
C++

#include "defs.qh"
/*====================================================
SCOUT.QC
TeamFortress v2.5 29/2/97
Craig Hauser 26/3/00
======================================================
Functions for the SCOUT class and associated weaponry
======================================================*/
// Functions outside this file
// Functions inside this file
// Concussion Grenade Functions
void() ConcussionGrenadeTouch;
void() ConcussionGrenadeExplode;
void() ConcussionGrenadeTimer;
// Scanner Functions
void(float scanrange,float inAuto) TeamFortress_Scan;
void(entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce;
entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan;
//void(entity pl, string s1) CenterPrint;
void(entity pl, float fTime, string s1) StatusPrint;
//=========================================================================
// Touch Function for Flash Grenade
void() FlashGrenadeTouch =
{
// If the Flash Grenade hits a player, it just bounces off
sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
if (self.velocity == '0 0 0')
self.avelocity = '0 0 0';
};
#ifdef NET_SERVER
#define SMOOTH_FLASH 0.3
#else
#define SMOOTH_FLASH 0.1
#endif
void() FlashTimer =
{
local entity te;
te = self.owner;
if (te.has_disconnected) //WK Safety, now that we call this to clean up after death
return;
te.FlashTime = te.FlashTime - SMOOTH_FLASH;
if (te.FlashTime < 4 && te.FlashTime != -1)
{
te.FlashTime = 0;
stuffcmd(te, "v_cshift 0 0 0 0\n");
return;
}
local string st;
// Sequential III math proved useful! GR
st = ftos(-0.1 * (te.FlashTime - 5) * (te.FlashTime - 115));
stuffcmd(te, "v_cshift 0 0 0 " + st + "\n");
self.nextthink = time + SMOOTH_FLASH;
};
//=========================================================================
// Flash Grenade explode function, for when the PRIMETIME runs out
void() FlashGrenadeExplode =
{
local entity te;
local float loopc = 0;
self.effects |= EF_BRIGHTLIGHT;
sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
// Find all people in area
while (loopc < 32)
{
te = checkclient();
// Player?
if (te && te.classname == "player")
{
makevectors(te.v_angle);
// Damage player and explode
// no, don't damage
if (te.health > 0 && (normalize(self.origin - te.origin) * v_forward > -0.5) && visible(te))
{
local float ft = 60 - (vlen(self.origin - te.origin) * 6 / 50);
if (te.FlashTime == 0)
{
// create flash timer
newmis = spawn();
newmis.classname = "timer";
newmis.netname = "flashtimer";
newmis.team_no = self.owner.team_no;
newmis.owner = te;
newmis.think = FlashTimer;
newmis.nextthink = time + 0.1;
newmis.heat = 1;
}
if (ft > 0)
te.FlashTime = ft;
stuffcmd (te, "v_cshift 255 255 255 245; bf\n"); // big white flash
}
}
loopc++;
}
#ifdef DEMO_STUFF
// Remove any camera's locks on this missile
if (self.enemy)
CamProjectileLockOff();
#endif
dremove(self);
};
//=========================================================================
// Touch function for a concussion grenade
void() ConcussionGrenadeTouch =
{
// concussion grenades bounce off other players now
sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); // bounce sound
if (self.velocity == '0 0 0')
self.avelocity = '0 0 0';
};
//=========================================================================
// Concussion grenade explosion function
void() ConcussionGrenadeExplode =
{
T_RadiusBounce (self, self.owner, 240, nil);
#ifdef DEMO_STUFF
// Remove any camera's locks on this missile
if (self.enemy)
CamProjectileLockOff();
#endif
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);
};
//=========================================================================
// Concussion grenade timer to remove idlescale
void() ConcussionGrenadeTimer =
{
if (self.owner.invincible_finished > time)
{
sprint(self.owner, PRINT_HIGH, "The power heals your concussion\n");
stuffcmd(self.owner, "v_idlescale 0\n");
self.owner.mangle = '0 0 0';
self.owner.tfstate &= ~TFSTATE_CONCUSSIONED;
dremove(self);
return;
}
#ifdef GR_CONCUSS_BUBBLETIME
if (self.has_tesla < time)
{
newmis = spawn();
setmodel (newmis, "progs/s_bubble.spr");
setorigin (newmis, self.owner.origin);
newmis.movetype = MOVETYPE_NOCLIP;
newmis.solid = SOLID_NOT;
newmis.velocity = '0 0 15';
newmis.nextthink = time + 0.5;
newmis.think = bubble_bob;
newmis.touch = bubble_remove;
newmis.classname = "bubble";
newmis.frame = 0;
newmis.cnt = 0;
setsize(newmis, '-8 -8 -8', '8 8 8');
self.has_tesla += GR_CONCUSS_BUBBLETIME;
}
#endif
self.health = self.health - GR_CONCUSS_DEC;
// medic recovers twice as fast
if (self.owner.weapons_carried & WEAP_MEDIKIT) //WK
self.health = self.health - GR_CONCUSS_DEC;
if (self.owner.cutf_items & CUTF_STEALTH)
self.health = self.health - GR_CONCUSS_DEC;
if (self.owner.cutf_items & CUTF_GYMNAST)
self.health = self.health - GR_CONCUSS_DEC;
if (self.health < 0)
self.health = 0;
if (self.health == 0)
{
sprint (self.owner, PRINT_HIGH, "Your head feels better now\n");
#ifdef OLD_CONC_GRENADE
stuffcmd (self.owner, "v_idlescale 0\n");
#endif
self.owner.mangle = '0 0 0';
self.owner.tfstate &= ~TFSTATE_CONCUSSIONED;
dremove(self);
return;
}
self.nextthink = time + GR_CONCUSS_TIME;
#ifdef OLD_CONC_GRENADE
stuffcmd(self.owner, "v_idlescale " + ftos (self.health * GR_CONCUSS_IDLE) + "\n");
#else
if (self.has_camera < time)
{
self.owner.mangle = '0 0 0';
#ifdef GR_CONCUSS_SETANGLE
msg_entity = self.owner;
WriteByte (MSG_ONE, SVC_SETANGLE);
WriteAngleV (MSG_ONE, self.owner.v_angle);
#endif
self.has_camera = time + GR_CONCUSS_FIXTIME;
}
local float r = random();
local float amount = self.health;
if (amount > GR_CONCUSS_MAX)
amount = GR_CONCUSS_MAX;
amount *= (0.8 + random() * 0.2);
local float x = random() * amount;
local float y = amount - x;
if (random() < 0.5)
self.owner.mangle.x += x * GR_CONCUSS_X;
else
self.owner.mangle.x -= x * GR_CONCUSS_X;
if (random() < 0.5)
self.owner.mangle.y += y * GR_CONCUSS_Y;
else
self.owner.mangle.y -= y * GR_CONCUSS_Y;
local float rat = self.health / GR_CONCUSS_MAX;
if (self.owner.mangle.x > GR_CONCUSS_MAX_X * rat)
self.owner.mangle.x = GR_CONCUSS_MAX_X * rat;
if (self.owner.mangle.x < GR_CONCUSS_MIN_X * rat)
self.owner.mangle.x = GR_CONCUSS_MIN_X * rat;
if (self.owner.mangle.y > GR_CONCUSS_MAX_Y * rat)
self.owner.mangle.y = GR_CONCUSS_MAX_Y * rat;
if (self.owner.mangle.y < GR_CONCUSS_MIN_Y * rat)
self.owner.mangle.y = GR_CONCUSS_MIN_Y * rat;;
if (self.owner.waterlevel || (self.owner.flags & FL_ONGROUND))
{
local float vel = vlen (self.owner.velocity);
x = random() * amount;
y = amount - x;
if (random() < 0.5)
self.owner.velocity.x += x * GR_CONCUSS_KICK * vel;
else
self.owner.velocity.x -= x * GR_CONCUSS_KICK * vel;
if (random() < 0.5)
self.owner.velocity.y += y * GR_CONCUSS_KICK * vel;
else
self.owner.velocity.y -= y * GR_CONCUSS_KICK * vel;
}
//sprint (self.owner, PRINT_HIGH, "mangle: " + vtos (self.owner.mangle) + "\n");
#endif
};
//=========================================================================
// Handles the scanner function for Scouts
void(float scanrange,float inAuto) TeamFortress_Scan =
{
local string power;
local entity list = nil;
local float scen, scfr;
local vector lightningvec;
// added in for the direction scanner code
local float enemy_detected;
local float any_detected;
// prevent scan impulse from triggering anything else
self.impulse = 0;
self.last_impulse = 0;
if (self.classname == "player")
{
if (!(self.tf_items & NIT_SCANNER))
return;
// If Impulse is TF_SCAN_ENEMY, toggle Scanning for Enemies
if (scanrange == TF_SCAN_ENEMY)
{
if (self.tf_items_flags & NIT_SCANNER_ENEMY)
{
sprint (self, PRINT_HIGH, "Enemy Scanning disabled.\n");
self.tf_items_flags &= ~NIT_SCANNER_ENEMY;
return;
}
sprint (self, PRINT_HIGH, "Enemy Scanning enabled.\n");
self.tf_items_flags |= NIT_SCANNER_ENEMY;
return;
}
// If Impulse is TF_SCAN_FRIENDLY, toggle Scanning for Friendlies
if (scanrange == TF_SCAN_FRIENDLY)
{
if (self.tf_items_flags & NIT_SCANNER_FRIENDLY)
{
sprint (self, PRINT_HIGH, "Friendly Scanning disabled.\n");
self.tf_items_flags &= ~NIT_SCANNER_FRIENDLY;
return;
}
sprint (self, PRINT_HIGH, "Friendly Scanning enabled.\n");
self.tf_items_flags |= NIT_SCANNER_FRIENDLY;
return;
}
// If the user doesn't have as many cells as he/she specified, just
// use as many as they've got.
/* local float scancost;
scancost = ceil(scanrange / 20);
if (scancost > self.ammo_cells)
{
scanrange = self.ammo_cells * 20;
scancost = self.ammo_cells;
}
if (scanrange <= 0)
{
sprint(self, PRINT_HIGH, "No cells.\n");
return;
}
*/
if (scanrange > NIT_SCANNER_MAXCELL)
scanrange = NIT_SCANNER_MAXCELL;
scen = 0;
scfr = 0;
// Set the Scanner flags
if (self.tf_items_flags & NIT_SCANNER_ENEMY)
scen = 1;
if (self.tf_items_flags & NIT_SCANNER_FRIENDLY)
scfr = 1;
// If no entity type is enabled, don't scan
if ((scen == 0) && (scfr == 0))
{
sprint(self, PRINT_HIGH, "All scanner functions are disabled.\nEnable with 'scane' or 'scanf'.\n");
return;
}
// Use up cells to power the scanner
// additions:
// altered this so scanner could be more easily tested
//WK self.ammo_cells = self.ammo_cells - scancost;
scanrange = scanrange * NIT_SCANNER_POWER;
if (!inAuto) { //WK Only sprint() if not autoscanner
sprint (self, PRINT_HIGH, "Range: ");
power = ftos(ceil(scanrange));
sprint (self, PRINT_HIGH, power);
sprint (self, PRINT_HIGH, ". Scanning...\n");
}
// Get the list of entities the scanner finds
list = T_RadiusScan(self, scanrange, scen, scfr);
}
// Base Defence scanning code here
// Reset the entity counts
scen = 0;
scfr = 0;
// the vectors v_forward and v_right are required to
// 'triangulate' the enemies position
makevectors(self.v_angle);
// Walk the list
// For now, just count the entities.
// In the future, we'll display bearings :)
// additions: the future is now!
while (list)
{
if (list != self)
{
// sets the enemy_detected flag to TRUE if not on your team, FALSE if so
any_detected = TRUE; // this flag is set to false if bogie is moving
// too slow to be detected (and velocity checking is on)
if (vlen(list.origin - self.origin) <= scanrange) //CH Secondary check NEEDED!!!
{
// If this scanner is a motion detector, don't record
// object that don't have the required velocity to be detected.
if (self.tf_items_flags & NIT_SCANNER_MOVEMENT)
{
if (vlen(list.velocity) > NIT_SCANNER_MIN_MOVEMENT)
{
if (list.classname == "monster_demon1" && list.health > 0) //Because they dont have teams
{
if (Teammate(list.real_owner.team_no,self.team_no))
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else
{
scen = scen + 1;
enemy_detected = TRUE;
}
}
else if (list.classname == "monster_army" && list.health > 0) //Because they dont have teams
{
if (Teammate(list.real_owner.team_no,self.team_no))
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else
{
scen = scen + 1;
enemy_detected = TRUE;
}
}
else if (list.classname == "monster_shambler" && list.health > 0) //Because they dont have teams
{
if (Teammate(list.real_owner.team_no,self.team_no))
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else
{
scen = scen + 1;
enemy_detected = TRUE;
}
}
//- OfN -
else if (list.classname == "monster_wizard" && list.health > 0) //Because they dont have teams
{
if (Teammate(list.real_owner.team_no,self.team_no))
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else
{
scen = scen + 1;
enemy_detected = TRUE;
}
}
else if (list.classname == "item_tfgoal" && list.owned_by > 0 && list.team_no > 0 && self.team_no > 0) //Because they use owned_by
{
if (list.owned_by == self.team_no && list.team_no != self.team_no)
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else if (list.owned_by == self.team_no && list.team_no == self.team_no)
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else if (list.owned_by != self.team_no && list.team_no == self.team_no)
{
scen = scen + 1;
enemy_detected = TRUE;
}
else
any_detected = FALSE;
}
else if ((list.classname == "player" || list.classname == "building_sentrygun" || list.classname == "building_tesla" || list.classname == "building_teleporter") && list.health > 0 && !(list.cutf_items & CUTF_JAMMER))
{
if (Teammate(list.team_no, self.team_no))
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else
{
scen = scen + 1;
enemy_detected = TRUE;
}
}
else
{
any_detected = FALSE;
}
}
else
{
any_detected = FALSE;
}
}
else
{
if (list.classname == "monster_demon1" && list.health > 0) //Because they dont have teams
{
if (Teammate(list.real_owner.team_no,self.team_no))
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else
{
scen = scen + 1;
enemy_detected = TRUE;
}
}
if (list.classname == "monster_army" && list.health > 0) //Because they dont have teams
{
if (Teammate(list.real_owner.team_no, self.team_no))
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else
{
scen = scen + 1;
enemy_detected = TRUE;
}
}
if (list.classname == "monster_shambler" && list.health > 0) //Because they dont have teams
{
if (Teammate(list.real_owner.team_no, self.team_no))
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else
{
scen = scen + 1;
enemy_detected = TRUE;
}
}
//- OfN -
if (list.classname == "monster_wizard" && list.health > 0) //Because they dont have teams
{
if (Teammate(list.real_owner.team_no, self.team_no))
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else
{
scen = scen + 1;
enemy_detected = TRUE;
}
}
else if (list.classname == "item_tfgoal" && list.owned_by > 0 && list.team_no > 0 && self.team_no > 0) //Because they use owned_by
{
if (list.owned_by == self.team_no && list.team_no != self.team_no)
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else if (list.owned_by == self.team_no && list.team_no == self.team_no)
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else if (list.owned_by != self.team_no && list.team_no == self.team_no)
{
scen = scen + 1;
enemy_detected = TRUE;
}
else
any_detected = FALSE;
}
else if ((list.classname == "player" || list.classname == "building_sentrygun" || list.classname == "building_tesla" || list.classname == "building_teleporter") && list.health > 0 && !(list.cutf_items & CUTF_JAMMER))
{
if (Teammate(list.team_no, self.team_no))
{
scfr = scfr + 1;
enemy_detected = FALSE;
}
else
{
scen = scen + 1;
enemy_detected = TRUE;
}
}
else
{
any_detected = FALSE;
}
}
}
else
{
any_detected = FALSE;
}
// this displays the direction of the detected player
// using the cosine rule to find the angle
// cos theta = A.B divided by |A||B|
// it should return a value between 1 and -1
if (any_detected)
{
// Get the unit vector
lightningvec = normalize(list.origin - self.origin);
lightningvec = lightningvec * (vlen(list.origin - self.origin) / 5);
lightningvec = lightningvec + self.origin;
// Create the Lightning
msg_entity = self;
WriteByte (MSG_ONE, SVC_TEMPENTITY);
WriteByte (MSG_ONE, TE_LIGHTNING1);
WriteEntity (MSG_ONE, self);
WriteCoord (MSG_ONE, self.origin.x);
WriteCoord (MSG_ONE, self.origin.y);
WriteCoord (MSG_ONE, self.origin.z + 8);
WriteCoord (MSG_ONE, lightningvec.x);
WriteCoord (MSG_ONE, lightningvec.y);
WriteCoord (MSG_ONE, lightningvec.z + 8);
self.scaned = list; //CH for the sbar
if (!inAuto)
{
self.StatusRefreshTime = time + 0.2;
self.StatusBarScreen = 5;
}
} // end if(any_detected)
}
list = list.linked_list;
}
// Display the counts
// For Base Defences, it will display the counts to all team members
if ((scen == 0) && (scfr == 0) && (!inAuto))
{
sprint (self, PRINT_HIGH, "No blips.\n");
return;
}
// Update ammo levels
//W_SetCurrentAmmo ();
return;
};
//=========================================================================
// Acts just like T_RadiusDamage, but doesn't damage things, just pushes them away
// from the explosion at a speed relative to the distance from the explosion's origin.
void(entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce =
{
local float points;
local entity head, te;
local vector org;
head = findradius(inflictor.origin, bounce+40);
while (head)
{
if (head != ignore)
{
if (head.takedamage && head.classname != "monster_shambler")
{
org = head.origin + (head.mins + head.maxs)*0.5;
points = 0.5*vlen (org - inflictor.origin);
if (points < 0)
points = 0;
points = bounce - points;
if (head.cutf_items & CUTF_GYMNAST)
points = points * 2;
if (!IsBuilding(head) && points > 0)
{
// Bounce!!
#ifdef NEW_CONCUSS_BOUNCE
head.velocity += normalize (org - inflictor.origin) * points * 8;
#else
head.velocity = org - inflictor.origin;
head.velocity *= points / 20;
#endif
if (head.classname != "player")
{
head.flags &= ~FL_ONGROUND;
}
else
{
//WK Add cheat immunity since they fly
makeImmune(head,time+3);
// Concuss 'em!!
// If they are already concussed, set the concussion back up
// Try to find a concusstimer entity for this player
head.tfstate |= TFSTATE_CONCUSSIONED;
te = find(nil, classname, "timer");
while (((te.owner != head) || (te.think != ConcussionGrenadeTimer)) && (te))
te = find(te, classname, "timer");
if (te)
{
te.health += GR_CONCUSS_AMOUNT;
#ifdef OLD_CONC_GRENADE
stuffcmd(head, "v_idlescale " +
ftos (te.health * GR_CONCUSS_IDLE) + "\n");
#endif
te.nextthink = time + GR_CONCUSS_TIME;
}
else
{
#ifdef OLD_CONC_GRENADE
stuffcmd(head,"v_idlescale " +
ftos (GR_CONCUSS_AMOUNT * GR_CONCUSS_IDLE)+ "\n");
#endif
stuffcmd(head,"bf\n");
// Create a timer entity
te = spawn();
te.nextthink = time + GR_CONCUSS_TIME;
te.think = ConcussionGrenadeTimer;
te.team_no = attacker.team_no;
te.classname = "timer";
te.owner = head;
te.health += GR_CONCUSS_AMOUNT;
te.has_tesla = time + 0.1;
}
}
}
}
}
head = head.chain;
}
};
//CH checks a player and returns True of False
float(entity scan, entity targ, float enemies, float friends) Scanner_Check_Player =
{
if (targ.playerclass == PC_UNDEFINED) {
return FALSE;
}
else if (targ.done_custom & CUSTOM_BUILDING) {
return FALSE;
}
else if (targ.health <= 0) {
return FALSE;
}
else if (targ.has_disconnected) {
return FALSE;
}
else if (targ == scan) {
return FALSE;
}
else if (targ.flags & FL_NOTARGET) {
return FALSE;
}
else if (targ.cutf_items & CUTF_JAMMER)
return FALSE;
//CH ALL NEW CHECKS ABOVE THIS LINE
if (teamplay)
{
if ( friends && Teammate(targ.team_no,scan.team_no) )
return TRUE;
if ( enemies && !Teammate(targ.team_no,scan.team_no) )
return TRUE;
}
else
return TRUE;
return FALSE;
};
//=========================================================================
// 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, float enemies, float friends) T_RadiusScan =
{
local entity head;
local entity list_head;
local entity list;
local float gotatarget;
list_head = nil;
list = nil;
head = findradius(scanner.origin, scanrange+40);
while (head)
{
gotatarget = 0;
if (head != scanner && (friends || enemies)) // Don't pick up the entity that's scanning
{
if (head.takedamage) //item_tfgoal does not take dammage
{
if (head.classname == "player")
{
gotatarget = Scanner_Check_Player(scanner, head, enemies, friends);
}
else if ((head.classname == "building_tesla" || head.classname == "building_sentrygun" || head.classname == "building_teleporter") && (head.health > 0)) //CH uses team_no :)
{
if (teamplay)
{
if ( friends && Teammate(head.team_no, scanner.team_no) )
gotatarget = 1;
if ( enemies && !Teammate(head.team_no, scanner.team_no) )
gotatarget = 1;
}
else
gotatarget = 1;
}
else if ((head.classname == "monster_demon1") && head.health > 0) //CH demons trace back to real_owner
{
if (teamplay)
{
if ( friends && Teammate(head.real_owner.team_no, scanner.team_no) )
gotatarget = 1;
if ( enemies && !Teammate(head.real_owner.team_no, scanner.team_no) )
gotatarget = 1;
}
else
gotatarget = 1;
}
else if ((head.classname == "monster_army") && head.health > 0) //CH demons trace back to real_owner
{
if (teamplay)
{
if ( friends && Teammate(head.real_owner.team_no, scanner.team_no) )
gotatarget = 1;
if ( enemies && !Teammate(head.real_owner.team_no, scanner.team_no) )
gotatarget = 1;
}
else
gotatarget = 1;
}
else if ((head.classname == "monster_shambler") && head.health > 0) //CH demons trace back to real_owner
{
if (teamplay)
{
if ( friends && Teammate(head.real_owner.team_no, scanner.team_no) )
gotatarget = 1;
if ( enemies && !Teammate(head.real_owner.team_no, scanner.team_no) )
gotatarget = 1;
}
else
gotatarget = 1;
}
//- OfN -
else if ((head.classname == "monster_wizard") && head.health > 0) //CH demons trace back to real_owner
{
if (teamplay)
{
if ( friends && Teammate(head.real_owner.team_no, scanner.team_no) )
gotatarget = 1;
if ( enemies && !Teammate(head.real_owner.team_no, scanner.team_no) )
gotatarget = 1;
}
else
gotatarget = 1;
}
}
else if (head.classname == "item_tfgoal") //CH flags used owned_by for what team it is
{
if (teamplay)
{
if ( friends && (head.team_no > 0) && (head.owned_by > 0) && (scanner.team_no > 0) && (head.team_no == scanner.team_no) && (head.owned_by == scanner.team_no) )
gotatarget = 1;
if ( friends && (head.team_no > 0) && (head.owned_by > 0) && (scanner.team_no > 0) && (head.team_no != scanner.team_no) && (head.owned_by == scanner.team_no) )
gotatarget = 1;
if ( enemies && (head.team_no > 0) && (head.owned_by > 0) && (scanner.team_no > 0) && (head.team_no == scanner.team_no) && (head.owned_by != scanner.team_no) )
gotatarget = 1;
}
else
gotatarget = 1;
}
}
// Add this entity to the linked list if it matches the target criteria
if (gotatarget)
{
if (list)
{
list.linked_list = head;
list = list.linked_list;
}
else
{
list_head = head;
list = head;
}
}
head = head.chain;
}
return list_head;
};
//=========================================================================
// Caltrop Grenade explosion
#define GR_TYPE_CALTROP_NO 5
void (vector org, entity shooter) CreateCaltrop;
void() CaltropTouch;
void() CaltropGrenadeExplode =
{
local float i;
/* deathmsg = DMSG_GREN_CALTROP;
T_RadiusDamage (self, self.owner, 50, nil);
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);
self.solid = SOLID_NOT;
*/
// Very well admiral. Engage the rebels.
i = 0;
while (i < GR_TYPE_CALTROP_NO)
{
CreateCaltrop(self.origin + '0 0 -1',self.owner);
i = i + 1;
}
#ifdef DEMO_STUFF
// Remove any camera's locks on this missile
if (self.enemy)
CamProjectileLockOff();
#endif
//BecomeExplosion();
dremove(self);
};
void (vector org, entity shooter) CreateCaltrop =
{
local float xdir,ydir,zdir;
xdir = 80 * random() - 40;
ydir = 80 * random() - 40;
zdir = 15 + 15 * random();
newmis = spawn ();
newmis.owner = shooter;
newmis.movetype = MOVETYPE_BOUNCE;
newmis.solid = SOLID_TRIGGER;
//newmis.solid = SOLID_BBOX;
newmis.classname = "caltrop";
newmis.weapon = DMSG_CALTROP;
newmis.touch = CaltropTouch;
newmis.think = SUB_Remove;
newmis.nextthink = time + 14 + random()*6; // was 7+random()
newmis.heat = time + 2; // The caltrop doesn't activate for 2 seconds
newmis.velocity.x = xdir * 2;
newmis.velocity.y = ydir * 2;
newmis.velocity.z = zdir * 15;
newmis.avelocity = '500 500 500';
setmodel (newmis, "progs/caltrop.mdl");
setsize (newmis, '-10 -10 -9', '0 0 0');
//setsize (newmis, '-5 -5 -4', '5 5 5');
setorigin (newmis, org);
};
void() CaltropTouch =
{
if (self.velocity == '0 0 0')
{
self.avelocity = '0 0 0';
self.angles = '0 0 0';
}
if (self.heat > time)
return;
if (other.takedamage && other.classname == "player")
{
if (Teammate(self.owner.team_no, other.team_no) && other != self.owner)
return;
//if (other.classname == "player")
if (self.velocity == '0 0 0') // supposedly on the ground..
{
sprint(other, PRINT_HIGH, "Ouch! Ouch! Caltrops!\n");
other.leg_damage = other.leg_damage + 2;
TeamFortress_SetSpeed(other);
deathmsg = DMSG_CALTROP;
TF_T_Damage(other, self, self.owner, 16, 0, TF_TD_OTHER);
}
else // if its moving...
{
sprint(other, PRINT_HIGH, "Woah! Caltrops!\n");
deathmsg = DMSG_FLYCALTROP;
TF_T_Damage(other, self, self.owner, 20 + random() * 9, 0, TF_TD_OTHER);
}
dremove(self);
}
};