-// ================================================================
-// Official capture the flag game mode coding, reworked by Samual
-// Last updated: September, 2012
-// ================================================================
+#include "gamemode_ctf.qh"
+#include "../_all.qh"
+
+#include "gamemode.qh"
+
+#ifdef SVQC
+#include "../../common/vehicles/sv_vehicles.qh"
+#endif
+
+#include "../../warpzonelib/common.qh"
+#include "../../warpzonelib/mathlib.qh"
void ctf_FakeTimeLimit(entity e, float t)
{
WriteCoord(MSG_ONE, (t + 1) / 60);
}
-void ctf_EventLog(string mode, float flagteam, entity actor) // use an alias for easy changing and quick editing later
+void ctf_EventLog(string mode, int flagteam, entity actor) // use an alias for easy changing and quick editing later
{
if(autocvar_sv_eventlog)
GameLogEcho(sprintf(":ctf:%s:%d:%d:%s", mode, flagteam, actor.team, ((actor != world) ? ftos(actor.playerid) : "")));
void ctf_FlagcarrierWaypoints(entity player)
{
- WaypointSprite_Spawn("flagcarrier", 0, 0, player, FLAG_WAYPOINT_OFFSET, world, player.team, player, wps_flagcarrier, TRUE, RADARICON_FLAG, WPCOLOR_FLAGCARRIER(player.team));
+ WaypointSprite_Spawn("flagcarrier", 0, 0, player, FLAG_WAYPOINT_OFFSET, world, player.team, player, wps_flagcarrier, true, RADARICON_FLAG, WPCOLOR_FLAGCARRIER(player.team));
WaypointSprite_UpdateMaxHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON) * 2);
WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON));
WaypointSprite_UpdateTeamRadar(player.wps_flagcarrier, RADARICON_FLAGCARRIER, WPCOLOR_FLAGCARRIER(player.team));
void ctf_CalculatePassVelocity(entity flag, vector to, vector from, float turnrate)
{
- float current_distance = vlen((('1 0 0' * to_x) + ('0 1 0' * to_y)) - (('1 0 0' * from_x) + ('0 1 0' * from_y))); // for the sake of this check, exclude Z axis
+ float current_distance = vlen((('1 0 0' * to.x) + ('0 1 0' * to.y)) - (('1 0 0' * from.x) + ('0 1 0' * from.y))); // for the sake of this check, exclude Z axis
float initial_height = min(autocvar_g_ctf_pass_arc_max, (flag.pass_distance * tanh(autocvar_g_ctf_pass_arc)));
float current_height = (initial_height * min(1, (current_distance / flag.pass_distance)));
//print("current_height = ", ftos(current_height), ", initial_height = ", ftos(initial_height), ".\n");
else { flag.velocity = (desired_direction * autocvar_g_ctf_pass_velocity); }
}
-float ctf_CheckPassDirection(vector head_center, vector passer_center, vector passer_angle, vector nearest_to_passer)
+bool ctf_CheckPassDirection(vector head_center, vector passer_center, vector passer_angle, vector nearest_to_passer)
{
if(autocvar_g_ctf_pass_directional_max || autocvar_g_ctf_pass_directional_min)
{
makevectors(passer_angle);
// find the closest point on the enemy to the center of the attack
- float ang; // angle between shotdir and h
float h; // hypotenuse, which is the distance between attacker to head
float a; // adjacent side, which is the distance between attacker and the point on w_shotdir that is closest to head.origin
h = vlen(head_center - passer_center);
- ang = acos(dotproduct(normalize(head_center - passer_center), v_forward));
- a = h * cos(ang);
+ a = h * (normalize(head_center - passer_center) * v_forward);
vector nearest_on_line = (passer_center + a * v_forward);
float distance_from_line = vlen(nearest_to_passer - nearest_on_line);
spreadlimit = (autocvar_g_ctf_pass_directional_min * (1 - spreadlimit) + autocvar_g_ctf_pass_directional_max * spreadlimit);
if(spreadlimit && (distance_from_line <= spreadlimit) && ((vlen(normalize(head_center - passer_center) - v_forward) * RAD2DEG) <= 90))
- { return TRUE; }
+ { return true; }
else
- { return FALSE; }
+ { return false; }
}
- else { return TRUE; }
+ else { return true; }
}
// CaptureShield Functions
// =======================
-float ctf_CaptureShield_CheckStatus(entity p)
+bool ctf_CaptureShield_CheckStatus(entity p)
{
- float s, s2, s3, s4, se, se2, se3, se4, sr, ser;
+ int s, s2, s3, s4, se, se2, se3, se4, sr, ser;
entity e;
- float players_worseeq, players_total;
+ int players_worseeq, players_total;
if(ctf_captureshield_max_ratio <= 0)
- return FALSE;
+ return false;
s = PlayerScore_Add(p, SP_CTF_CAPS, 0);
s2 = PlayerScore_Add(p, SP_CTF_PICKUPS, 0);
sr = ((s - s2) + (s3 + s4));
if(sr >= -ctf_captureshield_min_negscore)
- return FALSE;
+ return false;
players_total = players_worseeq = 0;
FOR_EACH_PLAYER(e)
// use this rule here
if(players_worseeq >= players_total * ctf_captureshield_max_ratio)
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
-void ctf_CaptureShield_Update(entity player, float wanted_status)
+void ctf_CaptureShield_Update(entity player, bool wanted_status)
{
- float updated_status = ctf_CaptureShield_CheckStatus(player);
+ bool updated_status = ctf_CaptureShield_CheckStatus(player);
if((wanted_status == player.ctf_captureshielded) && (updated_status != wanted_status)) // 0: shield only, 1: unshield only
{
Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((updated_status) ? CENTER_CTF_CAPTURESHIELD_SHIELDED : CENTER_CTF_CAPTURESHIELD_FREE));
}
}
-float ctf_CaptureShield_Customize()
+bool ctf_CaptureShield_Customize()
{
- if(self.enemy.active != ACTIVE_ACTIVE) { return TRUE; }
- if(!other.ctf_captureshielded) { return FALSE; }
- if(CTF_SAMETEAM(self, other)) { return FALSE; }
+ if(!other.ctf_captureshielded) { return false; }
+ if(CTF_SAMETEAM(self, other)) { return false; }
- return TRUE;
+ return true;
}
void ctf_CaptureShield_Touch()
{
- if(self.enemy.active != ACTIVE_ACTIVE)
- {
- vector mymid = (self.absmin + self.absmax) * 0.5;
- vector othermid = (other.absmin + other.absmax) * 0.5;
-
- Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * ctf_captureshield_force);
- if(IS_REAL_CLIENT(other)) { Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_INACTIVE); }
-
- return;
- }
-
if(!other.ctf_captureshielded) { return; }
if(CTF_SAMETEAM(self, other)) { return; }
// Drop/Pass/Throw Code
// ====================
-void ctf_Handle_Drop(entity flag, entity player, float droptype)
+void ctf_Handle_Drop(entity flag, entity player, int droptype)
{
// declarations
player = (player ? player : flag.pass_sender);
// waypoints
if(autocvar_g_ctf_flag_dropped_waypoint)
- WaypointSprite_Spawn("flagdropped", 0, 0, flag, FLAG_WAYPOINT_OFFSET, world, ((autocvar_g_ctf_flag_dropped_waypoint == 2) ? 0 : player.team), flag, wps_flagdropped, TRUE, RADARICON_FLAG, WPCOLOR_DROPPEDFLAG(flag.team));
+ WaypointSprite_Spawn("flagdropped", 0, 0, flag, FLAG_WAYPOINT_OFFSET, world, ((autocvar_g_ctf_flag_dropped_waypoint == 2) ? 0 : player.team), flag, wps_flagdropped, true, RADARICON_FLAG, WPCOLOR_DROPPEDFLAG(flag.team));
if(autocvar_g_ctf_flag_return_time || (autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health))
{
flag.pass_target = world;
}
-void ctf_Handle_Throw(entity player, entity receiver, float droptype)
+void ctf_Handle_Throw(entity player, entity receiver, int droptype)
{
entity flag = player.flagcarried;
vector targ_origin, flag_velocity;
WarpZone_RefSys_AddInverse(flag, receiver); // wz1^-1 ... wzn^-1 receiver
targ_origin = WarpZone_RefSys_TransformOrigin(receiver, flag, (0.5 * (receiver.absmin + receiver.absmax))); // this is target origin as seen by the flag
- flag.pass_distance = vlen((('1 0 0' * targ_origin_x) + ('0 1 0' * targ_origin_y)) - (('1 0 0' * player.origin_x) + ('0 1 0' * player.origin_y))); // for the sake of this check, exclude Z axis
- ctf_CalculatePassVelocity(flag, targ_origin, player.origin, FALSE);
+ flag.pass_distance = vlen((('1 0 0' * targ_origin.x) + ('0 1 0' * targ_origin.y)) - (('1 0 0' * player.origin.x) + ('0 1 0' * player.origin.y))); // for the sake of this check, exclude Z axis
+ ctf_CalculatePassVelocity(flag, targ_origin, player.origin, false);
// main
flag.movetype = MOVETYPE_FLY;
case DROP_THROW:
{
- makevectors((player.v_angle_y * '0 1 0') + (bound(autocvar_g_ctf_throw_angle_min, player.v_angle_x, autocvar_g_ctf_throw_angle_max) * '1 0 0'));
+ makevectors((player.v_angle.y * '0 1 0') + (bound(autocvar_g_ctf_throw_angle_min, player.v_angle.x, autocvar_g_ctf_throw_angle_max) * '1 0 0'));
- flag_velocity = (('0 0 1' * autocvar_g_ctf_throw_velocity_up) + ((v_forward * autocvar_g_ctf_throw_velocity_forward) * ((player.items & IT_STRENGTH) ? autocvar_g_ctf_throw_strengthmultiplier : 1)));
- flag.velocity = W_CalculateProjectileVelocity(player.velocity, flag_velocity, FALSE);
+ flag_velocity = (('0 0 1' * autocvar_g_ctf_throw_velocity_up) + ((v_forward * autocvar_g_ctf_throw_velocity_forward) * ((player.items & ITEM_Strength.m_itemid) ? autocvar_g_ctf_throw_strengthmultiplier : 1)));
+ flag.velocity = W_CalculateProjectileVelocity(player.velocity, flag_velocity, false);
ctf_Handle_Drop(flag, player, droptype);
break;
}
default:
case DROP_NORMAL:
{
- flag.velocity = W_CalculateProjectileVelocity(player.velocity, (('0 0 1' * autocvar_g_ctf_drop_velocity_up) + ((('0 1 0' * crandom()) + ('1 0 0' * crandom())) * autocvar_g_ctf_drop_velocity_side)), FALSE);
+ flag.velocity = W_CalculateProjectileVelocity(player.velocity, (('0 0 1' * autocvar_g_ctf_drop_velocity_up) + ((('0 1 0' * crandom()) + ('1 0 0' * crandom())) * autocvar_g_ctf_drop_velocity_side)), false);
ctf_Handle_Drop(flag, player, droptype);
break;
}
// Event Handlers
// ==============
-void ctf_Handle_Capture(entity flag, entity toucher, float capturetype)
+void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
{
entity enemy_flag = ((capturetype == CAPTURE_NORMAL) ? toucher.flagcarried : toucher);
entity player = ((capturetype == CAPTURE_NORMAL) ? toucher : enemy_flag.ctf_dropper);
PlayerScore_Add(player, SP_CTF_CAPTIME, new_time - old_time);
// effects
- pointparticles(particleeffectnum(flag.capeffect), flag.origin, '0 0 0', 1);
+ Send_Effect(flag.capeffect, flag.origin, '0 0 0', 1);
//shockwave_spawn("models/ctf/shockwavetransring.md3", flag.origin - '0 0 15', -0.8, 0, 1);
// other
void ctf_Handle_Return(entity flag, entity player)
{
// messages and sounds
- if(player.flags & FL_MONSTER)
+ if(IS_MONSTER(player))
{
Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(flag, INFO_CTF_RETURN_MONSTER_), player.monster_name);
}
ctf_RespawnFlag(flag);
}
-void ctf_Handle_Pickup(entity flag, entity player, float pickuptype)
+void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
{
// declarations
float pickup_dropped_score; // used to calculate dropped pickup score
}
// effects
- pointparticles(particleeffectnum(flag.toucheffect), player.origin, '0 0 0', 1);
+ Send_Effect(flag.toucheffect, player.origin, '0 0 0', 1);
// waypoints
if(pickuptype == PICKUP_DROPPED) { WaypointSprite_Kill(flag.wps_flagdropped); }
// Main Flag Functions
// ===================
-void ctf_CheckFlagReturn(entity flag, float returntype)
+void ctf_CheckFlagReturn(entity flag, int returntype)
{
if((flag.ctf_status == FLAG_DROPPED) || (flag.ctf_status == FLAG_PASSING))
{
}
}
-float ctf_Stalemate_Customize()
+bool ctf_Stalemate_Customize()
{
// make spectators see what the player would see
entity e, wp_owner;
wp_owner = self.owner;
// team waypoints
- if(CTF_SAMETEAM(wp_owner.flagcarried, wp_owner)) { return FALSE; }
- if(SAME_TEAM(wp_owner, e)) { return FALSE; }
- if(!IS_PLAYER(e)) { return FALSE; }
+ if(CTF_SAMETEAM(wp_owner.flagcarried, wp_owner)) { return false; }
+ if(SAME_TEAM(wp_owner, e)) { return false; }
+ if(!IS_PLAYER(e)) { return false; }
- return TRUE;
+ return true;
}
void ctf_CheckStalemate(void)
{
// declarations
- float stale_flags = 0, stale_red_flags = 0, stale_blue_flags = 0, stale_yellow_flags = 0, stale_pink_flags = 0, stale_neutral_flags = 0;
+ int stale_flags = 0, stale_red_flags = 0, stale_blue_flags = 0, stale_yellow_flags = 0, stale_pink_flags = 0, stale_neutral_flags = 0;
entity tmp_entity;
entity ctf_staleflaglist = world; // reset the list, we need to build the list each time this function runs
stale_flags = (stale_red_flags >= 1) + (stale_blue_flags >= 1) + (stale_yellow_flags >= 1) + (stale_pink_flags >= 1);
if(ctf_oneflag && stale_flags == 1)
- ctf_stalemate = TRUE;
- else if(stale_flags == ctf_teams)
- ctf_stalemate = TRUE;
+ ctf_stalemate = true;
+ else if(stale_flags >= 2)
+ ctf_stalemate = true;
else if(stale_flags == 0 && autocvar_g_ctf_stalemate_endcondition == 2)
- { ctf_stalemate = FALSE; wpforenemy_announced = FALSE; }
- else if(stale_flags < ctf_teams && autocvar_g_ctf_stalemate_endcondition == 1)
- { ctf_stalemate = FALSE; wpforenemy_announced = FALSE; }
+ { ctf_stalemate = false; wpforenemy_announced = false; }
+ else if(stale_flags < 2 && autocvar_g_ctf_stalemate_endcondition == 1)
+ { ctf_stalemate = false; wpforenemy_announced = false; }
// if sufficient stalemate, then set up the waypointsprite and announce the stalemate if necessary
if(ctf_stalemate)
{
if((tmp_entity.owner) && (!tmp_entity.owner.wps_enemyflagcarrier))
{
- WaypointSprite_Spawn(((ctf_oneflag) ? "flagcarrier" : "enemyflagcarrier"), 0, 0, tmp_entity.owner, FLAG_WAYPOINT_OFFSET, world, 0, tmp_entity.owner, wps_enemyflagcarrier, TRUE, RADARICON_FLAG, WPCOLOR_ENEMYFC(tmp_entity.owner.team));
+ WaypointSprite_Spawn(((ctf_oneflag) ? "flagcarrier" : "enemyflagcarrier"), 0, 0, tmp_entity.owner, FLAG_WAYPOINT_OFFSET, world, 0, tmp_entity.owner, wps_enemyflagcarrier, true, RADARICON_FLAG, WPCOLOR_ENEMYFC(tmp_entity.owner.team));
tmp_entity.owner.wps_enemyflagcarrier.customizeentityforclient = ctf_Stalemate_Customize;
}
}
FOR_EACH_REALPLAYER(tmp_entity)
Send_Notification(NOTIF_ONE, tmp_entity, MSG_CENTER, ((tmp_entity.flagcarried) ? CENTER_CTF_STALEMATE_CARRIER : CENTER_CTF_STALEMATE_OTHER));
- wpforenemy_announced = TRUE;
+ wpforenemy_announced = true;
}
}
}
-void ctf_FlagDamage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void ctf_FlagDamage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
if(ITEM_DAMAGE_NEEDKILL(deathtype))
{
if(autocvar_g_ctf_flag_return_damage_delay)
{
- self.ctf_flagdamaged = TRUE;
+ self.ctf_flagdamaged = true;
}
else
{
else
{
// still a viable target, go for it
- ctf_CalculatePassVelocity(self, targ_origin, self.origin, TRUE);
+ ctf_CalculatePassVelocity(self, targ_origin, self.origin, true);
}
return;
}
void ctf_FlagTouch()
{
if(gameover) { return; }
- if(self.active != ACTIVE_ACTIVE) { return; }
if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; }
entity toucher = other, tmp_entity;
- float is_not_monster = (!(toucher.flags & FL_MONSTER)), num_perteam = 0;
+ bool is_not_monster = (!IS_MONSTER(toucher)), num_perteam = 0;
// automatically kill the flag and return it if it touched lava/slime/nodrop surfaces
if(ITEM_TOUCH_NEEDKILL())
// special touch behaviors
if(toucher.frozen) { return; }
- else if(toucher.vehicle_flags & VHF_ISVEHICLE)
+ else if(IS_VEHICLE(toucher))
{
if(autocvar_g_ctf_allow_vehicle_touch && toucher.owner)
toucher = toucher.owner; // the player is actually the vehicle owner, not other
else
return; // do nothing
}
- else if(toucher.flags & FL_MONSTER)
+ else if(IS_MONSTER(toucher))
{
if(!autocvar_g_ctf_allow_monster_touch)
return; // do nothing
{
if(time > self.wait) // if we haven't in a while, play a sound/effect
{
- pointparticles(particleeffectnum(self.toucheffect), self.origin, '0 0 0', 1);
+ Send_Effect(self.toucheffect, self.origin, '0 0 0', 1);
sound(self, CH_TRIGGER, self.snd_flag_touch, VOL_BASE, ATTEN_NORM);
self.wait = time + FLAG_TOUCHRATE;
}
ctf_RespawnFlag(self);
}
-void ctf_Use()
-{
- if(self.ctf_status != FLAG_BASE) { return; }
-
- self.active = ((self.active) ? ACTIVE_NOT : ACTIVE_ACTIVE);
-
- if(self.active == ACTIVE_ACTIVE)
- WaypointSprite_Ping(self.wps_flagbase);
-}
-
-float ctf_FlagWaypoint_Customize()
-{
- if(self.owner.active != ACTIVE_ACTIVE) { return FALSE; }
- return TRUE;
-}
-
void ctf_DelayedFlagSetup(void) // called after a flag is placed on a map by ctf_FlagSetup()
{
// bot waypoints
}
WaypointSprite_SpawnFixed(basename, self.origin + FLAG_WAYPOINT_OFFSET, self, wps_flagbase, RADARICON_FLAG, ((self.team) ? Team_ColorRGB(self.team) : '1 1 1'));
- WaypointSprite_UpdateTeamRadar(self.wps_flagbase, RADARICON_FLAG, ((self.team) ? colormapPaletteColor(self.team - 1, FALSE) : '1 1 1'));
- self.wps_flagbase.customizeentityforclient = ctf_FlagWaypoint_Customize;
+ WaypointSprite_UpdateTeamRadar(self.wps_flagbase, RADARICON_FLAG, ((self.team) ? colormapPaletteColor(self.team - 1, false) : '1 1 1'));
// captureshield setup
ctf_CaptureShield_Spawn(self);
}
-void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
+void set_flag_string(entity flag, .string field, string value, string teamname)
+{
+ if(flag.field == "")
+ flag.field = strzone(sprintf(value,teamname));
+}
+
+void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
{
// declarations
+ string teamname = Static_Team_ColorName_Lower(teamnumber);
self = flag; // for later usage with droptofloor()
// main setup
flag.max_flag_health = ((autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health) ? autocvar_g_ctf_flag_health : 100);
flag.health = flag.max_flag_health;
flag.event_damage = ctf_FlagDamage;
- flag.pushable = TRUE;
+ flag.pushable = true;
flag.teleportable = TELEPORT_NORMAL;
flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
flag.damagedbytriggers = autocvar_g_ctf_flag_return_when_unreachable;
flag.velocity = '0 0 0';
flag.mangle = flag.angles;
flag.reset = ctf_Reset;
- flag.use = ctf_Use;
flag.touch = ctf_FlagTouch;
flag.think = ctf_FlagThink;
flag.nextthink = time + FLAG_THINKRATE;
flag.ctf_status = FLAG_BASE;
// appearence
- if(flag.model == "") { flag.model = ((teamnumber == NUM_TEAM_1) ? autocvar_g_ctf_flag_red_model : ((teamnumber == NUM_TEAM_2) ? autocvar_g_ctf_flag_blue_model : ((teamnumber == NUM_TEAM_3) ? autocvar_g_ctf_flag_yellow_model : ((teamnumber == NUM_TEAM_4) ? autocvar_g_ctf_flag_pink_model : autocvar_g_ctf_flag_neutral_model)))); }
- if(!flag.scale) { flag.scale = FLAG_SCALE; }
- if(!flag.skin) { flag.skin = ((teamnumber == NUM_TEAM_1) ? autocvar_g_ctf_flag_red_skin : ((teamnumber == NUM_TEAM_2) ? autocvar_g_ctf_flag_blue_skin : ((teamnumber == NUM_TEAM_3) ? autocvar_g_ctf_flag_yellow_skin : ((teamnumber == NUM_TEAM_4) ? autocvar_g_ctf_flag_pink_skin : autocvar_g_ctf_flag_neutral_skin)))); }
- if(flag.toucheffect == "") { flag.toucheffect = ((teamnumber == NUM_TEAM_1) ? "redflag_touch" : ((teamnumber == NUM_TEAM_2) ? "blueflag_touch" : ((teamnumber == NUM_TEAM_3) ? "yellowflag_touch" : ((teamnumber == NUM_TEAM_4) ? "pinkflag_touch" : "neutralflag_touch")))); }
- if(flag.passeffect == "") { flag.passeffect = ((teamnumber == NUM_TEAM_1) ? "red_pass" : ((teamnumber == NUM_TEAM_2) ? "blue_pass" : ((teamnumber == NUM_TEAM_3) ? "yellow_pass" : ((teamnumber == NUM_TEAM_4) ? "pink_pass" : "neutral_pass")))); }
- if(flag.capeffect == "") { flag.capeffect = ((teamnumber == NUM_TEAM_1) ? "red_cap" : ((teamnumber == NUM_TEAM_2) ? "blue_cap" : ((teamnumber == NUM_TEAM_3) ? "yellow_cap" : ((teamnumber == NUM_TEAM_4) ? "pink_cap" : "")))); } // neutral flag cant be capped itself
- if(!flag.active) { flag.active = ACTIVE_ACTIVE; }
-
- // sound
- if(flag.snd_flag_taken == "") { flag.snd_flag_taken = ((teamnumber == NUM_TEAM_1) ? "ctf/red_taken.wav" : ((teamnumber == NUM_TEAM_2) ? "ctf/blue_taken.wav" : ((teamnumber == NUM_TEAM_3) ? "ctf/yellow_taken.wav" : ((teamnumber == NUM_TEAM_4) ? "ctf/pink_taken.wav" : "ctf/neutral_taken.wav")))); }
- if(flag.snd_flag_returned == "") { flag.snd_flag_returned = ((teamnumber == NUM_TEAM_1) ? "ctf/red_returned.wav" : ((teamnumber == NUM_TEAM_2) ? "ctf/blue_returned.wav" : ((teamnumber == NUM_TEAM_3) ? "ctf/yellow_returned.wav" : ((teamnumber == NUM_TEAM_4) ? "ctf/pink_returned.wav" : "")))); } // neutral flag can't be returned by players
- if(flag.snd_flag_capture == "") { flag.snd_flag_capture = ((teamnumber == NUM_TEAM_1) ? "ctf/red_capture.wav" : ((teamnumber == NUM_TEAM_2) ? "ctf/blue_capture.wav" : ((teamnumber == NUM_TEAM_3) ? "ctf/yellow_capture.wav" : ((teamnumber == NUM_TEAM_4) ? "ctf/pink_capture.wav" : "")))); } // again can't be captured
- if(flag.snd_flag_respawn == "") { flag.snd_flag_respawn = "ctf/flag_respawn.wav"; } // if there is ever a team-based sound for this, update the code to match.
- if(flag.snd_flag_dropped == "") { flag.snd_flag_dropped = ((teamnumber == NUM_TEAM_1) ? "ctf/red_dropped.wav" : ((teamnumber == NUM_TEAM_2) ? "ctf/blue_dropped.wav" : ((teamnumber == NUM_TEAM_3) ? "ctf/yellow_dropped.wav" : ((teamnumber == NUM_TEAM_4) ? "ctf/pink_dropped.wav" : "ctf/neutral_dropped.wav")))); }
- if(flag.snd_flag_touch == "") { flag.snd_flag_touch = "ctf/touch.wav"; } // again has no team-based sound
- if(flag.snd_flag_pass == "") { flag.snd_flag_pass = "ctf/pass.wav"; } // same story here
+ if(!flag.scale) { flag.scale = FLAG_SCALE; }
+ if(flag.skin == 0) { flag.skin = cvar(sprintf("g_ctf_flag_%s_skin", teamname)); }
+ if(flag.model == "") { flag.model = cvar_string(sprintf("g_ctf_flag_%s_model", teamname)); }
+ set_flag_string(flag, toucheffect, "%sflag_touch", teamname);
+ set_flag_string(flag, passeffect, "%s_pass", teamname);
+ set_flag_string(flag, capeffect, "%s_cap", teamname);
+
+ // sounds
+ set_flag_string(flag, snd_flag_taken, "ctf/%s_taken.wav", teamname);
+ set_flag_string(flag, snd_flag_returned, "ctf/%s_returned.wav", teamname);
+ set_flag_string(flag, snd_flag_capture, "ctf/%s_capture.wav", teamname);
+ set_flag_string(flag, snd_flag_dropped, "ctf/%s_dropped.wav", teamname);
+ if(flag.snd_flag_respawn == "") { flag.snd_flag_respawn = "ctf/flag_respawn.wav"; } // if there is ever a team-based sound for this, update the code to match.
+ if(flag.snd_flag_touch == "") { flag.snd_flag_touch = "ctf/touch.wav"; } // again has no team-based sound
+ if(flag.snd_flag_pass == "") { flag.snd_flag_pass = "ctf/pass.wav"; } // same story here
// precache
precache_sound(flag.snd_flag_taken);
if(autocvar_g_ctf_flag_glowtrails)
{
- flag.glow_color = ((teamnumber == NUM_TEAM_1) ? 251 : ((teamnumber == NUM_TEAM_2) ? 210 : ((teamnumber == NUM_TEAM_3) ? 110 : ((teamnumber == NUM_TEAM_4) ? 145 : 254))));
+ switch(teamnumber)
+ {
+ case NUM_TEAM_1: flag.glow_color = 251; break;
+ case NUM_TEAM_2: flag.glow_color = 210; break;
+ case NUM_TEAM_3: flag.glow_color = 110; break;
+ case NUM_TEAM_4: flag.glow_color = 145; break;
+ default: flag.glow_color = 254; break;
+ }
flag.glow_size = 25;
flag.glow_trail = 1;
}
case NUM_TEAM_2: flag.effects |= EF_BLUE; break;
case NUM_TEAM_3: flag.effects |= EF_DIMLIGHT; break;
case NUM_TEAM_4: flag.effects |= EF_RED; break;
- default: flag.effects |= EF_DIMLIGHT; break;
+ default: flag.effects |= EF_DIMLIGHT; break;
}
}
if((flag.spawnflags & 1) || flag.noalign) // don't drop to floor, just stay at fixed location
{
flag.dropped_origin = flag.origin;
- flag.noalign = TRUE;
+ flag.noalign = true;
flag.movetype = MOVETYPE_NONE;
}
else // drop to floor, automatically find a platform and set that as spawn origin
{
- flag.noalign = FALSE;
+ flag.noalign = false;
self = flag;
droptofloor();
flag.movetype = MOVETYPE_TOSS;
return world;
}
-float havocbot_ctf_teamcount(entity bot, vector org, float tc_radius)
+int havocbot_ctf_teamcount(entity bot, vector org, float tc_radius)
{
if (!teamplay)
return 0;
- float c = 0;
+ int c = 0;
entity head;
FOR_EACH_PLAYER(head)
{
entity head;
float t;
- head = findchainfloat(bot_pickup, TRUE);
+ head = findchainfloat(bot_pickup, true);
while (head)
{
// gather health and armor only
vector org;
org = havocbot_ctf_middlepoint;
- org_z = self.origin_z;
+ org.z = self.origin.z;
self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start();
}
}
-void havocbot_role_ctf_setrole(entity bot, float role)
+void havocbot_role_ctf_setrole(entity bot, int role)
{
dprint(strcat(bot.netname," switched to "));
switch(role)
MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink)
{
entity flag;
-
- float t = 0, t2 = 0, t3 = 0;
+ int t = 0, t2 = 0, t3 = 0;
// initially clear items so they can be set as necessary later.
self.ctf_flagstatus &= ~(CTF_RED_FLAG_CARRYING | CTF_RED_FLAG_TAKEN | CTF_RED_FLAG_LOST
if(self.wps_flagcarrier)
WaypointSprite_UpdateHealth(self.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(self.health, self.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON));
- return FALSE;
+ return false;
}
MUTATOR_HOOKFUNCTION(ctf_PlayerDamage) // for changing damage and force values that are applied to players in g_damage.qc
}
// todo: add notification for when flag carrier needs help?
}
- return FALSE;
+ return false;
}
MUTATOR_HOOKFUNCTION(ctf_PlayerDies)
tmp_entity.ctf_dropper = world;
}
- return FALSE;
+ return false;
}
MUTATOR_HOOKFUNCTION(ctf_GiveFragsForKill)
if(flag.ctf_dropper == self) { flag.ctf_dropper = world; }
}
- return FALSE;
+ return false;
}
MUTATOR_HOOKFUNCTION(ctf_PortalTeleport)
if(!autocvar_g_ctf_portalteleport)
{ ctf_Handle_Throw(self, world, DROP_NORMAL); }
- return FALSE;
+ return false;
}
MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey)
{
- if(MUTATOR_RETURNVALUE || gameover) { return FALSE; }
+ if(MUTATOR_RETURNVALUE || gameover) { return false; }
entity player = self;
if(autocvar_g_ctf_pass)
{
entity head, closest_target = world;
- head = WarpZone_FindRadius(player.origin, autocvar_g_ctf_pass_radius, TRUE);
+ head = WarpZone_FindRadius(player.origin, autocvar_g_ctf_pass_radius, true);
while(head) // find the closest acceptable target to pass to
{
Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
}
player.throw_antispam = time + autocvar_g_ctf_pass_wait;
- return TRUE;
+ return true;
}
else if(player.flagcarried)
{
head = head.chain;
}
- if(closest_target) { ctf_Handle_Throw(player, closest_target, DROP_PASS); return TRUE; }
+ if(closest_target) { ctf_Handle_Throw(player, closest_target, DROP_PASS); return true; }
}
// throw the flag in front of you
player.throw_prevtime = time;
player.throw_count = 1;
ctf_Handle_Throw(player, world, DROP_THROW);
- return TRUE;
+ return true;
}
else
{
Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_FLAG_THROW_PUNISH, rint((player.throw_prevtime + autocvar_g_ctf_throw_punish_delay) - time));
- return FALSE;
+ return false;
}
}
else
player.throw_prevtime = time;
ctf_Handle_Throw(player, world, DROP_THROW);
- return TRUE;
+ return true;
}
}
}
- return FALSE;
+ return false;
}
MUTATOR_HOOKFUNCTION(ctf_HelpMePing)
}
else // create a normal help me waypointsprite
{
- WaypointSprite_Spawn("helpme", waypointsprite_deployed_lifetime, waypointsprite_limitedrange, self, FLAG_WAYPOINT_OFFSET, world, self.team, self, wps_helpme, FALSE, RADARICON_HELPME, '1 0.5 0');
+ WaypointSprite_Spawn("helpme", waypointsprite_deployed_lifetime, waypointsprite_limitedrange, self, FLAG_WAYPOINT_OFFSET, world, self.team, self, wps_helpme, false, RADARICON_HELPME, '1 0.5 0');
WaypointSprite_Ping(self.wps_helpme);
}
- return TRUE;
+ return true;
}
MUTATOR_HOOKFUNCTION(ctf_VehicleEnter)
{
if(vh_player.flagcarried)
{
+ vh_player.flagcarried.nodrawtoclient = vh_player; // hide the flag from the driver
+
if(!autocvar_g_ctf_allow_vehicle_carry && !autocvar_g_ctf_allow_vehicle_touch)
{
ctf_Handle_Throw(vh_player, world, DROP_NORMAL);
vh_player.flagcarried.scale = VEHICLE_FLAG_SCALE;
//vh_player.flagcarried.angles = '0 0 0';
}
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
MUTATOR_HOOKFUNCTION(ctf_VehicleExit)
setorigin(vh_player.flagcarried, FLAG_CARRY_OFFSET);
vh_player.flagcarried.scale = FLAG_SCALE;
vh_player.flagcarried.angles = '0 0 0';
- return TRUE;
+ vh_player.flagcarried.nodrawtoclient = world;
+ return true;
}
- return FALSE;
+ return false;
}
MUTATOR_HOOKFUNCTION(ctf_AbortSpeedrun)
{
Send_Notification(NOTIF_ALL, world, MSG_INFO, ((self.flagcarried.team) ? APP_TEAM_ENT_4(self.flagcarried, INFO_CTF_FLAGRETURN_ABORTRUN_) : INFO_CTF_FLAGRETURN_ABORTRUN_NEUTRAL));
ctf_RespawnFlag(self.flagcarried);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
MUTATOR_HOOKFUNCTION(ctf_MatchEnd)
flag.movetype = MOVETYPE_NONE;
flag.takedamage = DAMAGE_NO;
flag.solid = SOLID_NOT;
- flag.nextthink = FALSE; // stop thinking
+ flag.nextthink = false; // stop thinking
//dprint("stopping the ", flag.netname, " from moving.\n");
break;
}
}
- return FALSE;
+ return false;
}
MUTATOR_HOOKFUNCTION(ctf_BotRoles)
{
havocbot_ctf_reset_role(self);
- return TRUE;
+ return true;
}
MUTATOR_HOOKFUNCTION(ctf_GetTeamCount)
{
//ret_float = ctf_teams;
ret_string = "ctf_team";
- return TRUE;
+ return true;
}
MUTATOR_HOOKFUNCTION(ctf_SpectateCopy)
{
self.ctf_flagstatus = other.ctf_flagstatus;
- return FALSE;
+ return false;
}
void spawnfunc_team_CTF_redspawn() { spawnfunc_info_player_team1(); }
void spawnfunc_team_CTF_bluespawn() { spawnfunc_info_player_team2(); }
+void team_CTF_neutralflag() { spawnfunc_item_flag_neutral(); }
+void team_neutralobelisk() { spawnfunc_item_flag_neutral(); }
+
// ==============
// Initialization
// ==============
// scoreboard setup
-void ctf_ScoreRules(float teams)
+void ctf_ScoreRules(int teams)
{
CheckAllowedTeams(world);
- ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, TRUE);
+ ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
ScoreInfo_SetLabel_TeamScore (ST_CTF_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
ScoreInfo_SetLabel_PlayerScore(SP_CTF_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
ScoreInfo_SetLabel_PlayerScore(SP_CTF_CAPTIME, "captime", SFL_LOWER_IS_BETTER | SFL_TIME);
}
// code from here on is just to support maps that don't have flag and team entities
-void ctf_SpawnTeam (string teamname, float teamcolor)
+void ctf_SpawnTeam (string teamname, int teamcolor)
{
entity oldself;
oldself = self;
{
if(tmp_entity.team == NUM_TEAM_3) { ctf_teams = max(3, ctf_teams); }
if(tmp_entity.team == NUM_TEAM_4) { ctf_teams = max(4, ctf_teams); }
- if(tmp_entity.team == 0) { ctf_oneflag = TRUE; }
+ if(tmp_entity.team == 0) { ctf_oneflag = true; }
}
ctf_teams = bound(2, ctf_teams, 4);