set g_ballistics_mindistance 2 // enable ballistics starting from 2 qu
set g_ballistics_density_player 0.50 // players are 2x as easy to pass as walls
set g_ballistics_density_corpse 0.10 // corpses are 10x as easy to pass as walls
+set g_ballistics_penetrate_clips 0 "allow ballistics to pass through weapon clips"
set cl_stripcolorcodes 0 "experimental feature (notes: strips ALL color codes from messages!)"
float autocvar_cl_hitsound_nom_damage = 25;
float autocvar_cl_hitsound_antispam_time;
int autocvar_cl_eventchase_death = 1;
-vector autocvar_cl_eventchase_generator_viewoffset = '0 0 80';
-float autocvar_cl_eventchase_generator_distance = 400;
float autocvar_cl_eventchase_distance = 140;
float autocvar_cl_eventchase_speed = 1.3;
vector autocvar_cl_eventchase_maxs = '12 12 8';
vector color = '0 0 0';
switch(i)
{
- case 0:
- stat = STAT(REDALIVE);
- pic = "player_red.tga";
- color = '1 0 0';
- break;
- case 1:
- stat = STAT(BLUEALIVE);
- pic = "player_blue.tga";
- color = '0 0 1';
- break;
- case 2:
- stat = STAT(YELLOWALIVE);
- pic = "player_yellow.tga";
- color = '1 1 0';
- break;
+ case 0: stat = STAT(REDALIVE); pic = "player_red"; color = '1 0 0'; break;
+ case 1: stat = STAT(BLUEALIVE); pic = "player_blue"; color = '0 0 1'; break;
+ case 2: stat = STAT(YELLOWALIVE); pic = "player_yellow"; color = '1 1 0'; break;
default:
- case 3:
- stat = STAT(PINKALIVE);
- pic = "player_pink.tga";
- color = '1 0 1';
- break;
+ case 3: stat = STAT(PINKALIVE); pic = "player_pink"; color = '1 0 1'; break;
}
if(mySize.x/mySize.y > aspect_ratio)
vector color = '0 0 0';
switch(i)
{
- case 0:
- stat = STAT(DOM_PPS_RED);
- pic = "dom_icon_red";
- color = '1 0 0';
- break;
- case 1:
- stat = STAT(DOM_PPS_BLUE);
- pic = "dom_icon_blue";
- color = '0 0 1';
- break;
- case 2:
- stat = STAT(DOM_PPS_YELLOW);
- pic = "dom_icon_yellow";
- color = '1 1 0';
- break;
+ case 0: stat = STAT(DOM_PPS_RED); pic = "dom_icon_red"; color = '1 0 0'; break;
+ case 1: stat = STAT(DOM_PPS_BLUE); pic = "dom_icon_blue"; color = '0 0 1'; break;
+ case 2: stat = STAT(DOM_PPS_YELLOW); pic = "dom_icon_yellow"; color = '1 1 0'; break;
default:
- case 3:
- stat = STAT(DOM_PPS_PINK);
- pic = "dom_icon_pink";
- color = '1 0 1';
- break;
+ case 3: stat = STAT(DOM_PPS_PINK); pic = "dom_icon_pink"; color = '1 0 1'; break;
}
- float pps_ratio = stat / STAT(DOM_TOTAL_PPS);
+ float pps_ratio = 0;
+ if(STAT(DOM_TOTAL_PPS))
+ pps_ratio = stat / STAT(DOM_TOTAL_PPS);
if(mySize.x/mySize.y > aspect_ratio)
{
/**/
MUTATOR_HOOKABLE(WantEventchase, EV_WantEventchase);
+/** allow customizing 3rd person mode effect */
+#define EV_CustomizeEventchase(i, o) \
+ /** entity id */ i(entity, MUTATOR_ARGV_0_entity) \
+ /* current_view_origin_override */ o(vector, MUTATOR_ARGV_0_vector) \
+ /* view_offset_override */ o(vector, MUTATOR_ARGV_1_vector) \
+ /* chase_distance_override */ o(float, MUTATOR_ARGV_0_float) \
+ /**/
+MUTATOR_HOOKABLE(CustomizeEventchase, EV_CustomizeEventchase);
+
#define EV_AnnouncerOption(i, o) \
/** announcer string */ i(string, MUTATOR_ARGV_0_string) \
/** announcer string */ o(string, MUTATOR_ARGV_0_string) \
cvar_set("chase_active", "0");
float vehicle_chase = (hud != HUD_NORMAL && (autocvar_cl_eventchase_vehicle || spectatee_status > 0));
- float ons_roundlost = (gametype == MAPINFO_TYPE_ONSLAUGHT && STAT(ROUNDLOST));
- entity gen = NULL;
float vehicle_viewdist = 0;
vector vehicle_viewofs = '0 0 0';
}
}
- if(ons_roundlost) // TODO: move this junk to a client mutator for onslaught (possible using the WantEventchase hook)
+ if(WantEventchase(this))
{
- IL_EACH(g_onsgenerators, it.health <= 0,
+ vector current_view_origin_override = '0 0 0';
+ vector view_offset_override = '0 0 0';
+ float chase_distance_override = 0;
+ bool custom_eventchase = MUTATOR_CALLHOOK(CustomizeEventchase, this);
+ if(custom_eventchase)
{
- gen = it;
- break;
- });
- if(!gen)
- ons_roundlost = false; // don't enforce the 3rd person camera if there is no dead generator to show
- }
- if(WantEventchase(this) || (!autocvar_cl_orthoview && ons_roundlost))
- {
+ current_view_origin_override = M_ARGV(0, vector);
+ view_offset_override = M_ARGV(1, vector);
+ chase_distance_override = M_ARGV(0, float);
+ }
eventchase_running = true;
entity local_player = ((csqcplayer) ? csqcplayer : CSQCModel_server2csqc(player_localentnum - 1));
// make special vector since we can't use view_origin (It is one frame old as of this code, it gets set later with the results this code makes.)
vector current_view_origin = (csqcplayer ? csqcplayer.origin : pmove_org);
- if(ons_roundlost) { current_view_origin = gen.origin; }
+ if (custom_eventchase)
+ current_view_origin = current_view_origin_override;
// detect maximum viewoffset and use it
vector view_offset = autocvar_cl_eventchase_viewoffset;
else
view_offset = autocvar_cl_eventchase_vehicle_viewoffset;
}
- if(ons_roundlost) { view_offset = autocvar_cl_eventchase_generator_viewoffset; }
+ if (custom_eventchase)
+ view_offset = view_offset_override;
if(view_offset)
{
else
chase_distance = autocvar_cl_eventchase_vehicle_distance;
}
- if(ons_roundlost) { chase_distance = autocvar_cl_eventchase_generator_distance; }
+ if (custom_eventchase)
+ chase_distance = chase_distance_override;
if(autocvar_cl_eventchase_speed && eventchase_current_distance < chase_distance)
eventchase_current_distance += autocvar_cl_eventchase_speed * (chase_distance - eventchase_current_distance) * frametime; // slow down the further we get
return MUT_ITEMTOUCH_CONTINUE;
}
-MUTATOR_HOOKFUNCTION(nb, GetTeamCount)
+MUTATOR_HOOKFUNCTION(nb, CheckAllowedTeams)
{
M_ARGV(1, string) = "nexball_team";
return true;
if(this.count > 10)
{
+ IL_REMOVE(g_drawables, this);
delete(this);
return;
}
this.classname = "onslaught_generator";
if(isnew)
+ {
IL_PUSH(g_onsgenerators, this);
+ IL_PUSH(g_drawables, this);
+ }
setorigin(this, this.origin);
setmodel(this, MDL_ONS_GEN);
#include "onslaught.qh"
+
+#ifdef CSQC
+
+REGISTER_MUTATOR(cl_ons, true);
+
+float ons_roundlost;
+vector generator_origin;
+vector autocvar_cl_eventchase_generator_viewoffset = '0 0 80';
+float autocvar_cl_eventchase_generator_distance = 400;
+MUTATOR_HOOKFUNCTION(cl_ons, WantEventchase)
+{
+ ons_roundlost = STAT(ROUNDLOST);
+ entity gen = NULL;
+ if(ons_roundlost)
+ {
+ IL_EACH(g_onsgenerators, it.health <= 0,
+ {
+ gen = it;
+ break;
+ });
+ if(!gen)
+ ons_roundlost = false; // don't enforce the 3rd person camera if there is no dead generator to show
+ }
+
+ if(ons_roundlost)
+ {
+ generator_origin = gen.origin;
+ return true;
+ }
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(cl_ons, CustomizeEventchase)
+{
+ if(ons_roundlost)
+ {
+ M_ARGV(0, vector) = generator_origin;
+ M_ARGV(1, vector) = autocvar_cl_eventchase_generator_viewoffset;
+ M_ARGV(0, float) = autocvar_cl_eventchase_generator_distance;
+ return true;
+ }
+ return false;
+}
+
+#endif
{
if (this.isshielded)
{
- // this is protected by a shield, so ignore the damage
+ // generator is protected by a shield, so ignore the damage
if (time > this.pain_finished)
if (IS_PLAYER(attacker))
{
return true;
}
-MUTATOR_HOOKFUNCTION(ons, GetTeamCount)
+MUTATOR_HOOKFUNCTION(ons, CheckAllowedTeams)
{
// onslaught is special
for(entity tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
void snake_hud_status(vector pos, vector mySize)
{
HUD_Panel_DrawBg();
- vector ts;
- ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
+ vector ts = minigame_drawstring_wrapped(mySize.x, pos, active_minigame.descriptor.message,
hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
- ts_y += hud_fontsize_y;
- pos_y += ts_y;
- mySize_y -= ts_y;
+ ts.y += hud_fontsize.y;
+ pos.y += ts.y;
+ mySize.y -= ts.y;
vector player_fontsize = hud_fontsize * 1.75;
- ts_y = ( mySize_y - SNAKE_TEAMS*player_fontsize_y ) / SNAKE_TEAMS;
- ts_x = mySize_x;
+ ts.y = player_fontsize.y + (mySize.y - SNAKE_TEAMS * player_fontsize.y) / SNAKE_TEAMS;
+ ts.x = mySize_x;
vector mypos;
entity e;
{
if ( e.classname == "minigame_player" )
{
- mypos = pos;
- mypos_y += (e.team-1) * (player_fontsize_y + ts_y);
+ mypos = pos + eY * (e.team - 1) * ts.y;
- drawfill(mypos, ts, snake_teamcolor(e.team), 0.25, DRAWFLAG_ADDITIVE);
+ if (e == minigame_self)
+ {
+ const vector hl_size = '1 1 0';
+ drawfill(mypos + hl_size, ts - 2 * hl_size, snake_teamcolor(e.team), 0.25 * panel_fg_alpha, DRAWFLAG_ADDITIVE);
+ drawborderlines(hl_size.x, mypos + hl_size, ts - 2 * hl_size, snake_teamcolor(e.team), panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ else
+ drawfill(mypos, ts, snake_teamcolor(e.team), 0.25 * panel_fg_alpha, DRAWFLAG_ADDITIVE);
- minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
- entcs_GetName(e.minigame_playerslot-1),
+ minigame_drawcolorcodedstring_trunc(mySize.x - hud_fontsize.x * 0.5, mypos + eX * hud_fontsize.x * 0.25,
+ entcs_GetName(e.minigame_playerslot - 1),
player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring(mypos+eY*player_fontsize_y,ftos(e.snake_score),'48 48 0' * (SNAKE_TEAMS * 0.1),
- '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring(mypos+(eY*player_fontsize_y) + (eX*player_fontsize_x),strcat("1UP: ", ftos(active_minigame.snake_lives[e.team])),'48 48 0' * (SNAKE_TEAMS * 0.1),
- '1 0.44 0.54', panel_fg_alpha, DRAWFLAG_NORMAL);
-
- if ( e == minigame_self )
- drawborderlines(1, mypos, ts, snake_teamcolor(e.team), 1, DRAWFLAG_NORMAL);
+ mypos.y += player_fontsize.y;
+ drawstring_aspect(mypos, ftos(e.snake_score), ts - eY * player_fontsize.y - eX * ts.x * (3 / 4),
+ '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(mypos + eX * ts.x * (1 / 4), strcat("1UP: ", ftos(active_minigame.snake_lives[e.team])), ts - eY * player_fontsize.y - eX * ts.x * (1 / 4),
+ '1 0.44 0.54', panel_fg_alpha, DRAWFLAG_NORMAL);
}
}
}
float autocvar_g_ballistics_density_corpse;
float autocvar_g_ballistics_density_player;
float autocvar_g_ballistics_mindistance;
+bool autocvar_g_ballistics_penetrate_clips;
float autocvar_g_ban_default_bantime;
float autocvar_g_ban_default_masksize;
float autocvar_g_ban_sync_interval;
/** called when the match ends */
MUTATOR_HOOKABLE(MatchEnd, EV_NO_ARGS);
-/** should adjust number to contain the team count */
-#define EV_GetTeamCount(i, o) \
- /** number of teams */ i(float, MUTATOR_ARGV_0_float) \
+/** allows adjusting allowed teams */
+#define EV_CheckAllowedTeams(i, o) \
+ /** mask of teams */ i(float, MUTATOR_ARGV_0_float) \
/**/ o(float, MUTATOR_ARGV_0_float) \
/** team entity name */ i(string, MUTATOR_ARGV_1_string) \
/**/ o(string, MUTATOR_ARGV_1_string) \
/**/
-MUTATOR_HOOKABLE(GetTeamCount, EV_GetTeamCount);
+MUTATOR_HOOKABLE(CheckAllowedTeams, EV_CheckAllowedTeams);
/** copies variables for spectating "spectatee" to "this" */
#define EV_SpectateCopy(i, o) \
return (frag_victim.classname == "func_assault_destructible");
}
-MUTATOR_HOOKFUNCTION(as, GetTeamCount)
+MUTATOR_HOOKFUNCTION(as, CheckAllowedTeams)
{
// assault always has 2 teams
c1 = c2 = 0;
return true;
}
-MUTATOR_HOOKFUNCTION(ca, GetTeamCount, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(ca, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
{
M_ARGV(0, float) = ca_teams;
}
return true;
}
-MUTATOR_HOOKFUNCTION(ctf, GetTeamCount)
+MUTATOR_HOOKFUNCTION(ctf, CheckAllowedTeams)
{
//M_ARGV(0, float) = ctf_teams;
M_ARGV(1, string) = "ctf_team";
}
}
-MUTATOR_HOOKFUNCTION(dom, GetTeamCount)
+MUTATOR_HOOKFUNCTION(dom, CheckAllowedTeams)
{
// fallback?
M_ARGV(0, float) = domination_teams;
return true;
}
-MUTATOR_HOOKFUNCTION(ft, GetTeamCount, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(ft, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
{
M_ARGV(0, float) = freezetag_teams;
}
return true;
}
-MUTATOR_HOOKFUNCTION(inv, GetTeamCount, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(inv, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
{
M_ARGV(0, float) = invasion_teams;
}
const vector KH_KEY_MAX = '10 10 3';
const float KH_KEY_BRIGHTNESS = 2;
-float kh_no_radar_circles;
+bool kh_no_radar_circles;
// kh_state
// bits 0- 4: team of key 1, or 0 for no such key, or 30 for dropped, or 31 for self
float kh_key_dropped, kh_key_carried;
+int kh_Key_AllOwnedByWhichTeam();
+
const float ST_KH_CAPS = 1;
void kh_ScoreRules(int teams)
{
}
// -1 when no team completely owns all keys yet
-float kh_Key_AllOwnedByWhichTeam() // constantly called. check to see if all the keys are owned by the same team
+int kh_Key_AllOwnedByWhichTeam() // constantly called. check to see if all the keys are owned by the same team
{
entity key;
- float teem;
- float keys;
-
- teem = -1;
- keys = NumTeams(kh_teams);
+ int teem = -1;
+ int keys = NumTeams(kh_teams);
FOR_EACH_KH_KEY(key)
{
if(!key.owner)
}
}
-float kh_CheckPlayers(float num)
+int kh_GetMissingTeams()
{
- if(num < NumTeams(kh_teams))
+ int missing_teams = 0;
+ for(int i = 0; i < NumTeams(kh_teams); ++i)
{
- float t_team = kh_Team_ByID(num);
- float players = 0;
+ int teem = kh_Team_ByID(i);
+ int players = 0;
FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
- if(!IS_DEAD(it) && !PHYS_INPUT_BUTTON_CHAT(it) && it.team == t_team)
+ if(!IS_DEAD(it) && !PHYS_INPUT_BUTTON_CHAT(it) && it.team == teem)
++players;
));
-
- if (!players) { return t_team; }
+ if (!players)
+ missing_teams |= pow(2, i);
}
- return 0;
+ return missing_teams;
}
-#define KH_READY_TEAMS() (!p1 + !p2 + ((NumTeams(kh_teams) >= 3) ? !p3 : p3) + ((NumTeams(kh_teams) >= 4) ? !p4 : p4))
-#define KH_READY_TEAMS_OK() (KH_READY_TEAMS() == NumTeams(kh_teams))
void kh_WaitForPlayers() // delay start of the round until enough players are present
{
if(time < game_starttime)
return;
}
- static float prev_missing_teams_mask;
- float p1 = kh_CheckPlayers(0), p2 = kh_CheckPlayers(1), p3 = kh_CheckPlayers(2), p4 = kh_CheckPlayers(3);
- if(KH_READY_TEAMS_OK())
+ static int prev_missing_teams_mask;
+ int missing_teams_mask = kh_GetMissingTeams();
+ if(!missing_teams_mask)
{
if(prev_missing_teams_mask > 0)
Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
}
else
{
- int missing_teams_mask = 0;
- if(kh_teams & BIT(0))
- missing_teams_mask += boolean(p1) * 1;
- if(kh_teams & BIT(1))
- missing_teams_mask += boolean(p2) * 2;
- if(kh_teams & BIT(2))
- missing_teams_mask += boolean(p3) * 4;
- if(kh_teams & BIT(3))
- missing_teams_mask += boolean(p4) * 8;
if(prev_missing_teams_mask != missing_teams_mask)
{
Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
void kh_StartRound() // runs at the start of each round
{
- float i, players, teem;
+ int i, players, teem;
if(time < game_starttime)
{
return;
}
- float p1 = kh_CheckPlayers(0), p2 = kh_CheckPlayers(1), p3 = kh_CheckPlayers(2), p4 = kh_CheckPlayers(3);
- if(!KH_READY_TEAMS_OK())
+ if(kh_GetMissingTeams())
{
kh_Controller_SetThink(1, kh_WaitForPlayers);
return;
kh_finalize();
}
-MUTATOR_HOOKFUNCTION(kh, GetTeamCount, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(kh, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
{
M_ARGV(0, float) = kh_teams;
}
// ALL OF THESE should be removed in the future, as other code should not have to care
// used by bots:
-float kh_tracking_enabled;
+bool kh_tracking_enabled;
.entity kh_next;
-float kh_Key_AllOwnedByWhichTeam();
USING(kh_Think_t, void());
void kh_StartRound();
return true; // in qualifying, you don't lose score by observing
}
-MUTATOR_HOOKFUNCTION(rc, GetTeamCount, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(rc, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
{
M_ARGV(0, float) = race_teams;
}
}
}
-MUTATOR_HOOKFUNCTION(tdm, GetTeamCount, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(tdm, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
{
M_ARGV(1, string) = "tdm_team";
return true;
// set c1...c4 to show what teams are allowed
void CheckAllowedTeams (entity for_whom)
{
- int dm = 0;
+ int teams_mask = 0;
c1 = c2 = c3 = c4 = -1;
cb1 = cb2 = cb3 = cb4 = 0;
string teament_name = string_null;
- bool mutator_returnvalue = MUTATOR_CALLHOOK(GetTeamCount, dm, teament_name);
- dm = M_ARGV(0, float);
+ bool mutator_returnvalue = MUTATOR_CALLHOOK(CheckAllowedTeams, teams_mask, teament_name);
+ teams_mask = M_ARGV(0, float);
teament_name = M_ARGV(1, string);
if(!mutator_returnvalue)
{
- if(dm & BIT(0)) c1 = 0;
- if(dm & BIT(1)) c2 = 0;
- if(dm & BIT(2)) c3 = 0;
- if(dm & BIT(3)) c4 = 0;
+ if(teams_mask & BIT(0)) c1 = 0;
+ if(teams_mask & BIT(1)) c2 = 0;
+ if(teams_mask & BIT(2)) c3 = 0;
+ if(teams_mask & BIT(3)) c4 = 0;
}
// find out what teams are allowed if necessary
}
}
- if (is_weapclip)
+ if (is_weapclip && !autocvar_g_ballistics_penetrate_clips)
break;
// go through solid!