mirror of
https://git.code.sf.net/p/quake/prozac-qfcc
synced 2024-11-13 00:24:33 +00:00
8c2d5fdd12
should get frags for blowing people up with others' dispensers/mines/expbody, airfisting rockets, etc. 2) Redid Give_Frags_Out 3) Changed many uses of pointcontents and ugly hacks to use hullpointcontents and checkmove, now a lot cleaner and less buggy 4) You can grapple builds again. This caused really odd bugs. 5) You can now damage your own buildings again (gasp). Any time a tesla or sentry is damaged it turns on its attacker, friendly or otherwise. This is both a counter-TK and counter-spy mechanism. 6) Teslas are now entirely inside their bounding box 7) Now check every frame for players startsolid and for outside of the map cube. 8) #define WALL_HURT to make it hurt when you hit a wall 9) Used some cool ideas (aka laws of physics) to make the airfist a little less annoying 10) You now only get 1 mirv per slot without bandolier. Demoman and hwguy gain bandolier. demoman loses his extra mirv but gains an extra grenade and pair of detpacks. Hwguy gets extra grenade. 11) New and improved EMP grenade now does damage based on range. no longer blows up shells. Doesn't directly damage sentries anymore, but does significant damage to dispensers. EMP someone who's setting a det and it blows up in their face. 12) Players now do radius damage from getting EMPed (again) 13) EMPs now go through walls (again) 14) EMP number lowered by one (3 without, 4 with bandolier) and cost raised by $100 15) You can only have 2 frag grens, 3 with bandolier now. 16) Hover boots will now eat cells if they get low on charge. In addition, the silly bug where their charge wasn't restored when you die is fixed now. 17) EMPing a detpack now sets its timer to anywhere between 1 and 121 seconds from current time, with a logarithmic probability of it being lower. (random() * random() * 120 + 1). Also, probably more time the closer it is to the EMP. 18) Judo can now be blocked by people with close combat, knife or judo. Blocked judo means that the attacker loses 3 seconds of attack. 19) Judo missing now makes them unable to fire. 20) Shortened judo range (back to normal if w/ close combat) 21) Attempted to rework the railgun. Seems to be okay now. Probably still a lot of bugs in here, but since this is the devel version I thought I would commit all my changes so people could start testing it. I'll commit fixes as soon as I find the bugs.
3632 lines
84 KiB
C++
3632 lines
84 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;
|
||
}
|
||
};
|
||
|
||
// Place the Goal Item
|
||
void() TF_PlaceItem =
|
||
{
|
||
local vector temp1;
|
||
local vector temp2;
|
||
|
||
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_DIMLIGHT;
|
||
|
||
// 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 =
|
||
{
|
||
UpdateAbbreviations(self);
|
||
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 (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 =
|
||
{
|
||
UpdateAbbreviations(self);
|
||
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;
|
||
}
|
||
|
||
// 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;
|
||
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 - (Goal.armorclass & AT_SAVEMELEE);
|
||
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.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;
|
||
|
||
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_DIMLIGHT;
|
||
if (Item.goal_activation & TFGI_SLOW)
|
||
TeamFortress_SetSpeed(AP);
|
||
|
||
if (Item.goal_activation & TFGI_ITEMGLOWS)
|
||
Item.effects = Item.effects - (Item.effects | EF_DIMLIGHT);
|
||
|
||
// 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 lighton, 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
|
||
|
||
lighton = FALSE;
|
||
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
|
||
te = find (NIL, classname, "item_tfgoal");
|
||
while (te)
|
||
{
|
||
if ((te.owner == AP) && (te != Item))
|
||
{
|
||
if (te.goal_activation & TFGI_GLOW)
|
||
lighton = TRUE;
|
||
if (te.goal_activation & TFGI_SLOW)
|
||
slowon = TRUE;
|
||
|
||
if (te.items & IT_KEY1)
|
||
key1on = TRUE;
|
||
if (te.items & IT_KEY2)
|
||
key2on = TRUE;
|
||
|
||
if (te.goal_result & TFGR_REMOVE_DISGUISE)
|
||
spyoff = 1;
|
||
}
|
||
te = find(te, classname, "item_tfgoal");
|
||
}
|
||
|
||
// Check Powerups too
|
||
if (!lighton)
|
||
{
|
||
if (AP.invincible_finished > time + 3)
|
||
lighton = TRUE;
|
||
}
|
||
|
||
if (!lighton)
|
||
AP.effects = AP.effects - (AP.effects & EF_DIMLIGHT);
|
||
|
||
if (Item.goal_activation & TFGI_ITEMGLOWS)
|
||
Item.effects = Item.effects | EF_DIMLIGHT;
|
||
|
||
// 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.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);
|
||
}
|
||
else
|
||
{
|
||
// Remove the Item
|
||
Item.owner = NIL;
|
||
dremove(Item);
|
||
TeamFortress_SetSpeed(AP);
|
||
return;
|
||
}
|
||
Item.owner = NIL;
|
||
TeamFortress_SetSpeed(AP);
|
||
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);
|
||
return;
|
||
}
|
||
|
||
// Don't remove it, since it may be given away again later
|
||
Item.solid = SOLID_NOT;
|
||
Item.owner = NIL;
|
||
TeamFortress_SetSpeed(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 - '0 0 8';
|
||
|
||
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.goal_result & TFGR_DROPITEMS) //checks for dropitems
|
||
{
|
||
Item.nextthink = time + 1; //CH wait a sec then make it pickupable
|
||
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;
|
||
}
|
||
};
|
||
|
||
//CH brings the item online after 1 sec
|
||
void() tfgoalitem_settouchandthink =
|
||
{
|
||
self.nextthink = time + 4.0; // 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;
|
||
};
|
||
|
||
//=========================================================================
|
||
// 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;
|
||
};
|