mirror of
https://git.code.sf.net/p/quake/prozac-qfcc
synced 2024-11-14 00:40:32 +00:00
3682 lines
85 KiB
C++
3682 lines
85 KiB
C++
#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;
|
||
};
|