prozac-qfcc/tfortmap.qc
2004-03-23 04:29:46 +00:00

3682 lines
85 KiB
C++
Raw Blame History

#include "defs.qh"
#include "messages.qh"
/*======================================================
TFORTMAP.QC Custom TeamFortress v3.1
(c) TeamFortress Software Pty Ltd 29/2/97
(c) William Kerney 2/23/00
(c) Craig Hauser 2/23/00
========================================================
Functions handling TeamFortress Map Entities
======================================================*/
// Prototypes
// Team Functions
void(float tno, float scoretoadd) TeamFortress_TeamIncreaseScore;
void(float all) TeamFortress_TeamShowScores;
float() TeamFortress_TeamGetWinner;
// Functions to handle entity placement when spawned
void() TF_PlaceItem;
void() TF_StartItem;
void() TF_PlaceGoal;
void() TF_StartGoal;
// Spawn functions for all Map Entities
float() CheckExistence;
void() info_tfdetect;
void() info_player_teamspawn;
void() info_tfgoal;
void() info_tfgoal_timer;
void() item_tfgoal;
// AutoDetection Function
void(entity AD) ParseTFDetect;
// Generic Functions
entity(float ino) Finditem;
entity(float gno) Findgoal;
entity(float gno) Findteamspawn;
void(entity Goal) InactivateGoal;
void(entity Goal) RestoreGoal;
void(entity Goal) RemoveGoal;
float(entity Goal, entity Player, entity AP) IsAffectedBy;
void(entity Goal, entity Player, entity AP, float addb) Apply_Results;
float(entity Goal, entity AP) APMeetsCriteria;
void(entity Goal) SetupRespawn;
void() DoRespawn;
void(entity Goal, entity AP) DoGoalWork;
void(entity Goal, entity AP) DoGroupWork;
void(entity Item, entity AP) DoItemGroupWork;
void(entity Goal, entity AP) DoTriggerWork;
void(entity Goal, entity AP, float addb) DoResults;
void(entity Goal, entity Player) RemoveResults;
//CH
void() tfgoalitem_dropthink2;
void() tfgoalitem_settouchandthink;
//CH 3 checks for a returning goalitem
void() tfgoalitem_checkoriginagain;
void() tfgoalitem_checkoriginagain2;
void() tfgoalitem_checkoriginagain3;
// Goal Functions
void() tfgoal_touch;
void() info_tfgoal_use;
// Timer Goal Functions
void() tfgoal_timer_tick;
// Item Functions
void() item_tfgoal_touch;
void(entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer;
void(float Item)Update_team_with_flag_touch;
void(float Item)Update_team_with_flag_drop;
void(entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer;
void() tfgoalitem_remove;
void(entity Item) tfgoalitem_drop;
void(entity Item) tfgoalitem_checkgoalreturn;
void() ReturnItem;
void(entity Goal, entity Player, entity Item) DisplayItemStatus;
// CTF Support Functions
void() CTF_FlagCheck;
// Chris Support Functions
//void (float winner) RoundStop;
//=========================================================================
// ENTITY PLACEMENT HANDLING FUNCTIONS
//=========================================================================
// Copy the abbreviations into their storage areas
void(entity Goal) UpdateAbbreviations =
{
// The first time we enter this, copy the abbreviations
if (Goal.has_disconnected == FALSE)
{
// Floats
if (Goal.g_a != 0 && Goal.goal_activation == 0)
Goal.goal_activation = Goal.g_a;
if (Goal.g_e != 0 && Goal.goal_effects == 0)
Goal.goal_effects = Goal.g_e;
// Strings
if (Goal.t_s_h)
Goal.team_str_home = Goal.t_s_h;
if (Goal.t_s_m)
Goal.team_str_moved = Goal.t_s_m;
if (Goal.t_s_c)
Goal.team_str_carried = Goal.t_s_c;
if (Goal.n_s_h)
Goal.non_team_str_home = Goal.n_s_h;
if (Goal.n_s_m)
Goal.non_team_str_moved = Goal.n_s_m;
if (Goal.n_s_c)
Goal.non_team_str_carried = Goal.n_s_c;
if (Goal.b_b)
Goal.broadcast = Goal.b_b;
if (Goal.b_t)
Goal.team_broadcast = Goal.b_t;
if (Goal.b_n)
Goal.non_team_broadcast = Goal.b_n;
if (Goal.b_o)
Goal.owners_team_broadcast = Goal.b_o;
if (Goal.n_b)
Goal.netname_broadcast = Goal.n_b;
if (Goal.n_t)
Goal.netname_team_broadcast = Goal.n_t;
if (Goal.n_n)
Goal.netname_non_team_broadcast = Goal.n_n;
if (Goal.n_o)
Goal.netname_owners_team_broadcast = Goal.n_o;
if (Goal.d_t)
Goal.team_drop = Goal.d_t;
if (Goal.d_n)
Goal.non_team_drop = Goal.d_n;
if (Goal.d_n_t)
Goal.netname_team_drop = Goal.d_n_t;
if (Goal.d_n_n)
Goal.netname_non_team_drop = Goal.d_n_n;
Goal.has_disconnected = TRUE;
}
if (toggleflags & (TFLAG_WARSTANDARD | TFLAG_FLAGEMU))
{
local string newmdl;
if (toggleflags & TFLAG_WARSTANDARD)
newmdl = "progs/tf_stan.mdl";
else
newmdl = "progs/tf_flag.mdl";
switch (Goal.mdl)
{
case "progs/b_s_key.mdl":
case "progs/w_s_key.mdl":
case "progs/m_s_key.mdl":
Goal.skin = 1;
Goal.mdl = newmdl;
break;
case "progs/b_g_key.mdl":
case "progs/w_g_key.mdl":
case "progs/m_g_key.mdl":
Goal.skin = 2;
Goal.mdl = newmdl;
break;
}
}
};
// Place the Goal Item
void() TF_PlaceItem =
{
local vector temp1;
local vector temp2;
if (!toggleflags)
SetToggleFlags ();
UpdateAbbreviations (self);
// Graphic
if (self.mdl)
setmodel(self, self.mdl);
self.flags = FL_ITEM; // make extra wide
self.touch = item_tfgoal_touch;
setorigin(self, self.origin);
self.goal_state = TFGS_INACTIVE;
//CH my updates
if (self.goal_activation & TFGI_GOAL_TO_GROUND)
{
self.oldorigin = self.origin;
self.movetype = MOVETYPE_TOSS;
self.velocity_z = -40;
self.velocity_x = 0; //-50 + (random() * 100);
self.velocity_y = 0; //-50 + (random() * 100);
self.nextthink = time + 5.0; // give it 5 seconds
self.think = tfgoalitem_dropthink2; // and then find where it ended up
}
else
{
self.velocity = '0 0 0';
self.movetype = MOVETYPE_NONE;
self.oldorigin = self.origin;
}
//CH sets goal bounding box size
if (self.goal_min)
temp1 = self.goal_min;
else
temp1 = '-16 -16 -24';
if (self.goal_max)
temp2 = self.goal_max;
else
temp2 = '16 16 32';
setsize (self, temp1, temp2); //CH sets box size from above
if (self.goal_activation & TFGI_GOAL_IS_SOLID)
self.solid = SOLID_BBOX;
else
self.solid = SOLID_TRIGGER;
//CH end my updates
//On tfgoalitem_dropthink2
// self.velocity = '0 0 0';
// self.oldorigin = self.origin; // So we can return it later
if (self.goal_activation & TFGI_ITEMGLOWS)
self.effects = self.effects | EF_GlowColor(self);
// Setup the item_list mask
if (item_list_bit == 0)
item_list_bit = 1;
self.item_list = item_list_bit;
item_list_bit = item_list_bit * 2;
};
//=========================================================================
// Start the Goal Item
void() TF_StartItem =
{
self.nextthink = time + 0.2; // items start after other solids
self.think = TF_PlaceItem;
if (self.goal_state == TFGS_REMOVED)
RemoveGoal(self);
};
//=========================================================================
// Place the Goal
void() TF_PlaceGoal =
{
if (!toggleflags)
SetToggleFlags ();
UpdateAbbreviations (self);
if (self.classname != "info_tfgoal_timer")
{
// Only give touch functions to goals that can be activated by touch
if (self.goal_activation & TFGA_TOUCH)
self.touch = tfgoal_touch;
}
else
{
// Set up the next Timer Tick
self.think = tfgoal_timer_tick;
self.nextthink = time + self.search_time;
// So searches for this goal work later on
self.classname = "info_tfgoal";
}
self.flags = FL_ITEM; // make extra wide
self.movetype = MOVETYPE_NONE;
self.velocity = '0 0 0';
self.oldorigin = self.origin; // So we can return it later
};
//=========================================================================
// Start the Goal
void() TF_StartGoal =
{
self.nextthink = time + 0.2; // goals start after other solids
self.think = TF_PlaceGoal;
self.use = info_tfgoal_use;
if (self.goal_state == TFGS_REMOVED)
RemoveGoal(self);
};
//=========================================================================
// SPAWN FUNCTIONS
//=========================================================================
// Checks whether this entity should exist under the current settings
float() CheckExistence =
{
UpdateAbbreviations(self);
if (self.ex_skill_min && (skill <= self.ex_skill_min))
return FALSE;
else if (self.ex_skill_max && (skill >= self.ex_skill_max))
return FALSE;
return TRUE;
};
//=========================================================================
// Spawn a detection entity
void() info_tfdetect =
{
UpdateAbbreviations(self);
// The rest of the checking is done in the ParseTFDetect() function,
// which is called the first time someone enters the map, in client.qc
};
//=========================================================================
// Spawn a Team Spawn Point
void() info_player_teamspawn =
{
local entity te;
if (CheckExistence() == FALSE)
{
dremove(self);
return;
}
// find the highest team number
if (number_of_teams < self.team_no)
number_of_teams = self.team_no;
// Team spawnpoints must have a team associated with them
if (self.team_no <= 0)
{
RPrint("no team_no associated with info_player_teamspawn\n");
dremove(self);
}
// Does this give out a GoalItem?
if (self.items != 0)
{
te = Finditem(self.items);
if (!te)
{
RPrint("info_player_teamspawn specifies a GoalItem that does not exist\n");
dremove(self);
}
}
if (self.team_no == 1)
self.team_str_home = "ts1";
else if (self.team_no == 2)
self.team_str_home = "ts2";
else if (self.team_no == 3)
self.team_str_home = "ts3";
else if (self.team_no == 4)
self.team_str_home = "ts4";
};
void() i_p_t =
{
self.classname = "info_player_teamspawn";
info_player_teamspawn();
};
//=========================================================================
// Spawn a goal entity
void() info_tfgoal =
{
local vector temp1;
local vector temp2;
if (CheckExistence() == FALSE)
{
dremove(self);
return;
}
// Graphic
if (self.mdl)
{
// We try both, so at least one will work
precache_model(self.mdl);
precache_model2(self.mdl);
setmodel (self, self.mdl);
}
// Activation sound
if (self.noise)
{
// We try both, so at least one will work
precache_sound(self.noise);
precache_sound2(self.noise);
}
// For the powerups
precache_sound ("items/protect.wav");
precache_sound ("items/protect2.wav");
precache_sound ("items/protect3.wav");
precache_sound2 ("items/protect2.wav");
precache_sound2 ("items/protect3.wav");
precache_sound ("items/suit.wav");
precache_sound ("items/suit2.wav");
precache_sound ("items/inv1.wav");
precache_sound ("items/inv2.wav");
precache_sound ("items/inv3.wav");
precache_sound ("items/damage.wav");
precache_sound ("items/damage2.wav");
precache_sound ("items/damage3.wav");
//CH set solid state
if (self.goal_activation & TFGI_GOAL_IS_SOLID)
self.solid = SOLID_BBOX;
else
self.solid = SOLID_TRIGGER;
if (self.goal_state == 0)
self.goal_state = TFGS_INACTIVE;
//CH sets goal bounding box size
if (self.goal_min)
temp1 = self.goal_min;
else
temp1 = '-16 -16 -24';
if (self.goal_max)
temp2 = self.goal_max;
else
temp2 = '16 16 32';
setsize (self, temp1, temp2); //CH sets box size from above
TF_StartGoal ();
};
void() i_t_g =
{
self.classname = "info_tfgoal";
info_tfgoal();
};
//=========================================================================
// Spawn a Timer goal entity
void() info_tfgoal_timer =
{
if (CheckExistence() == FALSE)
{
dremove(self);
return;
}
// Graphic
if (self.mdl)
{
// We try both, so at least one will work
precache_model(self.mdl);
precache_model2(self.mdl);
setmodel(self, self.mdl);
}
// Activation sound
if (self.noise)
{
// We try both, so at least one will work
precache_sound(self.noise);
precache_sound2(self.noise);
}
// Timer Goals must have a time specified
if (self.search_time <= 0)
{
RPrint("Timer Goal created with no specified time.\n");
dremove(self);
}
self.solid = SOLID_NOT;
if (self.goal_state == 0)
self.goal_state = TFGS_INACTIVE;
setsize (self, '-16 -16 -24', '16 16 32');
TF_StartGoal ();
};
void() i_t_t =
{
self.classname = "info_tfgoal_timer";
info_tfgoal_timer();
};
//=========================================================================
// Spawn a goalitem entity
void() item_tfgoal =
{
local vector temp1;
local vector temp2;
if (CheckExistence() == FALSE)
{
dremove(self);
return;
}
UpdateAbbreviations (self);
// Graphic
if (self.mdl)
{
// We try both, so at least one will work
precache_model(self.mdl);
precache_model2(self.mdl);
setmodel(self, self.mdl);
}
else
{
// Default mdl for a GoalItem
self.mdl = "";
setmodel(self, "");
}
// Respawn sound
precache_sound2("items/itembk2.wav");
// Activation sound
if (self.noise)
{
// We try both, so at least one will work
precache_sound(self.noise);
precache_sound2(self.noise);
}
self.touch = item_tfgoal_touch;
if (self.goal_state == 0)
self.goal_state = TFGS_INACTIVE;
//CH sets how it is
if (self.goal_activation & TFGI_GOAL_IS_SOLID)
self.solid = SOLID_BBOX;
else
self.solid = SOLID_TRIGGER;
setorigin(self, self.origin);
if (!(self.netname))
self.netname = "goalitem";
if (self.pausetime <= 0)
self.pausetime = 60;
// for backwards compatability
if (self.delay != 0 && self.pausetime == 0)
self.pausetime = self.delay;
//CH sets goal bounding box size
if (self.goal_min)
temp1 = self.goal_min;
else
temp1 = '-16 -16 -24';
if (self.goal_max)
temp2 = self.goal_max;
else
temp2 = '16 16 32';
setsize (self, temp1, temp2); //CH sets box size from above
TF_StartItem ();
};
//=========================================================================
// AUTODETECTION FUNCTIONS
//=========================================================================
// Parse the Detection entities variables and set anything relevant
void(entity AD) ParseTFDetect =
{
// Check Version
/*
if (AD.broadcast)
{
if (AD.broadcast != "TeamFortress v2.5")
{
RPrint("This map was designed to be run on ");
RPrint(AD.broadcast);
RPrint("\nYou are using TeamFortress v2.5\n");
RPrint("You can get the latest version of this patch at: ");
RPrint("http://www.planetquake.com/teamfortress/\n");
}
}
*/
// Set the team menu string
if (AD.team_broadcast)
team_menu_string = AD.team_broadcast;
// Set toggleflags (DEFUNCT)
// toggleflags = AD.impulse;
// Do localcmds
localcmd(AD.message);
// Set life limits
team1lives = AD.ammo_shells;
team2lives = AD.ammo_nails;
team3lives = AD.ammo_rockets;
team4lives = AD.ammo_cells;
// If the lives of any of the teams are 0, they want infinite lives,
// so we set their number to -1
if (team1lives == 0)
team1lives = -1;
if (team2lives == 0)
team2lives = -1;
if (team3lives == 0)
team3lives = -1;
if (team4lives == 0)
team4lives = -1;
// Prevent hook use
if ((AD.hook_out == 1) || no_grapple == 1)
allow_hook = FALSE;
// Set player number limits for each team
team1maxplayers = AD.ammo_medikit;
team2maxplayers = AD.ammo_detpack;
team3maxplayers = AD.maxammo_medikit;
team4maxplayers = AD.maxammo_detpack;
if (team1maxplayers == 0)
team1maxplayers = 100;
if (team2maxplayers == 0)
team2maxplayers = 100;
if (team3maxplayers == 0)
team3maxplayers = 100;
if (team4maxplayers == 0)
team4maxplayers = 100;
// Set illegal playerclasses
illegalclasses = AD.playerclass;
illegalclasses1 = AD.maxammo_shells;
illegalclasses2 = AD.maxammo_nails;
illegalclasses3 = AD.maxammo_rockets;
illegalclasses4 = AD.maxammo_cells;
civilianteams = 0;
// Civilian team checking
if (illegalclasses1 == -1)
{
illegalclasses1 = 0;
civilianteams = civilianteams | TEAM1_CIVILIANS;
}
if (illegalclasses2 == -1)
{
illegalclasses2 = 0;
civilianteams = civilianteams | TEAM2_CIVILIANS;
}
if (illegalclasses3 == -1)
{
illegalclasses3 = 0;
civilianteams = civilianteams | TEAM3_CIVILIANS;
}
if (illegalclasses4 == -1)
{
illegalclasses4 = 0;
civilianteams = civilianteams | TEAM4_CIVILIANS;
}
};
//=========================================================================
// GENERIC FUNCTIONS
//=========================================================================
// Return the item with a goal_no equal to ino
entity(float ino) Finditem =
{
local entity tg;
local string st;
// Look for the goal
tg = find (NIL, classname, "item_tfgoal");
while (tg)
{
if (tg.goal_no == ino)
return tg;
tg = find(tg, classname, "item_tfgoal");
}
// Goal does not exist
RPrint("Could not find an item with a goal_no of ");
st = ftos(ino);
RPrint(st);
RPrint(".\n");
};
//=========================================================================
// Return the goal with a goal_no equal to gno
entity(float gno) Findgoal =
{
local entity tg;
local string st;
// Look for the goal
tg = find (NIL, classname, "info_tfgoal");
while (tg)
{
if (tg.goal_no == gno)
{
return tg;
}
tg = find(tg, classname, "info_tfgoal");
}
// Goal does not exist
RPrint("Could not find a goal with a goal_no of ");
st = ftos(gno);
RPrint(st);
RPrint(".\n");
};
//=========================================================================
// Return the TeamSpawn with a goal_no equal to gno
entity(float gno) Findteamspawn =
{
local entity tg;
local string st;
// Look for the goal
tg = find (NIL, classname, "info_player_teamspawn");
while (tg)
{
if (tg.goal_no == gno)
return tg;
tg = find(tg, classname, "info_player_teamspawn");
}
// Goal does not exist
RPrint("Could not find a Teamspawn with a goal_no of ");
st = ftos(gno);
RPrint(st);
RPrint(".\n");
};
//=========================================================================
// Inactivate a Timer/Goal
void(entity Goal) InactivateGoal =
{
#ifdef MAP_DEBUG
RPrint("Attempting to Inactivate ");
RPrint(Goal.netname);
#endif
if (Goal.goal_state == TFGS_ACTIVE)
{
// Not a timer goal
if (Goal.search_time == 0) {
if (Goal.goal_activation & TFGI_GOAL_IS_SOLID)
Goal.solid = SOLID_BBOX;
else
Goal.solid = SOLID_TRIGGER;
}
Goal.goal_state = TFGS_INACTIVE;
if (Goal.mdl)
setmodel(Goal, Goal.mdl);
}
#ifdef MAP_DEBUG
else
{
RPrint("... failed. Goal is ");
if (Goal.goal_state == TFGS_INACTIVE)
RPrint("inactive\n");
else if (Goal.goal_state == TFGS_REMOVED)
RPrint("removed\n");
else if (Goal.goal_state == TFGS_DELAYED)
RPrint("delayed\n");
}
#endif
};
//=========================================================================
void(entity Goal) RestoreGoal =
{
#ifdef MAP_DEBUG
RPrint("Attempting to Restore ");
RPrint(Goal.netname);
#endif
if (Goal.search_time == 0)
{
if (Goal.goal_activation & TFGI_GOAL_IS_SOLID)
Goal.solid = SOLID_BBOX;
else
Goal.solid = SOLID_TRIGGER;
if (Goal.mdl)
setmodel(Goal, Goal.mdl);
if (Goal.goal_state == TFGS_REMOVED)
Goal.goal_state = TFGS_INACTIVE;
}
if (Goal.goal_state == TFGS_REMOVED)
{
#ifdef MAP_DEBUG
RPrint("... succeeded.\n");
#endif
// Not a timer goal
if (Goal.search_time != 0)
// {
// if (Goal.goal_activation & TFGI_GOAL_IS_SOLID)
// Goal.solid = SOLID_BBOX;
// else
// Goal.solid = SOLID_TRIGGER;
// }
// else
Goal.nextthink = time + Goal.search_time;
Goal.goal_state = TFGS_INACTIVE;
// if (Goal.mdl)
// setmodel(Goal, Goal.mdl);
}
#ifdef MAP_DEBUG
else
{
RPrint("... failed. Goal is ");
if (Goal.goal_state == TFGS_INACTIVE)
RPrint("inactive\n");
else if (Goal.goal_state == TFGS_ACTIVE)
RPrint("active\n");
else if (Goal.goal_state == TFGS_DELAYED)
RPrint("delayed\n");
}
#endif
};
//=========================================================================
// Remove a Timer/Goal
void(entity Goal) RemoveGoal =
{
#ifdef MAP_DEBUG
RPrint("Removing ");
RPrint(Goal.netname);
RPrint("\n");
#endif
Goal.solid = SOLID_NOT;
Goal.goal_state = TFGS_REMOVED;
if (Goal.mdl)
setmodel(Goal, "");
};
//=========================================================================
// Return TRUE if the player is affected by the goal
float(entity Goal, entity Player, entity AP) IsAffectedBy =
{
local float genv;
// Don't affect anyone who isn't alive or is in Observer mode
if (Player.playerclass == PC_UNDEFINED)
return FALSE;
// if (Player.health <= 0)
// return FALSE;
// Same Environment Check
if (Goal.goal_effects & TFGE_SAME_ENVIRONMENT)
{
genv = pointcontents(Goal.origin);
if (pointcontents(Player.origin) != genv)
return FALSE;
}
if (Goal.t_length != 0)
{
// Within radius?
if (vlen(Goal.origin - Player.origin) <= Goal.t_length)
{
// Obstructed by walls?
if (Goal.goal_effects & TFGE_WALL)
{
traceline (Goal.origin, Player.origin, TRUE, Goal);
if (trace_fraction == 1)
return TRUE;
}
else
return TRUE;
}
}
if (Goal.classname != "info_tfgoal_timer")
{
if ((Goal.goal_effects & TFGE_AP) && (Player == AP))
return TRUE;
if ((Goal.goal_effects & TFGE_AP_TEAM) && (AP.team_no == Player.team_no))
return TRUE;
if ((Goal.goal_effects & TFGE_NOT_AP_TEAM) && (AP.team_no != Player.team_no))
return TRUE;
if ((Goal.goal_effects & TFGE_NOT_AP) && (Player != AP))
return TRUE;
}
if ((Goal.maxammo_shells != 0) && (Player.team_no == Goal.maxammo_shells))
return TRUE;
if ((Goal.maxammo_nails != 0) && (Player.team_no != Goal.maxammo_shells))
return TRUE;
return FALSE;
};
//=========================================================================
// Apply modifications to the Player passed in
void(entity Goal, entity Player, entity AP, float addb) Apply_Results =
{
local entity oldself, te, oldte;
stuffcmd(Player, "bf\n");
#ifdef MAP_DEBUG
RPrint("Applying Results from ");
RPrint(Goal.netname);
RPrint(" to ");
RPrint(AP.netname);
RPrint("\n");
#endif
// If this is a goalitem, record the fact that this player
// has been affected by it.
if (Goal.classname == "item_tfgoal")
Player.item_list = Player.item_list | Goal.item_list;
if (Player == AP)
{
// Increase the team score
if (Goal.count > 0)
{
if (Player.team_no > 0)
{
TeamFortress_TeamIncreaseScore(Player.team_no, Goal.count);
// Display short team scores
TeamFortress_TeamShowScores(2);
}
}
}
// Apply Stats, only if told to
if (addb)
{
#ifdef MAP_DEBUG
RPrint("Adding bonuses.\n");
#endif
// Some results are not applied to dead players
if (Player.health > 0)
{
if (Goal.health > 0)
T_Heal(Player, Goal.health, 0);
if (Goal.health < 0)
{
if (Goal.invincible_finished < 0)
{
// KK allow goal to strip invinc cheats
Player.items = Player.items & ~IT_INVULNERABILITY;
Player.invincible_time = 0;
Player.invincible_finished = 0;
}
// Make sure we don't gib them. We don't want to gib, because
// it creates too many entities if a lot of players are affected
// by this Goal.
if ((0 - Player.health) > Goal.health)
TF_T_Damage (Player, Goal, Goal, (Player.health + 1), TF_TD_IGNOREARMOUR, TF_TD_OTHER);
else
TF_T_Damage (Player, Goal, Goal, (0 - Goal.health), TF_TD_IGNOREARMOUR, TF_TD_OTHER);
}
}
// The player may be dead now, so check again
if (Player.health > 0)
{
if (Goal.armortype)
Player.armortype = Goal.armortype;
else if (!Player.armorvalue || !Player.armortype)
Player.armortype = Player.armor_allowed;
Player.armorvalue = Player.armorvalue + Goal.armorvalue;
if (Goal.armorclass)
{ //WK Modify to | it with bought armor
//TODO: Make this a map specific option
//WK Don't give wooden armor since it doesn't exist
// any more. And we don't want gel for free, right?
Player.armorclass = Goal.armorclass;
}
// always get their bought armorclass back
if (Player.tf_items & NIT_KEVLAR)
Player.armorclass = Player.armorclass | AT_SAVESHOT;
if (Player.tf_items & NIT_GEL)
Player.armorclass = Player.armorclass | AT_SAVEMELEE;
if (Player.tf_items & NIT_BLAST)
Player.armorclass = Player.armorclass | AT_SAVEEXPLOSION;
if (Player.tf_items & NIT_CERAMIC)
Player.armorclass = Player.armorclass | AT_SAVEELECTRICITY;
if (Player.tf_items & NIT_ASBESTOS)
Player.armorclass = Player.armorclass | AT_SAVEFIRE;
Player.items &= ~(IT_ARMOR3 | IT_ARMOR2 | IT_ARMOR1);
if (Player.armortype >= 0.8)
Player.items |= IT_ARMOR3;
else if (Player.armortype >= 0.6)
Player.items |= IT_ARMOR2;
else if (Player.armortype >= 0.3)
Player.items |= IT_ARMOR1;
Player.ammo_shells = Player.ammo_shells + Goal.ammo_shells;
Player.ammo_nails = Player.ammo_nails + Goal.ammo_nails;
Player.ammo_rockets = Player.ammo_rockets + Goal.ammo_rockets;
Player.ammo_cells = Player.ammo_cells + Goal.ammo_cells;
Player.ammo_medikit = Player.ammo_medikit + Goal.ammo_medikit;
Player.ammo_detpack = Player.ammo_detpack + Goal.ammo_detpack;
if (Player.tp_grenades_1 != 0) //WK Stop Bug grenades
Player.no_grenades_1 = Player.no_grenades_1 + Goal.no_grenades_1;
if (Player.tp_grenades_2 != 0) //WK Stop Bug grenades
Player.no_grenades_2 = Player.no_grenades_2 + Goal.no_grenades_2;
if (Player.no_grenades_1 > GetMaxGrens(Player,1))
Player.no_grenades_1 = GetMaxGrens(Player,1);
if (Player.no_grenades_2 > GetMaxGrens(Player,2))
Player.no_grenades_2 = GetMaxGrens(Player,2);
/*if (Player.no_grenades_1 > 4)
if (Player.tf_items & NIT_AMMO_BANDOLIER)
Player.no_grenades_1 = 5;
else
Player.no_grenades_1 = 4;
if (Player.no_grenades_2 > 4)
if (Player.tf_items & NIT_AMMO_BANDOLIER)
Player.no_grenades_2 = 5;
else
Player.no_grenades_2 = 4;*/
if (Player.ammo_detpack > Player.maxammo_detpack)
Player.ammo_detpack = Player.maxammo_detpack;
// Apply any powerups
if (Goal.invincible_finished > 0)
{
Player.items = Player.items | IT_INVULNERABILITY;
Player.invincible_time = 1;
Player.invincible_finished = time + Goal.invincible_finished;
// if its a GoalItem, powerup is permanent, so we use TFSTATE flags
if (Goal.classname == "item_tfgoal")
{
Player.tfstate = Player.tfstate | TFSTATE_INVINCIBLE;
Player.invincible_finished = time + 666;
}
}
if (Goal.invisible_finished > 0)
{
Player.items = Player.items | IT_INVISIBILITY;
Player.invisible_time = 1;
Player.invisible_finished = time + Goal.invisible_finished;
// if its a GoalItem, powerup is permanent, so we use TFSTATE flags
if (Goal.classname == "item_tfgoal")
{
Player.tfstate = Player.tfstate | TFSTATE_INVISIBLE;
Player.invisible_finished = time + 666;
}
}
if (Goal.super_damage_finished > 0)
{
//WK Remove Inspiration when we get the real thing
Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_INSPIRED);
Player.items = Player.items | IT_QUAD;
Player.super_time = 1;
Player.super_damage_finished = time + Goal.super_damage_finished;
// if its a GoalItem, powerup is permanent, so we use TFSTATE flags
if (Goal.classname == "item_tfgoal")
{
Player.tfstate = Player.tfstate | TFSTATE_QUAD;
Player.super_damage_finished = time + 666;
}
}
if (Goal.radsuit_finished > 0)
{
Player.items = Player.items | IT_SUIT;
Player.rad_time = 1;
Player.radsuit_finished = time + Goal.radsuit_finished;
// if its a GoalItem, powerup is permanent, so we use TFSTATE flags
if (Goal.classname == "item_tfgoal")
{
Player.tfstate = Player.tfstate | TFSTATE_RADSUIT;
Player.radsuit_finished = time + 666;
}
}
}
// These results are applied to dead and living players
if (Goal.lives < 0)
bprint(PRINT_HIGH,"ERROR: GOAL GAVE OUT NEGATIVE LIVES. CUSTOMTF DOESN'T SUPPORT THAT YET\n");
Player.lives = Player.lives + Goal.lives;
RPrint("Giving " + ftos(Goal.frags) + " frags to " + Player.netname +" from goal " + Goal.netname + ".\n");
Player.real_frags = Player.real_frags + Goal.frags;
if (!(toggleflags & TFLAG_TEAMFRAGS))
Player.frags = Player.real_frags;
// Now apply the Playerclass limitations & Redisplay Ammo counts
oldself = self;
self = Player;
TeamFortress_CheckClassStats();
//WK Fix CH's bug fix with this if statement :)
if (!(self.current_weapon == WEAP_ASSAULT_CANNON && self.heat >= 0))
W_SetCurrentAmmo(); //CH stops interrupt weapon fire bug
self = oldself;
}
#ifdef MAP_DEBUG
else
{
RPrint("NOT Adding bonuses.\n");
}
#endif
if (Goal.goal_result & TFGR_CAUSERESPAWN && Player)
{
if ((Player.playerclass == PC_CUSTOM && Player.done_custom & CUSTOM_FINISHED) || (Player.playerclass != PC_UNDEFINED && Player.playerclass != PC_CUSTOM)) //CH respawn player
{
//CH this needs lots of testing
//*CH
local entity temp;
temp = self;
self = Player;
PutClientInServer();
self = temp;
}
}
// If the Goal resets Spy skin/color then do it
//CH added looking for spykit also removes thief
if (Goal.goal_result & TFGR_REMOVE_DISGUISE)
{
if (Player.job & JOB_THIEF && (Player.job & JOB_ACTIVE || Player.job & JOB_FULL_HIDE))
RevealThief(Player,FALSE);
if (Player.playerclass == PC_SPY || Player.cutf_items & CUTF_SPY_KIT)
{
makeImmune(self,time + 4);
//self.immune_to_check = time + 4;
Spy_RemoveDisguise(Player);
}
}
// If there's a GoalItem for this goal, give it to the player
// GoalItems use "items" for the console lights... so don't do it for items.
if (Goal.items != 0 && Goal.classname != "item_tfgoal")
{
// Find the item
te = Finditem(Goal.items);
if (te)
tfgoalitem_GiveToPlayer(te, Player, Goal);
}
// If this goal removes an item from the player, remove it
if (Goal.axhitme != 0)
{
te = Finditem(Goal.axhitme);
if (te.owner == Player)
{
tfgoalitem_RemoveFromPlayer(te, Player, 1);
}
}
// if this goal removes a group of items from the player, remove them
if (Goal.remove_item_group != 0)
{
// Find all goals
te = find (NIL, classname, "item_tfgoal");
while (te)
{
if (te.group_no == Goal.remove_item_group && te.owner == AP)
{
// messy, since we need the item to find the next one,
// and we also want to remove it
oldte = te;
te = find(te, classname, "item_tfgoal");
tfgoalitem_RemoveFromPlayer(oldte, Player, 1);
}
else
{
te = find(te, classname, "item_tfgoal");
}
}
}
// If this goal displays some Item statuses, then do so
if (Goal.display_item_status1 != 0)
{
te = Finditem(Goal.display_item_status1);
if (te)
DisplayItemStatus(Goal, Player, te);
else
sprint(Player, PRINT_HIGH, "Item is missing.\n");
}
if (Goal.display_item_status2 != 0)
{
te = Finditem(Goal.display_item_status2);
if (te)
DisplayItemStatus(Goal, Player, te);
else
sprint(Player, PRINT_HIGH, "Item is missing.\n");
}
if (Goal.display_item_status3 != 0)
{
te = Finditem(Goal.display_item_status3);
if (te)
DisplayItemStatus(Goal, Player, te);
else
sprint(Player, PRINT_HIGH, "Item is missing.\n");
}
if (Goal.display_item_status4 != 0)
{
te = Finditem(Goal.display_item_status4);
if (te)
DisplayItemStatus(Goal, Player, te);
else
sprint(Player, PRINT_HIGH, "Item is missing.\n");
}
};
//=========================================================================
// Remove any results applied to this player by the Goal
// Used when a GoalItem is dropped/removed
void (entity Goal, entity Player) RemoveResults =
{
local entity oldself, te;
local float puinvin, puinvis, puquad, purad;
// Only remove the stats if the player has been affected
// by this item. This is needed because the player may have
// died since being affected
if (Goal.classname == "item_tfgoal")
{
if (!(Player.item_list & Goal.item_list))
return;
if (Goal.goal_activation & TFGI_DONTREMOVERES)
return;
// Remove the affected flag
Player.item_list = Player.item_list - (Player.item_list & Goal.item_list);
}
if (Goal.health > 0)
TF_T_Damage (Player, Goal, Goal, Goal.health, TF_TD_IGNOREARMOUR, TF_TD_OTHER);
if (Goal.health < 0)
T_Heal(Player, (0 - Goal.health), 0);
Player.lives = Player.lives - Goal.lives;
Player.armortype = Player.armortype - Goal.armortype;
Player.armorvalue = Player.armorvalue - Goal.armorvalue;
Player.armorclass = Player.armorclass - (Player.armorclass & Goal.armorclass);
Player.real_frags = Player.real_frags - Goal.frags;
if (!(toggleflags & TFLAG_TEAMFRAGS))
Player.frags = Player.real_frags;
Player.ammo_shells = Player.ammo_shells - Goal.ammo_shells;
Player.ammo_nails = Player.ammo_nails - Goal.ammo_nails;
Player.ammo_rockets = Player.ammo_rockets - Goal.ammo_rockets;
Player.ammo_cells = Player.ammo_cells - Goal.ammo_cells;
Player.ammo_medikit = Player.ammo_medikit - Goal.ammo_medikit;
Player.ammo_detpack = Player.ammo_detpack - Goal.ammo_detpack;
Player.no_grenades_1 = Player.no_grenades_1 - Goal.no_grenades_1;
Player.no_grenades_2 = Player.no_grenades_2 - Goal.no_grenades_2;
puinvin = FALSE;
puinvis = FALSE;
puquad = FALSE;
purad = FALSE;
// Make sure we don't remove an effect another Goal is also supplying
te = find (NIL, classname, "item_tfgoal");
while (te)
{
if ((te.owner == Player) && (te != Goal))
{
if (te.invincible_finished > 0)
puinvin = TRUE;
if (te.invisible_finished > 0)
puinvis = TRUE;
if (te.super_damage_finished > 0)
puquad = TRUE;
if (te.radsuit_finished > 0)
purad = TRUE;
}
te = find(te, classname, "item_tfgoal");
}
// Remove all powerups
if ((Goal.invincible_finished > 0) && (!puinvin))
{
// if its a GoalItem, powerup was permanent, so we remove TFSTATE flag
Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_INVINCIBLE);
Player.items = Player.items | IT_INVULNERABILITY;
Player.invincible_time = 1;
Player.invincible_finished = time + Goal.invincible_finished;
}
if ((Goal.invisible_finished > 0) && (!puinvis))
{
// if its a GoalItem, powerup was permanent, so we remove TFSTATE flag
Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_INVISIBLE);
Player.items = Player.items | IT_INVISIBILITY;
Player.invisible_time = 1;
Player.invisible_finished = time + Goal.invisible_finished;
}
if ((Goal.super_damage_finished > 0) && (!puquad))
{
// if its a GoalItem, powerup was permanent, so we remove TFSTATE flag
Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_QUAD);
Player.items = Player.items | IT_QUAD;
Player.super_time = 1;
Player.super_damage_finished = time + Goal.super_damage_finished;
}
//WK Don't remove the scuba gear
if ((Goal.radsuit_finished > 0) && (!purad) && !(Player.tf_items & NIT_SCUBA))
{
// if its a GoalItem, powerup was permanent, so we remove TFSTATE flag
Player.tfstate = Player.tfstate - (Player.tfstate & TFSTATE_RADSUIT);
Player.items = Player.items | IT_SUIT;
Player.rad_time = 1;
Player.radsuit_finished = time + Goal.radsuit_finished;
}
// Now apply the Playerclass limitations & Redisplay Ammo counts
oldself = self;
self = Player;
TeamFortress_CheckClassStats();
W_SetCurrentAmmo ();
self = oldself;
};
//=========================================================================
// Return TRUE if the player meets the AP criteria
float(entity Goal, entity AP) APMeetsCriteria =
{
local float gotone, temp;
local entity te;
#ifdef MAP_DEBUG
RPrint("==========================\n");
#ifdef VERBOSE
RPrint("AP Criteria Checking\n");
RPrint("Goal: ");
#else
RPrint("APCriteria: ");
#endif
RPrint(Goal.netname);
#endif
if (AP)
{
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("\nAP : ");
#else
RPrint(" by ");
#endif
RPrint(AP.netname);
RPrint("\n");
RPrint(" Checking team.");
#endif
// If a player of a specific team can only activate this
if (Goal.team_no)
{
if (Goal.team_no != AP.team_no)
return FALSE;
}
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("passed.\n Checking class...");
#else
RPrint("class.");
#endif
#endif
//CH uses function in tfort.qc to return the class for evaluation
if (AP.playerclass == PC_CUSTOM && (Goal.playerclass))
{
temp = Return_Custom_Skins(AP);
//CH now that we have their 'class' check
if (Goal.playerclass != temp)
return FALSE;
}
// If a player of a specific class can only activate this
else if (Goal.playerclass)
{
if (Goal.playerclass != AP.playerclass)
return FALSE;
}
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("passed.\n Checking items...");
#else
RPrint("items.");
#endif
#endif
// If this activation needs a GoalItem, make sure the player has it
if (Goal.items_allowed)
{
te = Finditem(Goal.items_allowed);
if (te.owner != AP)
return FALSE;
}
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("passed.\n Checking goal states...");
#else
RPrint("goal states.");
#endif
#endif
}
#ifdef MAP_DEBUG
#ifdef VERBOSE
if (AP)
RPrint("passed.\n Checking Goal States...");
else
RPrint("\nChecking Goal States...");
#else
RPrint("Goal States.");
#endif
#endif
// Check Goal states
if (Goal.if_goal_is_active)
{
te = Findgoal(Goal.if_goal_is_active);
if (te.goal_state != TFGS_ACTIVE)
return FALSE;
}
if (Goal.if_goal_is_inactive)
{
te = Findgoal(Goal.if_goal_is_inactive);
if (te.goal_state != TFGS_INACTIVE)
return FALSE;
}
if (Goal.if_goal_is_removed)
{
te = Findgoal(Goal.if_goal_is_removed);
if (te.goal_state != TFGS_REMOVED)
return FALSE;
}
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("passed.\n Checking group states...");
#else
RPrint("group states.");
#endif
#endif
if (Goal.if_group_is_active)
{
// Find all goals in the group
te = find (NIL, classname, "info_tfgoal");
while (te)
{
if (te.group_no == Goal.if_group_is_active)
{
if (te.goal_state != TFGS_ACTIVE)
return FALSE;
}
te = find(te, classname, "info_tfgoal");
}
}
if (Goal.if_group_is_inactive)
{
// Find all goals in the group
te = find (NIL, classname, "info_tfgoal");
while (te)
{
if (te.group_no == Goal.if_group_is_inactive)
{
if (te.goal_state != TFGS_INACTIVE)
return FALSE;
}
te = find(te, classname, "info_tfgoal");
}
}
if (Goal.if_group_is_removed)
{
// Find all goals in the group
te = find (NIL, classname, "info_tfgoal");
while (te)
{
if (te.group_no == Goal.if_group_is_removed)
{
if (te.goal_state != TFGS_REMOVED)
return FALSE;
}
te = find(te, classname, "info_tfgoal");
}
}
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("passed.\n Checking item states...");
#else
RPrint("item states.");
#endif
#endif
if (Goal.if_item_has_moved)
{
// Find the item
te = Finditem(Goal.if_item_has_moved);
if (te)
{
if (te.goal_state != TFGS_ACTIVE && te.origin == te.oldorigin )
return FALSE;
}
}
if (Goal.if_item_hasnt_moved)
{
// Find the item
te = Finditem(Goal.if_item_hasnt_moved);
if (te)
{
if (te.goal_state == TFGS_ACTIVE || te.origin != te.oldorigin )
return FALSE;
}
}
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("passed.\n Checking item groups...");
#else
RPrint("item groups ");
#endif
#endif
if (AP)
{
gotone = FALSE;
if (Goal.has_item_from_group)
{
// Find all goals
te = find (NIL, classname, "item_tfgoal");
while (te && !gotone)
{
if (te.group_no == Goal.has_item_from_group && te.owner == AP)
gotone = TRUE;
te = find(te, classname, "item_tfgoal");
}
if (!gotone)
return FALSE;
}
}
#ifdef MAP_DEBUG
RPrint("passed.\n");
#endif
return TRUE;
};
//=========================================================================
// Setup the way this Timer/Goal/Item will respawn
void(entity Goal) SetupRespawn =
{
// Timer Goal?
if (Goal.search_time != 0)
{
InactivateGoal(Goal);
Goal.think = tfgoal_timer_tick;
Goal.nextthink = time + Goal.search_time;
return;
}
// Check status of respawn for this goal
// Single Activation, do nothing
if (Goal.goal_result & TFGR_SINGLE)
{
RemoveGoal(Goal);
return;
}
// Respawn Activation, set up respawn
if (Goal.wait > 0)
{
Goal.nextthink = time + Goal.wait;
Goal.think = DoRespawn;
if (Goal.mdl) //CH if it has mdl, remove it so
setmodel(Goal, ""); //that people dont think it works
return;
}
// Permanently active goal?
else if (Goal.wait == -1)
return;
// Otherwise, it's a Multiple Goal
InactivateGoal(Goal);
};
//=========================================================================
// Respawn the goal
void() DoRespawn =
{
RestoreGoal(self);
InactivateGoal(self);
};
//=========================================================================
// THE Function for knowing whether to activate or not
// Fuck this map code is a mess!
// Returns TRUE if you should activate, FALSE if not
float(entity Goal, entity AP) Activated =
{
local float APMet, RevAct, Act;
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("\nDoIActivate: ");
#else
RPrint("\nGoal: ");
#endif
if (!Goal.netname)
RPrint(Goal.classname);
else
RPrint(Goal.netname);
RPrint(", AP: ");
RPrint(AP.netname);
RPrint("\n");
#endif
if (Goal.goal_state == TFGS_ACTIVE)
{
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("-- Goal already active --\n");
#endif
#endif
return FALSE;
}
if (Goal.goal_state == TFGS_REMOVED)
{
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("-- Goal is in Removed state --\n");
#endif
#endif
return FALSE;
}
if (Goal.goal_state == TFGS_DELAYED)
{
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("-- Goal is being Delayed --\n");
#endif
#endif
return FALSE;
}
APMet = APMeetsCriteria(Goal, AP);
if (Goal.classname == "item_tfgoal")
RevAct = Goal.goal_activation & TFGI_REVERSE_AP;
else
RevAct = Goal.goal_activation & TFGA_REVERSE_AP;
Act = FALSE;
// Does the AP match the AP Criteria?
if (APMet)
{
#ifdef MAP_DEBUG
RPrint("\n");
#ifdef VERBOSE
RPrint("-- Criteria met --\n");
#endif
#endif
if (!RevAct)
Act = TRUE;
}
else
{
#ifdef MAP_DEBUG
RPrint("\n");
#ifdef VERBOSE
RPrint("-- Criteria not met --\n");
#endif
#endif
if (RevAct)
{
Act = TRUE;
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("Reverse \n");
#endif
#endif
}
}
#ifdef MAP_DEBUG
#ifdef VERBOSE
if (Act)
{
RPrint("Activation.\n");
}
else
{
RPrint("NO Activation.\n");
}
#endif
#endif
return Act;
};
//=========================================================================
// Attempt to activate a Goal
void(entity Goal, entity AP, entity ActivatingGoal) AttemptToActivate =
{
local entity te;
if (Activated(Goal, AP))
{
// It's all cool. Do the Results.
if (ActivatingGoal == Goal)
DoResults(Goal, AP, TRUE);
else if (ActivatingGoal)
DoResults(Goal, AP, (ActivatingGoal.goal_result & TFGR_ADD_BONUSES));
else
DoResults(Goal, AP, 0);
}
else
{
// If an else goal should be activated, activate it
if (Goal.else_goal != 0)
{
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint(" Else Goal.\n");
#endif
#endif
te = Findgoal(Goal.else_goal);
if (te)
AttemptToActivate(te, AP, ActivatingGoal);
}
}
};
//=========================================================================
// Do all the activation/inactivation/etc of individual Goals
void(entity Goal, entity AP) DoGoalWork =
{
local entity te, RI;
// If another goal should be activated, activate it
if (Goal.activate_goal_no != 0)
{
Update_team_with_flag_touch(Goal.activate_goal_no);
te = Findgoal(Goal.activate_goal_no);
if (te)
AttemptToActivate(te, AP, Goal);
}
// If another goal should be inactivated, inactivate it
if (Goal.inactivate_goal_no != 0)
{
Update_team_with_flag_drop(Goal.inactivate_goal_no);
te = Findgoal(Goal.inactivate_goal_no);
if (te)
InactivateGoal(te);
}
// If another goal should be restored, restore it
if (Goal.restore_goal_no != 0)
{
te = Findgoal(Goal.restore_goal_no);
if (te)
RestoreGoal(te);
}
// If another goal should be removed, remove it
if (Goal.remove_goal_no != 0)
{
te = Findgoal(Goal.remove_goal_no);
if (te)
RemoveGoal(te);
}
// If a GoalItem should be returned, return it
if (Goal.return_item_no != 0)
{
te = Finditem(Goal.return_item_no);
if (te)
{
if (te.goal_state == TFGS_ACTIVE)
tfgoalitem_RemoveFromPlayer(te, te.owner, 1);
RI = spawn();
RI.enemy = te;
RI.think = ReturnItem;
RI.nextthink = time + 0.1;
te.solid = SOLID_NOT;
}
}
// Spawnpoint behaviour
if (Goal.remove_spawnpoint != 0)
{
te = Findteamspawn(Goal.remove_spawnpoint);
if (te)
{
te.goal_state = TFGS_REMOVED;
te.team_str_home = "";
}
}
if (Goal.restore_spawnpoint != 0)
{
te = Findteamspawn(Goal.restore_spawnpoint);
if (te)
{
if (te.goal_state == TFGS_REMOVED)
{
te.goal_state = TFGS_INACTIVE;
if (te.team_no == 1)
te.team_str_home = "ts1";
else if (te.team_no == 2)
te.team_str_home = "ts2";
else if (te.team_no == 3)
te.team_str_home = "ts3";
else if (te.team_no == 4)
te.team_str_home = "ts4";
}
}
}
};
//=========================================================================
// Do all the activation/inactivation/etc of Goal Groups
void(entity Goal, entity AP) DoGroupWork =
{
local string st;
local entity tg;
local float allset;
// Check all goals activated flag
if (Goal.all_active != 0)
{
if (Goal.last_impulse == 0)
{
// No goal specified in .lastimpulse. Print error.
RPrint("Goal ");
st = ftos(Goal.goal_no);
RPrint(st);
RPrint(" has a .all_active specified, but no .last_impulse\n");
}
else
{
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("All Active Group Check.\n");
#endif
#endif
allset = 1;
// Find all goals
tg = find (NIL, classname, "info_tfgoal");
while (tg)
{
if (tg.group_no == Goal.all_active)
{
if (tg.goal_state != TFGS_ACTIVE)
allset = 0;
}
tg = find(tg, classname, "info_tfgoal");
}
// If all goals in this group are activated, do it
if (allset)
{
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("All Active, Activating last_impulse.\n");
#endif
#endif
tg = Findgoal(Goal.last_impulse);
if (tg)
DoResults(tg, AP, (Goal.goal_result & TFGR_ADD_BONUSES));
}
#ifdef MAP_DEBUG
#ifdef VERBOSE
else
{
RPrint("Not all Active.\n");
}
#endif
#endif
}
}
// Check Activate all in the group flag
if (Goal.activate_group_no != 0)
{
// Find all goals
tg = find (NIL, classname, "info_tfgoal");
while (tg)
{
if (tg.group_no == Goal.activate_group_no)
DoResults(tg, AP, 0); // Don't apply bonuses
tg = find(tg, classname, "info_tfgoal");
}
}
// Check Inactivate all in the group flag
if (Goal.inactivate_group_no != 0)
{
// Find all goals
tg = find (NIL, classname, "info_tfgoal");
while (tg)
{
if (tg.group_no == Goal.inactivate_group_no)
InactivateGoal(tg);
tg = find(tg, classname, "info_tfgoal");
}
}
// Check Remove all in the group flag
if (Goal.remove_group_no != 0)
{
// Find all goals
tg = find (NIL, classname, "info_tfgoal");
while (tg)
{
if (tg.group_no == Goal.remove_group_no)
RemoveGoal(tg);
tg = find(tg, classname, "info_tfgoal");
}
}
// Check Restore all in the group flag
if (Goal.restore_group_no != 0)
{
// Find all goals
tg = find (NIL, classname, "info_tfgoal");
while (tg)
{
if (tg.group_no == Goal.restore_group_no)
RestoreGoal(tg);
tg = find(tg, classname, "info_tfgoal");
}
}
// Spawnpoint behaviour
if (Goal.remove_spawngroup != 0)
{
// Find all goals
tg = find (NIL, classname, "info_player_teamspawn");
while (tg)
{
if (tg.group_no == Goal.remove_spawngroup)
{
tg.goal_state = TFGS_REMOVED;
tg.team_str_home = "";
}
tg = find(tg, classname, "info_player_teamspawn");
}
}
if (Goal.restore_spawngroup != 0)
{
// Find all goals
tg = find (NIL, classname, "info_player_teamspawn");
while (tg)
{
if (tg.group_no == Goal.restore_spawngroup)
{
tg.goal_state = TFGS_INACTIVE;
if (tg.team_no == 1)
tg.team_str_home = "ts1";
else if (tg.team_no == 2)
tg.team_str_home = "ts2";
else if (tg.team_no == 3)
tg.team_str_home = "ts3";
else if (tg.team_no == 4)
tg.team_str_home = "ts4";
}
tg = find(tg, classname, "info_player_teamspawn");
}
}
};
//=========================================================================
// Do all the checking of Item Groups
void(entity Item, entity AP) DoItemGroupWork =
{
local entity tg, carrier;
local float allcarried;
local string st;
allcarried = TRUE;
if (Item.distance != 0)
{
if (Item.pain_finished == 0)
{
// No goal specified in .pain_finished. Print error.
RPrint("GoalItem ");
st = ftos(Item.goal_no);
RPrint(st);
RPrint(" has a .distance specified, but no .pain_finished\n");
}
// Find all goals
tg = find (NIL, classname, "item_tfgoal");
while (tg)
{
if (tg.group_no == Item.distance)
{
if (tg.goal_state != TFGS_ACTIVE)
allcarried = FALSE;
}
tg = find(tg, classname, "item_tfgoal");
}
if (allcarried == TRUE)
{
tg = Findgoal(Item.pain_finished);
if (tg)
DoResults(tg, AP, (Item.goal_result & TFGR_ADD_BONUSES));
}
}
allcarried = TRUE;
if (Item.speed != 0)
{
if (Item.attack_finished == 0)
{
// No goal specified in .attack_finished. Print error.
RPrint("GoalItem ");
st = ftos(Item.goal_no);
RPrint(st);
RPrint(" has a .speed specified, but no .attack_finished\n");
}
carrier = NIL;
// Find all goals
tg = find (NIL, classname, "item_tfgoal");
while (tg)
{
if (tg.group_no == Item.speed)
{
if (tg.goal_state != TFGS_ACTIVE)
allcarried = FALSE;
else if (!carrier)
carrier = tg.owner;
else if (carrier != tg.owner)
allcarried = FALSE;
}
tg = find(tg, classname, "item_tfgoal");
}
if (allcarried == TRUE)
{
tg = Findgoal(Item.attack_finished);
if (tg)
DoResults(tg, AP, (Item.goal_result & TFGR_ADD_BONUSES));
}
}
};
//=========================================================================
// Do all the activation/removal of Quake Triggers
void(entity Goal, entity AP) DoTriggerWork =
{
local entity otemp, stemp, t;
#ifdef MAP_DEBUG
if (Goal.killtarget)
{
RPrint("Killing Target(s): ");
RPrint(Goal.killtarget);
RPrint("\n");
}
#endif
// remove targets
if (Goal.killtarget)
{
t = NIL;
do
{
t = find(t, targetname, Goal.killtarget);
if (t && t != Goal)
remove(t);
} while ( t );
}
#ifdef MAP_DEBUG
if (Goal.target)
{
RPrint("Activating Target(s): ");
RPrint(Goal.target);
RPrint("\n");
}
#endif
// fire targets
if (Goal.target)
{
t = NIL;
activator = AP;
do
{
t = find (t, targetname, Goal.target);
if (!t)
return;
stemp = self;
otemp = other;
self = t;
other = stemp;
if (self.use)
self.use ();
self = stemp;
other = otemp;
activator = AP;
} while ( t );
}
};
//=========================================================================
// Handles Delayed Activation of Goals
void() DelayedResult =
{
if (self.enemy.goal_state == TFGS_DELAYED)
DoResults(self.enemy, self.owner, self.weapon);
dremove(self);
};
//=========================================================================
// Do the results for the Timer/Goal/Item
void(entity Goal, entity AP, float addb) DoResults =
{
local entity te;
local float winners;
// Is the goal already activated?
// This check is needed for goals which are being activated by other goals
if (Goal.goal_state == TFGS_ACTIVE)
return;
// Delayed Activation?
if (Goal.delay_time > 0 && Goal.goal_state != TFGS_DELAYED)
{
#ifdef MAP_DEBUG
RPrint("Delaying Results of ");
RPrint(Goal.netname);
RPrint("\n");
#endif
Goal.goal_state = TFGS_DELAYED;
te = spawn();
te.think = DelayedResult;
te.nextthink = time + Goal.delay_time;
te.owner = AP;
te.enemy = Goal;
te.weapon = addb;
return;
}
UpdateAbbreviations(Goal);
Goal.goal_state = TFGS_INACTIVE;
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("-= Doing Results =-\n");
RPrint("Goal: ");
#else
RPrint("DoRes: ");
#endif
RPrint(Goal.netname);
#ifdef VERBOSE
RPrint("\nAP : ");
#else
RPrint(" by ");
#endif
RPrint(AP.netname);
if (addb)
RPrint("\n adding bonuses");
else
RPrint("\nNOT adding bonuses");
#ifdef VERBOSE
RPrint("\n-=================-\n");
#else
RPrint("\n");
#endif
#endif
//- OfN if Goal.option is 1 then no sound attenuation (ATTN_NONE)
local float attn_value;
attn_value=ATTN_NORM;
if (Goal.option == 1)
attn_value=ATTN_NONE;
// Make the sound
if (Goal.noise)
sound (other, CHAN_ITEM, Goal.noise, 1, attn_value);
winners = FALSE;
// Increase scores
if (Goal.increase_team1 != 0)
{
TeamFortress_TeamIncreaseScore(1, Goal.increase_team1);
//if (chris)
// RoundStop(1);
winners = TRUE;
}
if (Goal.increase_team2 != 0)
{
TeamFortress_TeamIncreaseScore(2, Goal.increase_team2);
//if (chris)
// RoundStop(2);
winners = TRUE;
}
if (Goal.increase_team3 != 0)
{
TeamFortress_TeamIncreaseScore(3, Goal.increase_team3);
//if (chris)
// RoundStop(3);
winners = TRUE;
}
if (Goal.increase_team4 != 0)
{
TeamFortress_TeamIncreaseScore(4, Goal.increase_team4);
//if (chris)
// RoundStop(4);
winners = TRUE;
}
// Display short team scores only if scores changed
if (winners == TRUE)
TeamFortress_TeamShowScores(2);
// CTF Map support
if (CTF_Map == TRUE)
{
if (AP)
{
if (Goal.goal_no == CTF_FLAG1)
{
te = find(NIL, classname, "player");
while (te)
{
if (te.team_no == 2)
{
if (te == AP)
{
winners = random();
if (winners < 0.1)
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM1);
else if (winners < 0.2)
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM2);
else if (winners < 0.6)
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM3);
else if (winners < 0.7)
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM4);
else if (winners < 0.8)
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM5_2);
else if (winners < 0.95)
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM6);
else
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM7);
}
else
CenterPrint2(te, "\n\n\n", "Your team <20><><EFBFBD> the <20><><EFBFBD><EFBFBD><EFBFBD> flag!!");
}
else
CenterPrint2(te, "\n\n\n", "Your flag has been <20><><EFBFBD><EFBFBD><EFBFBD>!!");
te = find(te, classname, "player");
}
bprint(PRINT_HIGH, AP.netname);
bprint(PRINT_HIGH, " <20><><EFBFBD> the <20><><EFBFBD><EFBFBD> flag!\n");
AP.items = AP.items | IT_KEY1;
}
else if (Goal.goal_no == CTF_FLAG2)
{
te = find(NIL, classname, "player");
while (te)
{
if (te.team_no == 1)
{
if (te == AP)
{
winners = random();
if (winners < 0.1)
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM1);
else if (winners < 0.2)
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM2);
else if (winners < 0.6)
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM3);
else if (winners < 0.7)
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM4);
else if (winners < 0.8)
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM5_1);
else if (winners < 0.95)
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM6);
else
CenterPrint2(te, "\n\n\n", MSG_CTF_FLAG_GRAB_TEAM7);
}
else
CenterPrint2(te, "\n\n\n", "Your team <20><><EFBFBD> the <20><><EFBFBD><EFBFBD><EFBFBD> flag!!");
}
else
CenterPrint2(te, "\n\n\n", "Your flag has been <20><><EFBFBD><EFBFBD><EFBFBD>!!");
te = find(te, classname, "player");
}
bprint(PRINT_HIGH, AP.netname);
bprint(PRINT_HIGH, " <20><><EFBFBD> the <20><><EFBFBD> flag!\n");
AP.items = AP.items | IT_KEY2;
}
else if (Goal.goal_no == CTF_DROPOFF1)
{
te = find(NIL, classname, "player");
while (te)
{
if (te.team_no == 2)
{
if (te == AP)
CenterPrint2(te, "\n\n\n", "You <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the flag!!");
else
CenterPrint2(te, "\n\n\n", "Your flag was <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!!");
}
else
CenterPrint2(te, "\n\n\n", "Your team <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the flag!!");
te = find(te, classname, "player");
}
bprint(PRINT_HIGH, AP.netname);
bprint(PRINT_HIGH, " <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the <20><><EFBFBD> flag!\n");
AP.items = AP.items & ~IT_KEY2;
}
else if (Goal.goal_no == CTF_DROPOFF2)
{
te = find(NIL, classname, "player");
while (te)
{
if (te.team_no == 1)
{
if (te == AP)
CenterPrint2(te, "\n\n\n", "You <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the flag!!");
else
CenterPrint2(te, "\n\n\n", "Your flag was <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!!");
}
else
CenterPrint2(te, "\n\n\n", "Your team <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the flag!!");
te = find(te, classname, "player");
}
bprint(PRINT_HIGH, AP.netname);
bprint(PRINT_HIGH, " <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the <20><><EFBFBD><EFBFBD> flag!\n");
AP.items = AP.items & ~IT_KEY1;
}
}
}
// Go through all the players and do any results
te = find(NIL, classname, "player");
while (te)
{
// Centerprinting
if (Goal.broadcast && CTF_Map == FALSE)
CenterPrint2(te, "\n\n\n", Goal.broadcast);
if (Goal.netname_broadcast && CTF_Map == FALSE)
{
sprint(te, PRINT_HIGH, AP.netname);
sprint(te, PRINT_HIGH, Goal.netname_broadcast);
}
if (AP == te)
{
if (Goal.message)
CenterPrint2(te, "\n\n\n", Goal.message);
}
else if (AP.team_no == te.team_no)
{
if (Goal.owners_team_broadcast && te.team_no == Goal.owned_by)
CenterPrint2(te, "\n\n\n", Goal.owners_team_broadcast);
else if (Goal.team_broadcast)
CenterPrint2(te, "\n\n\n", Goal.team_broadcast);
if (Goal.netname_owners_team_broadcast && te.team_no == Goal.owned_by)
{
sprint(te, PRINT_HIGH, AP.netname);
sprint(te, PRINT_HIGH, Goal.netname_owners_team_broadcast);
}
else if (Goal.netname_team_broadcast)
{
sprint(te, PRINT_HIGH, AP.netname);
sprint(te, PRINT_HIGH, Goal.netname_team_broadcast);
}
}
else
{
if (Goal.owners_team_broadcast && te.team_no == Goal.owned_by)
CenterPrint2(te, "\n\n\n", Goal.owners_team_broadcast);
else if (Goal.non_team_broadcast)
CenterPrint2(te, "\n\n\n", Goal.non_team_broadcast);
if (Goal.netname_owners_team_broadcast && te.team_no == Goal.owned_by)
{
sprint(te, PRINT_HIGH, AP.netname);
sprint(te, PRINT_HIGH, Goal.netname_owners_team_broadcast);
}
else if (Goal.netname_non_team_broadcast)
{
sprint(te, PRINT_HIGH, AP.netname);
sprint(te, PRINT_HIGH, Goal.netname_non_team_broadcast);
}
}
if (IsAffectedBy(Goal, te, AP))
{
// If its a Timer Goal, see if it needs to check Criteria again
if (Goal.search_time != 0 && Goal.goal_effects & TFGE_TIMER_CHECK_AP)
{
if (APMeetsCriteria(Goal, te))
Apply_Results(Goal, te, AP, addb);
}
else
{
Apply_Results(Goal, te, AP, addb);
}
}
te = find(te, classname, "player");
}
// Goal is now active
// Items are not always set to active. They handle their modes.
if (Goal.classname != "item_tfgoal")
Goal.goal_state = TFGS_ACTIVE;
// EndGame checking
if (Goal.goal_result & TFGR_ENDGAME)
{
// Display Long TeamScores to everyone
TeamFortress_TeamShowScores(1);
winners = TeamFortress_TeamGetWinner();
// Stop everyone
te = find (NIL, classname, "player");
while (te)
{
te.takedamage = 0;
te.movetype = MOVETYPE_NONE;
te.velocity = '0 0 0';
te.avelocity = '0 0 0';
te = find(te, classname, "player");
}
te = spawn();
te.nextthink = time + 5; // Allow 5 secs to read the scores
te.think = execute_changelevel;
dremove(Goal);
return;
}
//CH spawn explosions if so needed
if (Goal.goal_effects & TFGE_CAUSE_EXPLOSION)
{
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);
// BecomeExplosion();
}
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("Doing Groupwork...\n");
#endif
#endif
// Do Goal Group checking
DoGroupWork(Goal, AP);
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("Doing Goalwork...\n");
#endif
#endif
// Do Goal checking
DoGoalWork(Goal, AP);
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("Doing Triggerwork...\n");
#endif
#endif
// Do Quake Trigger actions
DoTriggerWork(Goal, AP);
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("Setting up Respawn...\n");
#endif
#endif
if (Goal.killtarget && Goal.killtarget == Goal.targetname) {
// self destructive trigger
remove (Goal);
} else {
// Setup for Respawn
// Items and Triggers do their own respawn work
if (Goal.classname == "info_tfgoal")
SetupRespawn(Goal);
}
};
//=========================================================================
// GOAL FUNCTIONS
//=========================================================================
// Touch function for Goals
void() tfgoal_touch =
{
local entity te;
// If it is not activated in by the player's touch, return
if (!(self.goal_activation & TFGA_TOUCH))
return;
if (other.classname != "player")
return;
// If we're in prematch mode, ignore the touch
if (prematch >= time)
return;
if (other.penance_time >= time)
return;
// If it's already active, don't bother
if (self.goal_state == TFGS_ACTIVE)
{
#ifdef MAP_DEBUG
RPrint("Goal already active. aborting touch.\n");
#endif
return;
}
// CTF Hack to make sure the key is in place.
// Temporary hack :)
if (CTF_Map == TRUE)
{
if ((self.goal_no == CTF_DROPOFF1) && (other.team_no == 1))
{
te = Finditem(CTF_FLAG1);
if ((te.goal_state == TFGS_ACTIVE) || (te.origin != te.oldorigin))
return;
}
if ((self.goal_no == CTF_DROPOFF2) && (other.team_no == 2))
{
te = Finditem(CTF_FLAG2);
if ((te.goal_state == TFGS_ACTIVE) || (te.origin != te.oldorigin))
return;
}
}
AttemptToActivate(self, other, self);
};
//=========================================================================
// Use (Triggered) function for Goals
void() info_tfgoal_use =
{
#ifdef MAP_DEBUG
RPrint("\n");
RPrint("TFGoal triggered by other entity.\n");
#endif
AttemptToActivate(self, activator, self);
};
//=========================================================================
// Timer goal tick
void() tfgoal_timer_tick =
{
// Check criteria
if (self.goal_state != TFGS_REMOVED)
{
#ifdef MAP_DEBUG
RPrint("==========================\n");
#ifdef VERBOSE
RPrint("Timer Tick for: ");
#else
RPrint("Tick: ");
#endif
RPrint(self.netname);
RPrint(" Checking criteria...");
#endif
if (APMeetsCriteria(self, NIL))
{
DoResults(self, NIL, TRUE);
}
else
{
InactivateGoal(self);
self.think = tfgoal_timer_tick;
self.nextthink = time + self.search_time;
}
}
};
//=========================================================================
// GOALITEM FUNCTIONS
//=========================================================================
// Touch function for the goalitem entity
void() item_tfgoal_touch =
{
if (infokey(NIL,"ceasefire")=="on") //OfN
return;
local entity te;
if (other.classname != "player")
return;
if (other.health <= 0)
return;
// Don't let them take goalitems in prematch
if (prematch >= time)
return;
// Don't let lame teamkillers take items
if (other.penance_time >= time)
return;
// CTF Hack to return your key.
// Temporary hack :)
if (CTF_Map == TRUE)
{
if (self.goal_no == CTF_FLAG1)
{
// Flag not at home?
if (self.origin != self.oldorigin)
{
if (other.team_no == 1)
{
bprint(PRINT_HIGH, other.netname);
bprint(PRINT_HIGH, " <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the <20><><EFBFBD><EFBFBD> flag!\n");
te = find(NIL, classname, "player");
while (te)
{
if (te.team_no == 1)
CenterPrint2(te, "\n\n\n", "Your flag was <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!!");
else
CenterPrint2(te, "\n\n\n", "The <20><><EFBFBD><EFBFBD><EFBFBD> flag was <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!!");
te = find(te, classname, "player");
}
self.goal_state = TFGS_INACTIVE;
self.solid = SOLID_TRIGGER;
self.touch = item_tfgoal_touch;
self.origin = self.oldorigin;
setmodel(self, self.mdl);
setorigin(self, self.origin);
sound (self, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM);
return;
}
}
else
{
if (other.team_no == 1)
return;
}
}
else if (self.goal_no == CTF_FLAG2)
{
// Flag not at home?
if (self.origin != self.oldorigin)
{
if (other.team_no == 2)
{
bprint(PRINT_HIGH, other.netname);
bprint(PRINT_HIGH, " <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the <20><><EFBFBD> flag!\n");
te = find(NIL, classname, "player");
while (te)
{
if (te.team_no == 2)
CenterPrint(te, "\n\n\n Your flag was <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!!");
else
CenterPrint(te, "\n\n\n The <20><><EFBFBD><EFBFBD><EFBFBD> flag was <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!!");
te = find(te, classname, "player");
}
self.goal_state = TFGS_INACTIVE;
self.solid = SOLID_TRIGGER;
self.touch = item_tfgoal_touch;
self.origin = self.oldorigin;
setmodel(self, self.mdl);
setorigin(self, self.origin);
sound (self, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM);
return;
}
}
else
{
if (other.team_no == 2)
return;
}
}
}
if (Activated(self, other))
{
// Give it to the player
tfgoalitem_GiveToPlayer(self, other, self);
self.goal_state = TFGS_ACTIVE;
}
else
{
// If an else goal should be activated, activate it
if (self.else_goal != 0)
{
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint(" Else Goal.\n");
#endif
#endif
te = Findgoal(self.else_goal);
if (te)
AttemptToActivate(te, other, self);
}
}
};
//=========================================================================
// Give the GoalItem to a Player.
void(entity Item, entity AP, entity Goal) tfgoalitem_GiveToPlayer =
{
#ifdef MAP_DEBUG
RPrint("Giving ");
RPrint(Item.netname);
RPrint(" to ");
RPrint(AP.netname);
RPrint("\n");
#endif
Item.owner = AP;
// Remove it from the map
if (Item.mdl)
setmodel(Item, "");
Item.solid = SOLID_NOT;
// Do the deeds on the player
if (Item.goal_activation & TFGI_GLOW)
AP.effects = AP.effects | EF_GlowColor(AP);
if (Item.goal_activation & TFGI_SLOW)
TeamFortress_SetSpeed(AP);
if (Item.goal_activation & TFGI_ITEMGLOWS)
Item.effects &= ~EF_ANYGLOW;
// Light up console icons
if (Item.items & IT_KEY1)
AP.items = AP.items | IT_KEY1;
if (Item.items & IT_KEY2)
AP.items = AP.items | IT_KEY2;
// Only do the results if we're allowed to
if (Goal != Item)
{
if (Goal.goal_result & TFGR_NO_ITEM_RESULTS)
{
Item.goal_state = TFGS_ACTIVE;
return;
}
}
#ifdef MAP_DEBUG
#ifdef VERBOSE
RPrint("Doing item results...\n");
#endif
#endif
// Prevent the Player from disguising themself if applicable
//CH added looking for spykit & thief
if (Item.goal_result & TFGR_REMOVE_DISGUISE)
{
if (AP.job & JOB_THIEF && (AP.job & JOB_ACTIVE || AP.job & JOB_FULL_HIDE))
RevealThief(AP,FALSE);
if (AP.playerclass == PC_SPY || AP.cutf_items & CUTF_SPY_KIT)
{
AP.is_unabletospy = 1;
}
}
// Do the Results, adding the bonuses
DoResults(Item, AP, TRUE);
// Check the Item Group Stuff
DoItemGroupWork(Item, AP);
};
//=========================================================================
//Update which team has the flag
void(float item) Update_team_with_flag_touch =
{
if ( mapname != "steal4d" )
{
team_with_flag = 0;
return;
}
if (item == 103)
{
team_with_flag = 1;
friends1_mask = 0;
friends2_mask = friends3_mask = friends4_mask = 14;
return;
}
if (item == 203) {
team_with_flag = 2;
friends2_mask = 0;
friends1_mask = friends3_mask = friends4_mask = 13;
return;
}
if (item == 303) {
team_with_flag = 3;
friends3_mask = 0;
friends1_mask = friends2_mask = friends4_mask = 11;
return;
}
if (item == 403) {
team_with_flag = 4;
friends4_mask = 0;
friends1_mask = friends2_mask = friends3_mask = 7;
return;
}
};
//=========================================================================
//Update which team has the flag
void(float item) Update_team_with_flag_drop =
{
if ( mapname != "steal4d" ){
team_with_flag = 0;
return;
}
if (item != 103 && item != 203 && item != 303 && item != 403)
return;
team_with_flag= 0;
friends1_mask= friends2_mask= friends3_mask= friends4_mask= 0;
};
//=========================================================================
// Return the Item to its starting point
void() ReturnItem =
{
self.enemy.goal_state = TFGS_INACTIVE;
//CH sets solid type
if (self.enemy.goal_activation & TFGI_GOAL_IS_SOLID)
self.enemy.solid = SOLID_BBOX;
else
self.enemy.solid = SOLID_TRIGGER;
self.enemy.movetype = MOVETYPE_NONE;
self.enemy.touch = item_tfgoal_touch;
self.enemy.origin = self.enemy.oldorigin;
if (self.enemy.mdl)
setmodel(self.enemy, self.enemy.mdl);
setorigin(self.enemy, self.enemy.origin);
sound(self.enemy, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM);
// Restore a goal if needed
tfgoalitem_checkgoalreturn(self.enemy);
dremove(self);
};
//=========================================================================
// Remove the GoalItem from a Player.
void(entity Item, entity AP, float method) tfgoalitem_RemoveFromPlayer =
{
local entity te;
local float slowon;
local float key1on, key2on;
local float spyoff;
local entity DelayReturn;
if (!Item)
{
RPrint("error: tfgoalitem_RemoveFromPlayer(): !Item");
return;
}
#ifdef MAP_DEBUG
RPrint("Removing ");
RPrint(Item.netname);
RPrint(" from ");
RPrint(AP.netname);
RPrint("\n");
#endif
slowon = FALSE;
key1on = FALSE;
key2on = FALSE;
spyoff = FALSE;
// Remove the deeds from the player
// Make sure we don't remove an effect another Goal is also supplying
AP.effects &= ~EF_ANYGLOW;
if (Item.goal_activation & TFGI_ITEMGLOWS)
Item.effects = Item.effects | EF_GlowColor(Item);
// Remove the Spy prevention
if (!spyoff)
AP.is_unabletospy = 0;
// Remove the Light up of console icons
if (!key1on)
AP.items = AP.items & ~IT_KEY1;
if (!key2on)
AP.items = AP.items & ~IT_KEY2;
// Remove AP Modifications
// Go through all the players and do any results
te = find(NIL, classname, "player");
while (te)
{
if (IsAffectedBy(Item, te, AP))
{
RemoveResults(Item, te);
}
te = find(te, classname, "player");
}
/*
db1 = ftos(method);
RPrint("returning via method : ");
RPrint(db1);
RPrint("\n");
*/
// Return it to the starting point if the flag is set
if (method == 0) // Dropped by a dying player
{
// Do messages
te = find(NIL, classname, "player");
while (te)
{
if (te.team_no == Item.owned_by)
{
if (Item.team_drop)
CenterPrint2(te, "\n\n\n", Item.team_drop);
if (Item.netname_team_drop)
{
sprint(te, PRINT_HIGH, AP.netname);
sprint(te, PRINT_HIGH, Item.netname_team_drop);
}
}
else // (te.team_no != Item.owned_by)
{
if (Item.non_team_drop)
CenterPrint2(te, "\n\n\n", Item.non_team_drop);
if (Item.netname_non_team_drop)
{
sprint(te, PRINT_HIGH, AP.netname);
sprint(te, PRINT_HIGH, Item.netname_non_team_drop);
}
}
te = find(te, classname, "player");
}
// Drop it if the flag is set
if (Item.goal_activation & TFGI_RETURN_DROP)
{
DelayReturn = spawn();
DelayReturn.enemy = Item;
DelayReturn.think = ReturnItem;
DelayReturn.nextthink = time + 0.5;
Item.owner = NIL;
TeamFortress_SetSpeed (AP);
AP.effects |= EF_GlowColor (AP);
/*
Item.solid = SOLID_TRIGGER;
Item.touch = item_tfgoal_touch;
Item.origin = Item.oldorigin;
setmodel(Item, Item.mdl);
setorigin(Item, Item.origin);
sound (Item, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM);
*/
}
else if (Item.goal_activation & TFGI_DROP)
{
tfgoalitem_drop(Item);
AP.effects |= EF_GlowColor(AP);
}
else
{
// Remove the Item
Item.owner = NIL;
dremove(Item);
TeamFortress_SetSpeed(AP);
AP.effects |= EF_GlowColor(AP);
return;
}
return;
}
// Return it to the starting point if the flag is set
if (method == 1) // Removed by a goal activation
{
/*
bprint(Item.netname);
bprint(" ");
bprint(Item.mdl);
bprint(" ");
bprint(vtos(Item.origin));
bprint(" ");
bprint(vtos(Item.oldorigin));
bprint("\n");
*/
if (Item.goal_activation & TFGI_RETURN_GOAL)
{
DelayReturn = spawn();
DelayReturn.enemy = Item;
DelayReturn.think = ReturnItem;
DelayReturn.nextthink = time + 0.5;
/*
Item.origin = Item.oldorigin;
setorigin(Item, Item.origin);
Item.solid = SOLID_TRIGGER;
Item.touch = item_tfgoal_touch;
setmodel(Item, Item.mdl);
sound (Item, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM);
// Restore a goal if needed
tfgoalitem_checkgoalreturn(Item);
*/
Item.owner = NIL;
TeamFortress_SetSpeed(AP);
AP.effects |= EF_GlowColor(AP);
return;
}
// Don't remove it, since it may be given away again later
Item.solid = SOLID_NOT;
Item.owner = NIL;
TeamFortress_SetSpeed(AP);
AP.effects |= EF_GlowColor(AP);
return;
}
RPrint("Invalid method passed into tfgoalitem_RemoveFromPlayer\n");
};
//=========================================================================
// A quick check to make sure the items is not in a wall
void() tfgoalitem_dropthink =
{
local float pos;
#ifdef MAP_DEBUG
RPrint("DropThink for ");
RPrint(self.netname);
RPrint("\n");
#endif
// If the flag is set, remove it after 2 minutes
self.movetype = MOVETYPE_TOSS;
if (self.pausetime != 0)
{
pos = pointcontents(self.origin); // find the location of the Item
if (pos == CONTENTS_SLIME)
self.nextthink = time + (self.pausetime / 4);
else if (pos == CONTENTS_LAVA)
self.nextthink = time + 5;
else if (pos == CONTENTS_SOLID || pos == CONTENTS_SKY) // oh shit!
self.nextthink = time + 2;
else
self.nextthink = time + self.pausetime;
self.think = tfgoalitem_remove;
}
};
//CH does same as above but sets origion when done.
void() tfgoalitem_dropthink2 =
{
local float pos;
#ifdef MAP_DEBUG
RPrint("DropThink for ");
RPrint(self.netname);
RPrint("\n");
#endif
// If the flag is set, remove it after 2 minutes
self.movetype = MOVETYPE_TOSS;
/* CH leave this as it is working code. that below this is a test, which seems to work well.
// if (self.pausetime != 0)
// {
pos = pointcontents(self.origin); // find the location of the Item
if (pos == CONTENTS_SLIME)
self.nextthink = time + (self.pausetime / 4);
else if (pos == CONTENTS_LAVA)
self.nextthink = time + 5;
else if (pos == CONTENTS_SOLID || pos == CONTENTS_SKY) // oh shit!
self.nextthink = time + 2;
else
self.nextthink = time + self.pausetime;
self.think = tfgoalitem_remove;
self.velocity = '0 0 0';
self.oldorigin = self.origin;
// }
*/
// if (self.pausetime != 0)
// {
pos = pointcontents(self.origin); // find the location of the Item
if (pos == CONTENTS_SLIME)
setorigin(self, self.oldorigin);
else if (pos == CONTENTS_LAVA)
setorigin(self, self.oldorigin);
else if (pos == CONTENTS_SOLID || pos == CONTENTS_SKY) // oh shit!
setorigin(self, self.oldorigin);
else
setorigin(self, self.origin);
self.velocity = '0 0 0';
self.oldorigin = self.origin;
// }
};
//=========================================================================
// Drop the item just like a backpack
void(entity Item) tfgoalitem_drop =
{
local vector temp1;
local vector temp2;
Item.origin = Item.owner.origin;
Item.velocity_z = 400;
Item.velocity_x = -50 + (random() * 100);
Item.velocity_y = -50 + (random() * 100);
Item.movetype = MOVETYPE_TOSS;
//CH set solid state
if (Item.goal_activation & TFGI_GOAL_IS_SOLID)
Item.solid = SOLID_BBOX;
else
Item.solid = SOLID_TRIGGER;
setorigin(Item, Item.origin);
//CH sets goal bounding box size
if (Item.goal_min)
temp1 = Item.goal_min;
else
temp1 = '-16 -16 -24';
if (Item.goal_max)
temp2 = Item.goal_max;
else
temp2 = '16 16 32';
setsize (Item, temp1, temp2); //CH sets box size from above
if (Item.mdl)
setmodel(Item, Item.mdl);
if (!Item.owner.deadflag) //checks for dropitems
{
makevectors(Item.owner.v_angle);
Item.velocity = v_forward * 400 + v_up * 200;
Item.nextthink = time + 0.75; //CH wait a sec then make it pickupable GR .75 to match tf 2.9
Item.think = tfgoalitem_settouchandthink;
}
else
{
Item.nextthink = time + 5.0; // give it five seconds
Item.think = tfgoalitem_dropthink; // and then find where it ended up
Item.goal_state = TFGS_INACTIVE;
Item.touch = item_tfgoal_touch;
Item.owner = NIL;
}
};
//CH brings the item online after 1 sec
void() tfgoalitem_settouchandthink =
{
self.nextthink = time + 4.25; // give it five seconds
self.think = tfgoalitem_dropthink; // and then find where it ended up
self.goal_state = TFGS_INACTIVE;
self.touch = item_tfgoal_touch;
local entity o = self.owner;
self.owner = NIL;
TeamFortress_SetSpeed (o);
o.effects &= ~EF_ANYGLOW;
o.effects |= EF_GlowColor (o);
};
//=========================================================================
// Remove the item, or Return it if needed
void() tfgoalitem_remove =
{
local entity te;
#ifdef MAP_DEBUG
RPrint("RemoveItem for ");
RPrint(self.netname);
RPrint("... ");
#endif
// Has someone picked it up?
if (self.goal_state == TFGS_ACTIVE)
return;
// Should it be returned?
if (self.goal_activation & TFGI_RETURN_REMOVE)
{
#ifdef MAP_DEBUG
RPrint("Returned.\n");
#endif
//CH set solid state
if (self.goal_activation & TFGI_GOAL_IS_SOLID)
self.solid = SOLID_BBOX;
else
self.solid = SOLID_TRIGGER;
self.movetype = MOVETYPE_NONE;
self.touch = item_tfgoal_touch;
self.origin = self.oldorigin;
if (self.mdl)
setmodel(self, self.mdl);
setorigin (self, self.origin);
sound (self, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM);
// Restore a goal if needed
tfgoalitem_checkgoalreturn(self);
//CH could it check origin again?? nah...
//CH a better question would be why does it need this to work right???
self.think = tfgoalitem_checkoriginagain;
self.nextthink = time + 1;
// Do we need to do any CenterPrint2ing?
if (self.noise3 || self.noise4)
{
te = find (NIL, classname, "player");
while (te)
{
if (te.team_no == self.owned_by)
CenterPrint2(te, "\n\n\n", self.noise3);
else // (te.team_no != self.owned_by)
CenterPrint2(te, "\n\n\n", self.noise4);
te = find(te, classname, "player");
}
}
return;
}
#ifdef MAP_DEBUG
RPrint("Removed.\n");
#endif
dremove(self);
};
//===================
//CH i wonder what this does?
//CH WHY THE HELL DOES IT NEED THIS!!!!!!!
//CH first check
void() tfgoalitem_checkoriginagain =
{
// RPrint("Check #1 for return goalitem\n");
if (self.origin != self.oldorigin && self.goal_state != TFGS_ACTIVE)
{
self.origin = self.oldorigin;
setorigin (self, self.origin);
self.think = tfgoalitem_checkoriginagain2;
self.nextthink = time + 1;
}
};
//===================
//CH second check
void() tfgoalitem_checkoriginagain2 =
{
// RPrint("Check #2 for return goalitem\n");
if (self.origin != self.oldorigin && self.goal_state != TFGS_ACTIVE)
{
self.origin = self.oldorigin;
setorigin (self, self.origin);
self.think = tfgoalitem_checkoriginagain3;
self.nextthink = time + 1;
}
};
//===================
//CH third and final check
void() tfgoalitem_checkoriginagain3 =
{
// RPrint("Check #3 for return goalitem\n");
if (self.origin != self.oldorigin && self.goal_state != TFGS_ACTIVE)
{
self.origin = self.oldorigin;
setorigin (self, self.origin);
}
};
//=========================================================================
// Activate a goal when this item is removed, if needed
void(entity Item) tfgoalitem_checkgoalreturn =
{
local entity te;
// Do we need to activate a goal somewhere?
if (Item.impulse != 0)
{
// Find the goal
te = Findgoal(Item.impulse);
if (te)
{
te = Findgoal(Item.impulse);
if (te)
AttemptToActivate(te, NIL, Item);
}
}
};
//=========================================================================
// Displays the state of a GoalItem
void(entity Goal, entity Player, entity Item) DisplayItemStatus =
{
if (Item.goal_state == TFGS_ACTIVE)
{
if (Player.team_no == Item.owned_by)
sprint(Player, PRINT_HIGH, Goal.team_str_carried);
else
sprint(Player, PRINT_HIGH, Goal.non_team_str_carried);
sprint(Player, PRINT_HIGH, " ");
if (Player == Item.owner)
sprint(Player, PRINT_HIGH, " You");
else
sprint(Player, PRINT_HIGH, Item.owner.netname);
sprint(Player, PRINT_HIGH, ".");
}
else if (Item.origin != Item.oldorigin)
{
if (Player.team_no == Item.owned_by)
sprint(Player, PRINT_HIGH, Goal.team_str_moved);
else
sprint(Player, PRINT_HIGH, Goal.non_team_str_moved);
}
else
{
if (Player.team_no == Item.owned_by)
sprint(Player, PRINT_HIGH, Goal.team_str_home);
else
sprint(Player, PRINT_HIGH, Goal.non_team_str_home);
}
/*CH prints out the origin and oldorigin via flaginfo
sprint(Player, PRINT_HIGH, "\n");
ac = vtos(Item.origin);
sprint(Player, PRINT_HIGH, ac);
sprint(Player, PRINT_HIGH, " ");
ac = vtos(Item.oldorigin);
sprint(Player, PRINT_HIGH, ac);
*/
sprint(Player, PRINT_HIGH, "\n");
};
//=========================================================================
// CTF SUPPORT
//=========================================================================
// Spawn Functions for CTF entities.
// Team 1 spawnpoints
void() info_player_team1 =
{
CTF_Map = TRUE;
// Convert to a TeamFortress TeamSpawn point
self.classname = "info_player_teamspawn";
// We swap them, so that the colors match ours
self.team_no = 2;
// Make this point remove itself after being spawned on
self.goal_effects = TFSP_REMOVESELF;
self.team_str_home = "ts2";
};
// Team 2 spawnpoints
void() info_player_team2 =
{
CTF_Map = TRUE;
// Convert to a TeamFortress TeamSpawn point
self.classname = "info_player_teamspawn";
// We swap them, so that the colors match ours
self.team_no = 1;
// Make this point remove itself after being spawned on
self.goal_effects = TFSP_REMOVESELF;
self.team_str_home = "ts1";
};
// Team 2 flag
void() item_flag_team2 =
{
local entity dp;
CTF_Map = TRUE;
precache_model ("progs/w_s_key.mdl");
precache_sound ("ogre/ogwake.wav");
precache_sound ("boss2/pop2.wav");
// Convert the flag to a TeamFortress Goal Item
self.classname = "item_tfgoal";
self.netname = "Team 1 Flag";
self.broadcast = " <20><><EFBFBD> the enemy team's flag!\n";
self.deathtype = "You've got the enemy flag!\n";
self.noise = "ogre/ogwake.wav";
self.mdl = "progs/tf_flag.mdl";
self.skin = 0;
setmodel (self, self.mdl);
self.goal_no = CTF_FLAG1;
self.goal_activation = TFGI_GLOW | TFGI_DROP | TFGI_REMOVE | TFGI_RETURN_REMOVE | TFGI_RETURN_GOAL | TFGI_ITEMGLOWS;
self.goal_effects = 1;
self.pausetime = 128;
setsize (self, '-16 -16 -24', '16 16 32');
self.touch = item_tfgoal_touch;
self.goal_state = TFGS_INACTIVE;
self.solid = SOLID_TRIGGER;
setorigin(self, self.origin);
self.nextthink = time + 0.2; // items start after other solids
self.think = TF_PlaceItem;
// Create the dropoff point Goal
dp = spawn();
dp.origin = self.origin;
dp.classname = "info_tfgoal";
dp.goal_activation = 1;
dp.team_no = 1;
dp.items_allowed = CTF_FLAG2;
dp.goal_no = CTF_DROPOFF1;
dp.goal_effects = 3;
dp.broadcast = " <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the enemy flag!\n";
dp.message = "You <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the enemy flag!\n";
dp.noise = "boss2/pop2.wav";
dp.goal_result = TFGR_ADD_BONUSES;
dp.activate_goal_no = CTF_SCORE1;
dp.axhitme = CTF_FLAG2;
dp.count = 10;
dp.frags = 0;
dp.solid = SOLID_TRIGGER;
dp.goal_state = TFGS_INACTIVE;
setsize (dp, '-16 -16 -24', '16 16 32');
dp.nextthink = time + 0.2; // goals start after other solids
dp.think = TF_PlaceGoal;
// Create the extra scoring goal
dp = spawn();
dp.origin = dp.origin;
dp.classname = "info_tfgoal";
dp.goal_effects = 1;
dp.frags = 5;
dp.goal_activation = 0;
dp.goal_no = CTF_SCORE1;
dp.solid = SOLID_NOT;
dp.goal_state = TFGS_INACTIVE;
setsize (dp, '-16 -16 -24', '16 16 32');
dp.nextthink = time + 0.2; // goals start after other solids
dp.think = TF_PlaceGoal;
};
// Team 1 flag
void() item_flag_team1 =
{
local entity dp;
CTF_Map = TRUE;
precache_model ("progs/tf_flag.mdl");
precache_sound ("ogre/ogwake.wav");
precache_sound ("boss2/pop2.wav");
// Convert the flag to a TeamFortress Goal Item
self.classname = "item_tfgoal";
self.netname = "Team 2 Flag";
self.broadcast = " <20><><EFBFBD> the enemy team's flag!\n";
self.deathtype = "You've got the enemy flag!\n";
self.noise = "ogre/ogwake.wav";
self.mdl = "progs/tf_flag.mdl";
setmodel (self, self.mdl);
self.skin = 1;
self.goal_no = CTF_FLAG2;
self.goal_activation = TFGI_GLOW | TFGI_DROP | TFGI_REMOVE | TFGI_RETURN_REMOVE | TFGI_RETURN_GOAL | TFGI_ITEMGLOWS;
self.goal_effects = 1;
self.pausetime = 128;
setsize (self, '-16 -16 -24', '16 16 32');
self.touch = item_tfgoal_touch;
self.goal_state = TFGS_INACTIVE;
self.solid = SOLID_TRIGGER;
setorigin(self, self.origin);
self.nextthink = time + 0.2; // items start after other solids
self.think = TF_PlaceItem;
// Create the dropoff point Goal
dp = spawn();
dp.origin = self.origin;
dp.classname = "info_tfgoal";
dp.goal_activation = 1;
dp.team_no = 2;
dp.items_allowed = CTF_FLAG1;
dp.goal_no = CTF_DROPOFF2;
dp.goal_effects = 3;
dp.broadcast = " <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the enemy flag!\n";
dp.message = "You <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the enemy flag!\n";
dp.noise = "boss2/pop2.wav";
dp.goal_result = TFGR_ADD_BONUSES;
dp.activate_goal_no = CTF_SCORE2;
dp.axhitme = CTF_FLAG1;
dp.count = 10;
dp.frags = 0;
dp.solid = SOLID_TRIGGER;
dp.goal_state = TFGS_INACTIVE;
setsize (dp, '-16 -16 -24', '16 16 32');
dp.nextthink = time + 0.2; // goals start after other solids
dp.think = TF_PlaceGoal;
// Create the extra scoring goal
dp = spawn();
dp.origin = dp.origin;
dp.classname = "info_tfgoal";
dp.goal_effects = 1;
dp.frags = 5;
dp.goal_activation = 0;
dp.goal_no = CTF_SCORE2;
dp.solid = SOLID_NOT;
dp.goal_state = TFGS_INACTIVE;
setsize (dp, '-16 -16 -24', '16 16 32');
dp.nextthink = time + 0.2; // goals start after other solids
dp.think = TF_PlaceGoal;
};
//=========================================================================
// Checks to make sure either flag hasn't got into bad state, and if
// it has, returns it.
void() CTF_FlagCheck =
{
local entity te;
local float flagcount, pos;
flagcount = 0;
te = find(NIL, classname, "item_tfgoal");
while (te)
{
if (te.goal_no == CTF_FLAG1)
{
pos = pointcontents(te.origin); // find the location of the Flag
if (pos == CONTENTS_SOLID || pos == CONTENTS_SKY)
{
RPrint("*****BUG*****\nFlag(s) outside world.\nPlease report this.\n");
te.nextthink = time + 0.2;
te.think = tfgoalitem_remove;
}
flagcount = flagcount + 1;
}
else if (te.goal_no == CTF_FLAG2)
{
pos = pointcontents(te.origin); // find the location of the Flag
if (pos == CONTENTS_SOLID || pos == CONTENTS_SKY)
{
RPrint("*****BUG*****\nFlag(s) outside world.\nPlease report this.\n");
te.nextthink = time + 0.2;
te.think = tfgoalitem_remove;
}
flagcount = flagcount + 1;
}
te = find(te, classname, "item_tfgoal");
}
if (flagcount != 2)
RPrint("*****BUG*****\nFlag(s) missing.\nPlease report this.\n");
self.nextthink = time + 30;
};