- wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints
- wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache
- make
- - EXPECT=c2ae476e90317feda0756669a21ce1e7
+ - EXPECT=538cd6a692f22150ac60d9902eddc75b
- HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
| tee /dev/stderr
| grep '^:'
set g_balance_shotgun_secondary_alt_refire 1.2
set g_balance_shotgun_switchdelay_drop 0.2
set g_balance_shotgun_switchdelay_raise 0.2
-set g_balance_shotgun_weaponreplace "shockwave"
-set g_balance_shotgun_weaponstart 0
+set g_balance_shotgun_weaponreplace ""
+set g_balance_shotgun_weaponstart 1
set g_balance_shotgun_weaponstartoverride -1
set g_balance_shotgun_weaponthrowable 1
// }}}
set g_balance_crylink_secondary_animtime 0.2
set g_balance_crylink_secondary_bouncedamagefactor 0.5
set g_balance_crylink_secondary_bounces 0
-set g_balance_crylink_secondary_damage 50
-set g_balance_crylink_secondary_edgedamage 15
-set g_balance_crylink_secondary_force -400
+set g_balance_crylink_secondary_damage 10
+set g_balance_crylink_secondary_edgedamage 5
+set g_balance_crylink_secondary_force -200
set g_balance_crylink_secondary_joindelay 0
set g_balance_crylink_secondary_joinexplode 0
set g_balance_crylink_secondary_joinexplode_damage 0
set g_balance_crylink_secondary_joinexplode_force 0
set g_balance_crylink_secondary_joinexplode_radius 0
set g_balance_crylink_secondary_joinspread 0
-set g_balance_crylink_secondary_linkexplode 1
+set g_balance_crylink_secondary_linkexplode 0
set g_balance_crylink_secondary_middle_fadetime 5
set g_balance_crylink_secondary_middle_lifetime 5
-set g_balance_crylink_secondary_other_fadetime 5
-set g_balance_crylink_secondary_other_lifetime 5
-set g_balance_crylink_secondary_radius 70
-set g_balance_crylink_secondary_refire 0.8
-set g_balance_crylink_secondary_shots 1
-set g_balance_crylink_secondary_speed 3000
-set g_balance_crylink_secondary_spread 0
-set g_balance_crylink_secondary_spreadtype 1
+set g_balance_crylink_secondary_other_fadetime 2
+set g_balance_crylink_secondary_other_lifetime 2
+set g_balance_crylink_secondary_radius 100
+set g_balance_crylink_secondary_refire 0.65
+set g_balance_crylink_secondary_shots 5
+set g_balance_crylink_secondary_speed 7000
+set g_balance_crylink_secondary_spread 0.08
+set g_balance_crylink_secondary_spreadtype 0
set g_balance_crylink_switchdelay_drop 0.2
set g_balance_crylink_switchdelay_raise 0.2
set g_balance_crylink_weaponreplace ""
set g_balance_shockwave_switchdelay_drop 0.2
set g_balance_shockwave_switchdelay_raise 0.2
set g_balance_shockwave_weaponreplace ""
-set g_balance_shockwave_weaponstart 1
+set g_balance_shockwave_weaponstart 0
set g_balance_shockwave_weaponstartoverride -1
set g_balance_shockwave_weaponthrowable 0
// }}}
set g_balance_arc_burst_heat 5
set g_balance_arc_beam_maxangle 10
set g_balance_arc_beam_nonplayerdamage 80
-set g_balance_arc_beam_range 1250
+set g_balance_arc_beam_range 1500
set g_balance_arc_beam_refire 0.25
set g_balance_arc_beam_returnspeed 8
-set g_balance_arc_beam_tightness 0.5
+set g_balance_arc_beam_tightness 0.6
set g_balance_arc_bolt 1
set g_balance_arc_bolt_ammo 1
set g_balance_arc_bolt_damage 25
set g_balance_okmachinegun_primary_damage 25
set g_balance_okmachinegun_primary_force 5
set g_balance_okmachinegun_primary_refire 0.1
-set g_balance_okmachinegun_primary_solidpenetration 13.1
+set g_balance_okmachinegun_primary_solidpenetration 63
set g_balance_okmachinegun_primary_spread_add 0.012
set g_balance_okmachinegun_primary_spread_max 0.05
set g_balance_okmachinegun_primary_spread_min 0
MUTATOR_CALLHOOK(DrawInfoMessages, pos, mySize);
- if(!warmup_stage && gametype == MAPINFO_TYPE_LMS)
+ if(!warmup_stage && ISGAMETYPE(LMS))
{
entity sk;
sk = playerslots[player_localnum];
mod_active = 1; // required in each mod function that always shows something
int layout;
- if(gametype == MAPINFO_TYPE_CA)
+ if(ISGAMETYPE(CA))
layout = autocvar_hud_panel_modicons_ca_layout;
- else //if(gametype == MAPINFO_TYPE_FREEZETAG)
+ else //if(ISGAMETYPE(FREEZETAG))
layout = autocvar_hud_panel_modicons_freezetag_layout;
int rows, columns;
float aspect_ratio;
// clientside personal record
string rr;
- if(gametype == MAPINFO_TYPE_CTS)
+ if(ISGAMETYPE(CTS))
rr = CTS_RECORD;
else
rr = RACE_RECORD;
{
if(!autocvar_hud_panel_physics) return;
if(spectatee_status == -1 && (autocvar_hud_panel_physics == 1 || autocvar_hud_panel_physics == 3)) return;
- if(autocvar_hud_panel_physics == 3 && !(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
+ if(autocvar_hud_panel_physics == 3 && !(ISGAMETYPE(RACE) || ISGAMETYPE(CTS))) return;
}
HUD_Panel_LoadCvars();
if(!autocvar__hud_configure)
{
if(!autocvar_hud_panel_racetimer) return;
- if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
+ if(!(ISGAMETYPE(RACE) || ISGAMETYPE(CTS))) return;
if(spectatee_status == -1) return;
}
IL_EACH(g_radaricons, it.teamradar_icon, {
if ( hud_panel_radar_mouse )
if ( GetResourceAmount(it, RESOURCE_HEALTH) >= 0 )
- if ( it.team == myteam + 1 || gametype == MAPINFO_TYPE_RACE || !teamplay )
+ if ( it.team == myteam + 1 || ISGAMETYPE(RACE) || !teamplay )
{
vector coord = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(it.origin));
if(vdist((mousepos - coord), <, 8))
if(!autocvar__hud_configure)
{
if(!autocvar_hud_panel_score) return;
- if(spectatee_status == -1 && (gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
+ if(spectatee_status == -1 && (ISGAMETYPE(RACE) || ISGAMETYPE(CTS))) return;
}
HUD_Panel_LoadCvars();
return true;
else if (intermission == 2)
return false;
- else if (spectatee_status != -1 && STAT(HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS && !active_minigame)
+ else if (spectatee_status != -1 && STAT(HEALTH) <= 0 && autocvar_cl_deathscoreboard && !ISGAMETYPE(CTS) && !active_minigame)
return true;
else if (scoreboard_showscores_force)
return true;
vector hl_rgb = rgb + '0.5 0.5 0.5';
pos.y += hud_fontsize.y;
- drawstring(pos + eX * panel_bg_padding, ((gametype == MAPINFO_TYPE_CTF) ? _("Capture time rankings") : _("Rankings")), hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring(pos + eX * panel_bg_padding, ((ISGAMETYPE(CTF)) ? _("Capture time rankings") : _("Rankings")), hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
pos.y += 1.25 * hud_fontsize.y;
if(panel.current_panel_bg != "0")
pos.y += panel_bg_border;
bool have_weapon_stats;
bool Scoreboard_AccuracyStats_WouldDraw(float ypos)
{
- if (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_NEXBALL)
+ if (ISGAMETYPE(CTS) || ISGAMETYPE(RACE) || ISGAMETYPE(NEXBALL))
return false;
if (!autocvar_hud_panel_scoreboard_accuracy || warmup_stage || ypos > 0.91 * vid_conheight)
return false;
if (Scoreboard_AccuracyStats_WouldDraw(pos.y))
pos = Scoreboard_AccuracyStats_Draw(pos, panel_bg_color, bg_size);
- if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (autocvar_hud_panel_scoreboard_ctf_leaderboard && gametype == MAPINFO_TYPE_CTF && STAT(CTF_SHOWLEADERBOARD))) {
+ if(ISGAMETYPE(CTS) || ISGAMETYPE(RACE) || (autocvar_hud_panel_scoreboard_ctf_leaderboard && ISGAMETYPE(CTF) && STAT(CTF_SHOWLEADERBOARD))) {
if(race_speedaward) {
drawcolorcodedstring(pos, sprintf(_("Speed award: %d%s ^7(%s^7)"), race_speedaward, race_speedaward_unit, ColorTranslateRGB(race_speedaward_holder)), hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
pos.y += 1.25 * hud_fontsize.y;
tl = STAT(TIMELIMIT);
fl = STAT(FRAGLIMIT);
ll = STAT(LEADLIMIT);
- if(gametype == MAPINFO_TYPE_LMS)
+ if(ISGAMETYPE(LMS))
{
if(tl > 0)
str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
void HUD_Vote()
{
- if(autocvar_cl_allow_uid2name == -1 && (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (serverflags & SERVERFLAG_PLAYERSTATS)))
+ if(autocvar_cl_allow_uid2name == -1 && (ISGAMETYPE(CTS) || ISGAMETYPE(RACE) || (serverflags & SERVERFLAG_PLAYERSTATS)))
{
// this dialog gets overriden by the uid2name menu dialog, if it exists
// TODO remove this client side uid2name dialog in the next release
bool postinit;
entity gametype;
+// temporary hack
+#define ISGAMETYPE(NAME) (gametype == MAPINFO_TYPE_##NAME)
float FONT_USER = 8;
// FIXME: alpha is negative when dead, breaking death fade
if (!this.csqcmodel_isdead) a *= f;
}
- if (a < ALPHA_MIN_VISIBLE && gametype != MAPINFO_TYPE_CTS) return;
+ if (a < ALPHA_MIN_VISIBLE && ISGAMETYPE(CTS)) return;
if (vdist(this.origin - view_origin, >=, max_shot_distance)) return;
float dist = vlen(this.origin - view_origin);
if (autocvar_hud_shownames_maxdistance)
if(autocvar_r_letterbox == 0)
if(autocvar_viewsize < 120)
{
- if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS))
+ if(!(ISGAMETYPE(RACE) || ISGAMETYPE(CTS)))
Accuracy_LoadLevels();
HUD_Main();
else if(cvar("r_glsl_postprocess") == 2)
cvar_set("r_glsl_postprocess", "0");
- /*if(gametype == MAPINFO_TYPE_CTF)
+ /*if(ISGAMETYPE(CTF))
{
ctf_view();
} else */
void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_items;
void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
+// assault game mode: Which team is attacking in this round?
+float assault_attacker_team;
+
// predefined spawnfuncs
void target_objective_decrease_activate(entity this);
MUTATOR_HOOKFUNCTION(cl_nb, WantEventchase)
{
- if(autocvar_cl_eventchase_nexball && gametype == MAPINFO_TYPE_NEXBALL && !(WepSet_GetFromStat() & WEPSET(NEXBALL)))
+ if(autocvar_cl_eventchase_nexball && ISGAMETYPE(NEXBALL) && !(WepSet_GetFromStat() & WEPSET(NEXBALL)))
return true;
return false;
}
string _MapInfo_GetDefault(Gametype t)
{
- switch(t)
- {
- case MAPINFO_TYPE_DEATHMATCH: return "30 20 0";
- case MAPINFO_TYPE_TEAM_DEATHMATCH: return "50 20 2 0";
- case MAPINFO_TYPE_DOMINATION: return "200 20 0";
- case MAPINFO_TYPE_CTF: return "300 20 10 0";
- case MAPINFO_TYPE_LMS: return "9 20 0";
- case MAPINFO_TYPE_CA: return "10 20 0";
- case MAPINFO_TYPE_KEYHUNT: return "1000 20 3 0";
- case MAPINFO_TYPE_ASSAULT: return "20 0";
- case MAPINFO_TYPE_RACE: return "20 5 7 15 0";
- case MAPINFO_TYPE_ONSLAUGHT: return "20 0";
- case MAPINFO_TYPE_NEXBALL: return "5 20 0";
- case MAPINFO_TYPE_CTS: return "20 0 0";
- case MAPINFO_TYPE_FREEZETAG: return "10 20 0";
- // NOTE: DO NOT ADD ANY MORE GAME TYPES HERE
- // THIS IS JUST LEGACY SUPPORT FOR NEXUIZ MAPS
- // ONLY ADD NEW STUFF TO _MapInfo_GetDefaultEx
- // THIS FUNCTION WILL EVENTUALLY BE REMOVED
- default: return "";
- }
+ return t.m_legacydefaults;
}
void _MapInfo_Map_ApplyGametype(string s, Gametype pWantedType, Gametype pThisType, int load_default)
if(load_default)
_MapInfo_Map_ApplyGametype(_MapInfo_GetDefault(pThisType), pWantedType, pThisType, false);
- if(pWantedType == MAPINFO_TYPE_ASSAULT || pWantedType == MAPINFO_TYPE_ONSLAUGHT || pWantedType == MAPINFO_TYPE_RACE || pWantedType == MAPINFO_TYPE_CTS) // these modes don't use fraglimit
+ if(!pWantedType.frags) // these modes don't use fraglimit
{
cvar_set("fraglimit", "0");
}
// rc = timelimit timelimit_qualification laps laps_teamplay
if(pWantedType == MAPINFO_TYPE_RACE)
{
+ cvar_set("fraglimit", "0"); // special case!
+
sa = car(s); if(sa == "") sa = cvar_string("timelimit");
cvar_set("g_race_qualifying_timelimit", sa);
s = cdr(s);
s = cdr(s);
}
- if(pWantedType == MAPINFO_TYPE_ASSAULT || pWantedType == MAPINFO_TYPE_ONSLAUGHT || pWantedType == MAPINFO_TYPE_CTS) // these modes don't use fraglimit
+ if(!pWantedType.frags) // these modes don't use fraglimit
{
cvar_set("leadlimit", "0");
}
ATTRIB(Gametype, message, string);
/** does this gametype support teamplay? */
ATTRIB(Gametype, team, bool, false);
+ /** does this gametype use a point limit? */
+ ATTRIB(Gametype, frags, bool, true);
/** game type defaults */
ATTRIB(Gametype, model2, string);
/** game type description */
ATTRIB(Gametype, m_modicons_reset, void());
#endif
+ /** DO NOT USE, this is compatibility for legacy maps! */
+ ATTRIB(Gametype, m_legacydefaults, string, "");
+
ATTRIB(Gametype, m_mutators, string);
METHOD(Gametype, m_parse_mapinfo, bool(string k, string v))
{
{
return false;
}
+ METHOD(Gametype, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Frag limit:"), 5, 100, 5, "fraglimit_override", string_null, _("The amount of frags needed before the match will end"));
+ }
METHOD(Gametype, describe, string(Gametype this))
{
returns(this.message, strcat("gametype_", this.mdl));
}
- METHOD(Gametype, gametype_init, void(Gametype this, string hname, string sname, string g_name, bool gteamplay, string mutators, string defaults, string gdescription))
+ METHOD(Gametype, gametype_init, void(Gametype this, string hname, string sname, string g_name, bool gteamplay, bool gusepoints, string mutators, string defaults, string gdescription))
{
this.netname = g_name;
this.mdl = sname;
this.m_mutators = cons(sname, mutators);
this.model2 = defaults;
this.gametype_description = gdescription;
+ this.frags = gusepoints;
// same as `1 << m_id`
MAPINFO_TYPE_ALL |= this.items = this.m_flags = (MAPINFO_TYPE_ALL + 1);
CLASS(Deathmatch, Gametype)
INIT(Deathmatch)
{
- this.gametype_init(this, _("Deathmatch"),"dm","g_dm",false,"","timelimit=15 pointlimit=30 leadlimit=0",_("Score as many frags as you can"));
+ this.gametype_init(this, _("Deathmatch"),"dm","g_dm",false,true,"","timelimit=15 pointlimit=30 leadlimit=0",_("Score as many frags as you can"));
}
METHOD(Deathmatch, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
{
return true;
}
+ ATTRIB(Deathmatch, m_legacydefaults, string, "30 20 0");
ENDCLASS(Deathmatch)
REGISTER_GAMETYPE(DEATHMATCH, NEW(Deathmatch));
CLASS(LastManStanding, Gametype)
INIT(LastManStanding)
{
- this.gametype_init(this, _("Last Man Standing"),"lms","g_lms",false,"","timelimit=20 lives=9 leadlimit=0",_("Survive and kill until the enemies have no lives left"));
+ this.gametype_init(this, _("Last Man Standing"),"lms","g_lms",false,true,"","timelimit=20 lives=9 leadlimit=0",_("Survive and kill until the enemies have no lives left"));
}
METHOD(LastManStanding, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
{
return true;
}
+ METHOD(LastManStanding, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Lives:"), 3, 50, 1, "g_lms_lives_override", string_null, string_null);
+ }
+ ATTRIB(LastManStanding, m_legacydefaults, string, "9 20 0");
ENDCLASS(LastManStanding)
REGISTER_GAMETYPE(LMS, NEW(LastManStanding));
CLASS(Race, Gametype)
INIT(Race)
{
- this.gametype_init(this, _("Race"),"rc","g_race",false,"","timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0",_("Race against other players to the finish line"));
+ this.gametype_init(this, _("Race"),"rc","g_race",false,true,"","timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0",_("Race against other players to the finish line"));
}
METHOD(Race, m_parse_mapinfo, bool(string k, string v))
{
{
return true;
}
+ METHOD(Race, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Laps:"), 1, 25, 1, "g_race_laps_limit", string_null, string_null);
+ }
#ifdef CSQC
ATTRIB(Race, m_modicons, void(vector pos, vector mySize), HUD_Mod_Race);
#endif
+ ATTRIB(Race, m_legacydefaults, string, "20 5 7 15 0");
ENDCLASS(Race)
REGISTER_GAMETYPE(RACE, NEW(Race));
#define g_race IS_GAMETYPE(RACE)
CLASS(RaceCTS, Gametype)
INIT(RaceCTS)
{
- this.gametype_init(this, _("Race CTS"),"cts","g_cts",false,"cloaked","timelimit=20",_("Race for fastest time."));
+ this.gametype_init(this, _("Race CTS"),"cts","g_cts",false,false,"cloaked","timelimit=20",_("Race for fastest time."));
}
METHOD(RaceCTS, m_generate_mapinfo, void(Gametype this, string v))
{
// for map databases
// cvar_set("fraglimit", sa);
}
+ METHOD(RaceCTS, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null);
+ }
#ifdef CSQC
ATTRIB(RaceCTS, m_modicons, void(vector pos, vector mySize), HUD_Mod_Race);
#endif
+ ATTRIB(RaceCTS, m_legacydefaults, string, "20 0 0");
ENDCLASS(RaceCTS)
REGISTER_GAMETYPE(CTS, NEW(RaceCTS));
#define g_cts IS_GAMETYPE(CTS)
CLASS(TeamDeathmatch, Gametype)
INIT(TeamDeathmatch)
{
- this.gametype_init(this, _("Team Deathmatch"),"tdm","g_tdm",true,"","timelimit=15 pointlimit=50 teams=2 leadlimit=0",_("Help your team score the most frags against the enemy team"));
+ this.gametype_init(this, _("Team Deathmatch"),"tdm","g_tdm",true,true,"","timelimit=15 pointlimit=50 teams=2 leadlimit=0",_("Help your team score the most frags against the enemy team"));
}
METHOD(TeamDeathmatch, m_parse_mapinfo, bool(string k, string v))
{
{
cvar_set("g_tdm_teams", sa);
}
+ METHOD(TeamDeathmatch, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Point limit:"), 5, 100, 5, "g_tdm_point_limit", "g_tdm_teams_override", _("The amount of points needed before the match will end"));
+ }
+ ATTRIB(TeamDeathmatch, m_legacydefaults, string, "50 20 2 0");
ENDCLASS(TeamDeathmatch)
REGISTER_GAMETYPE(TEAM_DEATHMATCH, NEW(TeamDeathmatch));
#define g_tdm IS_GAMETYPE(TEAM_DEATHMATCH)
CLASS(CaptureTheFlag, Gametype)
INIT(CaptureTheFlag)
{
- this.gametype_init(this, _("Capture the Flag"),"ctf","g_ctf",true,"","timelimit=20 caplimit=10 leadlimit=6",_("Find and bring the enemy flag to your base to capture it, defend your base from the other team"));
+ this.gametype_init(this, _("Capture the Flag"),"ctf","g_ctf",true,true,"","timelimit=20 caplimit=10 leadlimit=6",_("Find and bring the enemy flag to your base to capture it, defend your base from the other team"));
}
METHOD(CaptureTheFlag, m_generate_mapinfo, void(Gametype this, string v))
{
{
cvar_set("fraglimit", sa);
}
+ METHOD(CaptureTheFlag, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Capture limit:"), 1, 20, 1, "capturelimit_override", string_null, _("The amount of captures needed before the match will end"));
+ }
#ifdef CSQC
ATTRIB(CaptureTheFlag, m_modicons, void(vector pos, vector mySize), HUD_Mod_CTF);
ATTRIB(CaptureTheFlag, m_modicons_reset, void(), HUD_Mod_CTF_Reset);
#endif
+ ATTRIB(CaptureTheFlag, m_legacydefaults, string, "300 20 10 0");
ENDCLASS(CaptureTheFlag)
REGISTER_GAMETYPE(CTF, NEW(CaptureTheFlag));
#define g_ctf IS_GAMETYPE(CTF)
CLASS(ClanArena, Gametype)
INIT(ClanArena)
{
- this.gametype_init(this, _("Clan Arena"),"ca","g_ca",true,"","timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill all enemy teammates to win the round"));
+ this.gametype_init(this, _("Clan Arena"),"ca","g_ca",true,true,"","timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill all enemy teammates to win the round"));
}
METHOD(ClanArena, m_parse_mapinfo, bool(string k, string v))
{
{
cvar_set("g_ca_teams", sa);
}
+ METHOD(ClanArena, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Frag limit:"), 5, 100, 5, "fraglimit_override", "g_ca_teams_override", _("The amount of frags needed before the match will end"));
+ }
#ifdef CSQC
ATTRIB(ClanArena, m_modicons, void(vector pos, vector mySize), HUD_Mod_CA);
#endif
+ ATTRIB(ClanArena, m_legacydefaults, string, "10 20 0");
ENDCLASS(ClanArena)
REGISTER_GAMETYPE(CA, NEW(ClanArena));
#define g_ca IS_GAMETYPE(CA)
CLASS(Domination, Gametype)
INIT(Domination)
{
- this.gametype_init(this, _("Domination"),"dom","g_domination",true,"","timelimit=20 pointlimit=200 teams=2 leadlimit=0",_("Capture and defend all the control points to win"));
+ this.gametype_init(this, _("Domination"),"dom","g_domination",true,true,"","timelimit=20 pointlimit=200 teams=2 leadlimit=0",_("Capture and defend all the control points to win"));
}
METHOD(Domination, m_parse_mapinfo, bool(string k, string v))
{
if(v == "dom_controlpoint")
MapInfo_Map_supportedGametypes |= this.m_flags;
}
+ METHOD(Domination, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Point limit:"), 50, 500, 10, "g_domination_point_limit", "g_domination_teams_override", _("The amount of points needed before the match will end"));
+ }
#ifdef CSQC
ATTRIB(Domination, m_modicons, void(vector pos, vector mySize), HUD_Mod_Dom);
#endif
+ ATTRIB(Domination, m_legacydefaults, string, "200 20 0");
ENDCLASS(Domination)
REGISTER_GAMETYPE(DOMINATION, NEW(Domination));
CLASS(KeyHunt, Gametype)
INIT(KeyHunt)
{
- this.gametype_init(this, _("Key Hunt"),"kh","g_keyhunt",true,"","timelimit=20 pointlimit=1000 teams=3 leadlimit=0",_("Gather all the keys to win the round"));
+ this.gametype_init(this, _("Key Hunt"),"kh","g_keyhunt",true,true,"","timelimit=20 pointlimit=1000 teams=3 leadlimit=0",_("Gather all the keys to win the round"));
}
METHOD(KeyHunt, m_parse_mapinfo, bool(string k, string v))
{
{
cvar_set("g_keyhunt_teams", sa);
}
+ METHOD(KeyHunt, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Point limit:"), 200, 1500, 50, "g_keyhunt_point_limit", "g_keyhunt_teams_override", _("The amount of points needed before the match will end"));
+ }
#ifdef CSQC
ATTRIB(KeyHunt, m_modicons, void(vector pos, vector mySize), HUD_Mod_KH);
#endif
+ ATTRIB(KeyHunt, m_legacydefaults, string, "1000 20 3 0");
ENDCLASS(KeyHunt)
REGISTER_GAMETYPE(KEYHUNT, NEW(KeyHunt));
CLASS(Assault, Gametype)
INIT(Assault)
{
- this.gametype_init(this, _("Assault"),"as","g_assault",true,"","timelimit=20",_("Destroy obstacles to find and destroy the enemy power core before time runs out"));
+ this.gametype_init(this, _("Assault"),"as","g_assault",true,false,"","timelimit=20",_("Destroy obstacles to find and destroy the enemy power core before time runs out"));
}
METHOD(Assault, m_generate_mapinfo, void(Gametype this, string v))
{
{
return true;
}
+ METHOD(Assault, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null);
+ }
+ ATTRIB(Assault, m_legacydefaults, string, "20 0");
ENDCLASS(Assault)
REGISTER_GAMETYPE(ASSAULT, NEW(Assault));
#define g_assault IS_GAMETYPE(ASSAULT)
CLASS(Onslaught, Gametype)
INIT(Onslaught)
{
- this.gametype_init(this, _("Onslaught"),"ons","g_onslaught",true,"","pointlimit=1 timelimit=20",_("Capture control points to reach and destroy the enemy generator"));
+ this.gametype_init(this, _("Onslaught"),"ons","g_onslaught",true,false,"","pointlimit=1 timelimit=20",_("Capture control points to reach and destroy the enemy generator"));
}
METHOD(Onslaught, m_generate_mapinfo, void(Gametype this, string v))
{
if(v == "onslaught_generator")
MapInfo_Map_supportedGametypes |= this.m_flags;
}
+ METHOD(Onslaught, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null);
+ }
+ ATTRIB(Onslaught, m_legacydefaults, string, "20 0");
ENDCLASS(Onslaught)
REGISTER_GAMETYPE(ONSLAUGHT, NEW(Onslaught));
CLASS(NexBall, Gametype)
INIT(NexBall)
{
- this.gametype_init(this, _("Nexball"),"nb","g_nexball",true,"","timelimit=20 pointlimit=5 leadlimit=0",_("Shoot and kick the ball into the enemies goal, keep your goal clean"));
+ this.gametype_init(this, _("Nexball"),"nb","g_nexball",true,true,"","timelimit=20 pointlimit=5 leadlimit=0",_("Shoot and kick the ball into the enemies goal, keep your goal clean"));
}
METHOD(NexBall, m_generate_mapinfo, void(Gametype this, string v))
{
{
return true;
}
+ METHOD(NexBall, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Goals:"), 1, 50, 1, "g_nexball_goallimit", string_null, _("The amount of goals needed before the match will end"));
+ }
#ifdef CSQC
ATTRIB(NexBall, m_modicons, void(vector pos, vector mySize), HUD_Mod_NexBall);
#endif
+ ATTRIB(NexBall, m_legacydefaults, string, "5 20 0");
ENDCLASS(NexBall)
REGISTER_GAMETYPE(NEXBALL, NEW(NexBall));
#define g_nexball IS_GAMETYPE(NEXBALL)
CLASS(FreezeTag, Gametype)
INIT(FreezeTag)
{
- this.gametype_init(this, _("Freeze Tag"),"ft","g_freezetag",true,"","timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill enemies to freeze them, stand next to frozen teammates to revive them; freeze all enemies to win"));
+ this.gametype_init(this, _("Freeze Tag"),"ft","g_freezetag",true,true,"","timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill enemies to freeze them, stand next to frozen teammates to revive them; freeze all enemies to win"));
}
METHOD(FreezeTag, m_parse_mapinfo, bool(string k, string v))
{
{
cvar_set("g_freezetag_teams", sa);
}
+ METHOD(FreezeTag, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Frag limit:"), 5, 100, 5, "fraglimit_override", "g_freezetag_teams_override", _("The amount of frags needed before the match will end"));
+ }
#ifdef CSQC
ATTRIB(FreezeTag, m_modicons, void(vector pos, vector mySize), HUD_Mod_CA);
#endif
+ ATTRIB(FreezeTag, m_legacydefaults, string, "10 20 0");
ENDCLASS(FreezeTag)
REGISTER_GAMETYPE(FREEZETAG, NEW(FreezeTag));
#define g_freezetag IS_GAMETYPE(FREEZETAG)
CLASS(Keepaway, Gametype)
INIT(Keepaway)
{
- this.gametype_init(this, _("Keepaway"),"ka","g_keepaway",false,"","timelimit=20 pointlimit=30",_("Hold the ball to get points for kills"));
+ this.gametype_init(this, _("Keepaway"),"ka","g_keepaway",false,true,"","timelimit=20 pointlimit=30",_("Hold the ball to get points for kills"));
}
METHOD(Keepaway, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
{
CLASS(Invasion, Gametype)
INIT(Invasion)
{
- this.gametype_init(this, _("Invasion"),"inv","g_invasion",false,"","pointlimit=50 teams=0 type=0",_("Survive against waves of monsters"));
+ this.gametype_init(this, _("Invasion"),"inv","g_invasion",false,true,"","pointlimit=50 teams=0 type=0",_("Survive against waves of monsters"));
}
METHOD(Invasion, m_parse_mapinfo, bool(string k, string v))
{
if(v == "invasion_spawnpoint")
MapInfo_Map_supportedGametypes |= this.m_flags;
}
+ METHOD(Invasion, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+ {
+ TC(Gametype, this);
+ returns(menu, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null);
+ }
ENDCLASS(Invasion)
REGISTER_GAMETYPE(INVASION, NEW(Invasion));
CLASS(Duel, Gametype)
INIT(Duel)
{
- this.gametype_init(this, _("Duel"),"duel","g_duel",false,"","timelimit=10 pointlimit=0 leadlimit=0",_("Fight in a one versus one arena battle to decide the winner"));
+ this.gametype_init(this, _("Duel"),"duel","g_duel",false,true,"","timelimit=10 pointlimit=0 leadlimit=0",_("Fight in a one versus one arena battle to decide the winner"));
}
METHOD(Duel, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
{
void MapInfo_Shutdown(); // call this in the shutdown handler
#define MAPINFO_SETTEMP_ACL_USER cvar_string("g_mapinfo_settemp_acl")
-#define MAPINFO_SETTEMP_ACL_SYSTEM "-g_mapinfo_* -rcon_* -_* -g_ban* +*"
+#define MAPINFO_SETTEMP_ACL_SYSTEM "-g_mapinfo_* -rcon_* -_* -g_ban* -r_water +*"
SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
}
- int slot = weaponslot(weaponentity);
- ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(okhmg, refire) * W_WeaponRateFactor(actor);
+ ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR_PRI(okhmg, refire) * W_WeaponRateFactor(actor);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(okhmg, refire), W_OverkillHeavyMachineGun_Attack_Auto);
}
SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
}
- int slot = weaponslot(weaponentity);
- ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(okmachinegun, refire) * W_WeaponRateFactor(actor);
+ ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR_PRI(okmachinegun, refire) * W_WeaponRateFactor(actor);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(okmachinegun, refire), W_OverkillMachineGun_Attack_Auto);
}
.entity realowner;
bool sound_allowed(int to, entity e)
{
+ if(!e) return true; // save on a few checks
for ( ; ; )
{
if (e.classname == "body") e = e.enemy;
if(s == t)
{
r = d;
+ break; // if we found a killing case, apply it! other settings may be allowed in the future, but this one is caught
}
}
return r;
getthink(beam)(beam);
}
-void Arc_Smoke(entity actor, .entity weaponentity)
+void W_Arc_Attack(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
+ if(!actor.(weaponentity).arc_beam || wasfreed(actor.(weaponentity).arc_beam))
+ {
+ w_ready(thiswep, actor, weaponentity, fire);
+ return;
+ }
+
+ // attack handled by the beam itself, this is just a loop to keep the attack happening!
+
+ // NOTE: arc doesn't use a refire
+ //ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR_PRI(arc, refire) * W_WeaponRateFactor(actor);
+ actor.(weaponentity).wframe = WFRAME_FIRE1;
+ weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, WEP_CVAR(arc, beam_animtime), W_Arc_Attack);
+}
+void Arc_Smoke(Weapon thiswep, entity actor, .entity weaponentity, int fire)
+{
+ // TODO: spamming this without checking any refires is asking for trouble!
makevectors(actor.v_angle);
- W_SetupShot_Range(actor,weaponentity,false,0,SND_Null,0,0,0,WEP_ARC.m_id); // TODO: probably doesn't need deathtype, since this is just a prefire effect
+ W_SetupShot_Range(actor,weaponentity,false,0,SND_Null,0,0,0,thiswep.m_id); // TODO: probably doesn't need deathtype, since this is just a prefire effect
vector smoke_origin = w_shotorg + actor.velocity*frametime;
if ( actor.arc_overheat > time )
{
if ( random() < actor.(weaponentity).arc_heat_percent )
Send_Effect(EFFECT_ARC_SMOKE, smoke_origin, '0 0 0', 1 );
- if ( PHYS_INPUT_BUTTON_ATCK(actor) || PHYS_INPUT_BUTTON_ATCK2(actor) )
+ if ( (fire & 1) || (fire & 2) )
{
Send_Effect(EFFECT_ARC_OVERHEAT_FIRE, smoke_origin, w_shotdir, 1 );
if ( !actor.arc_smoke_sound )
}
if ( actor.arc_smoke_sound && ( actor.arc_overheat <= time ||
- !( PHYS_INPUT_BUTTON_ATCK(actor) || PHYS_INPUT_BUTTON_ATCK2(actor) ) ) || actor.(weaponentity).m_switchweapon != WEP_ARC )
+ !( PHYS_INPUT_BUTTON_ATCK(actor) || PHYS_INPUT_BUTTON_ATCK2(actor) ) ) || actor.(weaponentity).m_switchweapon != thiswep )
{
actor.arc_smoke_sound = 0;
sound(actor, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
METHOD(Arc, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
Arc_Player_SetHeat(actor, weaponentity);
- Arc_Smoke(actor, weaponentity);
+ Arc_Smoke(thiswep, actor, weaponentity, fire);
bool beam_fire2 = ((fire & 2) && !WEP_CVAR(arc, bolt));
if (time >= actor.arc_overheat)
if ((fire & 1) || beam_fire2 || actor.(weaponentity).arc_beam.beam_bursting)
{
-
+ #if 0
if(actor.(weaponentity).arc_BUTTON_ATCK_prev)
{
#if 0
#endif
weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, WEP_CVAR(arc, beam_animtime), w_ready);
}
+ #endif
if((!actor.(weaponentity).arc_beam) || wasfreed(actor.(weaponentity).arc_beam))
{
if(!actor.(weaponentity).arc_BUTTON_ATCK_prev)
{
- weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
+ actor.(weaponentity).wframe = WFRAME_FIRE1;
+ weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, WEP_CVAR(arc, beam_animtime), W_Arc_Attack);
actor.(weaponentity).arc_BUTTON_ATCK_prev = true;
}
}
if(actor.(weaponentity).arc_BUTTON_ATCK_prev)
{
- int slot = weaponslot(weaponentity);
sound(actor, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
- ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(arc, beam_refire) * W_WeaponRateFactor(actor);
+ ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR(arc, beam_refire) * W_WeaponRateFactor(actor);
}
actor.(weaponentity).arc_BUTTON_ATCK_prev = false;
if(!(this.realowner.items & IT_UNLIMITED_WEAPON_AMMO))
{
this.realowner.cnt = thiswep.m_id;
- int slot = weaponslot(weaponentity);
- ATTACK_FINISHED(this.realowner, slot) = time;
+ ATTACK_FINISHED(this.realowner, weaponentity) = time;
this.realowner.(weaponentity).m_switchweapon = w_getbestweapon(this.realowner, weaponentity);
}
}
if(!(this.realowner.items & IT_UNLIMITED_WEAPON_AMMO))
{
this.realowner.cnt = thiswep.m_id;
- int slot = weaponslot(weaponentity);
- ATTACK_FINISHED(this.realowner, slot) = time;
+ ATTACK_FINISHED(this.realowner, weaponentity) = time;
this.realowner.(weaponentity).m_switchweapon = w_getbestweapon(this.realowner, weaponentity);
}
}
{
#if 0
// don't switch while guiding a missile
- if(ATTACK_FINISHED(actor, slot) <= time || PS(actor).m_weapon != WEP_DEVASTATOR)
+ if(ATTACK_FINISHED(actor, weaponentity) <= time || PS(actor).m_weapon != WEP_DEVASTATOR)
{
ammo_amount = false;
if(WEP_CVAR(devastator, reload_ammo))
W_Hagar_Attack(thiswep, actor, weaponentity);
- int slot = weaponslot(weaponentity);
- ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(hagar, refire) * W_WeaponRateFactor(actor);
- int theframe = WFRAME_FIRE1;
- entity this = actor.(weaponentity);
- if(this)
- {
- if(this.wframe == WFRAME_FIRE1)
- theframe = WFRAME_DONTCHANGE;
- }
- weapon_thinkf(actor, weaponentity, theframe, WEP_CVAR_PRI(hagar, refire), W_Hagar_Attack_Auto);
+ ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR_PRI(hagar, refire) * W_WeaponRateFactor(actor);
+ actor.(weaponentity).wframe = WFRAME_FIRE1;
+ weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, WEP_CVAR_PRI(hagar, refire), W_Hagar_Attack_Auto);
}
METHOD(Hagar, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
return;
}
- int slot = weaponslot(weaponentity);
- ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(hlac, refire) * W_WeaponRateFactor(actor);
+ ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR_PRI(hlac, refire) * W_WeaponRateFactor(actor);
W_HLAC_Attack(thiswep, actor, weaponentity);
actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame);
actor.punchangle_x = random() - 0.5;
actor.punchangle_y = random() - 0.5;
}
- int slot = weaponslot(weaponentity);
// this attack_finished just enforces a cooldown at the end of a burst
- ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor(actor);
+ ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor(actor);
if(actor.(weaponentity).misc_bulletcounter == 1)
fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(machinegun, first_spread), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, first_damage), WEP_CVAR(machinegun, first_force), deathtype, EFFECT_BULLET);
SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
}
- int slot = weaponslot(weaponentity);
- ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor(actor);
+ ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor(actor);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Auto);
}
actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
if(actor.(weaponentity).misc_bulletcounter == 0)
{
- int slot = weaponslot(weaponentity);
- ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(machinegun, burst_refire2) * W_WeaponRateFactor(actor);
+ ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR(machinegun, burst_refire2) * W_WeaponRateFactor(actor);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(machinegun, burst_animtime), w_ready);
}
else
if(!thiswep.wr_checkammo1(thiswep, own, weaponentity))
{
own.cnt = thiswep.m_id;
- int slot = weaponslot(weaponentity);
- ATTACK_FINISHED(own, slot) = time;
+ ATTACK_FINISHED(own, weaponentity) = time;
own.(weaponentity).m_switchweapon = w_getbestweapon(own, weaponentity);
}
}
if(!thiswep.wr_checkammo1(thiswep, own, weaponentity))
{
own.cnt = thiswep.m_id;
- int slot = weaponslot(weaponentity);
- ATTACK_FINISHED(own, slot) = time;
+ ATTACK_FINISHED(own, weaponentity) = time;
own.(weaponentity).m_switchweapon = w_getbestweapon(own, weaponentity);
}
}
}
METHOD(MineLayer, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
{
- //int slot = 0; // TODO: unhardcode
// actually do // don't switch while placing a mine
- //if(ATTACK_FINISHED(actor, slot) <= time || PS(actor).m_weapon != WEP_MINE_LAYER)
+ //if(ATTACK_FINISHED(actor, weaponentity) <= time || PS(actor).m_weapon != WEP_MINE_LAYER)
//{
float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(minelayer, ammo);
ammo_amount += actor.(weaponentity).(weapon_load[thiswep.m_id]) >= WEP_CVAR(minelayer, ammo);
float r, af;
Weapon sw = actor.(weaponentity).m_switchweapon; // make it not detect weapon changes as reason to abort firing
- int slot = weaponslot(weaponentity);
- af = ATTACK_FINISHED(actor, slot);
+ af = ATTACK_FINISHED(actor, weaponentity);
actor.(weaponentity).m_switchweapon = actor.(weaponentity).m_weapon;
- ATTACK_FINISHED(actor, slot) = time;
+ ATTACK_FINISHED(actor, weaponentity) = time;
r = weapon_prepareattack(thiswep, actor, weaponentity, actor.rifle_bullethail_frame == WFRAME_FIRE2, actor.rifle_bullethail_refire);
if(actor.(weaponentity).m_switchweapon == actor.(weaponentity).m_weapon)
actor.(weaponentity).m_switchweapon = sw;
}
else
{
- ATTACK_FINISHED(actor, slot) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
+ ATTACK_FINISHED(actor, weaponentity) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
}
}
void WarpZone_Touch(entity this, entity toucher);
NET_HANDLE(ENT_CLIENT_WARPZONE, bool isnew)
{
+ if(!warpzone_warpzones_exist)
+ cvar_settemp("r_water", "1"); // HACK for DarkPlaces: always enable reflections when a map has warpzones
warpzone_warpzones_exist = 1;
if (!this.enemy)
{
NET_HANDLE(ENT_CLIENT_WARPZONE_CAMERA, bool isnew)
{
+ if(!warpzone_cameras_exist)
+ cvar_settemp("r_water", "1"); // HACK for DarkPlaces: always enable reflections when a map has cameras
warpzone_cameras_exist = 1;
this.classname = "func_warpzone_camera";
void GameType_ConfigureSliders_for_CurrentGametype(entity me)
{
- switch(MapInfo_CurrentGametype())
- {
- case MAPINFO_TYPE_CA: GameType_ConfigureSliders(me, _("Frag limit:"), 5, 100, 5, "fraglimit_override", "g_ca_teams_override", _("The amount of frags needed before the match will end")); break;
- case MAPINFO_TYPE_FREEZETAG: GameType_ConfigureSliders(me, _("Frag limit:"), 5, 100, 5, "fraglimit_override", "g_freezetag_teams_override", _("The amount of frags needed before the match will end")); break;
- case MAPINFO_TYPE_CTF: GameType_ConfigureSliders(me, _("Capture limit:"), 1, 20, 1, "capturelimit_override", string_null, _("The amount of captures needed before the match will end")); break;
- case MAPINFO_TYPE_DOMINATION: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, "g_domination_point_limit", "g_domination_teams_override", _("The amount of points needed before the match will end")); break;
- case MAPINFO_TYPE_KEYHUNT: GameType_ConfigureSliders(me, _("Point limit:"), 200, 1500, 50, "g_keyhunt_point_limit", "g_keyhunt_teams_override", _("The amount of points needed before the match will end")); break;
- case MAPINFO_TYPE_LMS: GameType_ConfigureSliders(me, _("Lives:"), 3, 50, 1, "g_lms_lives_override", string_null, string_null); break;
- case MAPINFO_TYPE_RACE: GameType_ConfigureSliders(me, _("Laps:"), 1, 25, 1, "g_race_laps_limit", string_null, string_null); break;
- case MAPINFO_TYPE_NEXBALL: GameType_ConfigureSliders(me, _("Goals:"), 1, 50, 1, "g_nexball_goallimit", string_null, _("The amount of goals needed before the match will end")); break;
- case MAPINFO_TYPE_ASSAULT: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null); break;
- case MAPINFO_TYPE_ONSLAUGHT: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null); break;
- case MAPINFO_TYPE_CTS: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null); break;
- case MAPINFO_TYPE_INVASION: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null); break;
- case MAPINFO_TYPE_TEAM_DEATHMATCH: GameType_ConfigureSliders(me, _("Point limit:"), 5, 100, 5, "g_tdm_point_limit", "g_tdm_teams_override", _("The amount of points needed before the match will end")); break;
- default: GameType_ConfigureSliders(me, _("Frag limit:"), 5, 100, 5, "fraglimit_override", string_null, _("The amount of frags needed before the match will end")); break;
- }
+ Gametype gt = MapInfo_CurrentGametype();
+ gt.m_configuremenu(gt, me, GameType_ConfigureSliders);
}
entity makeXonoticServerCreateTab()
// Should it do a weapon combo?
float af, ct, combo_time, combo;
- af = ATTACK_FINISHED(this, 0);
+ af = ATTACK_FINISHED(this, weaponentity);
ct = autocvar_bot_ai_weapon_combo_threshold;
// Bots with no skill will be 4 times more slower than "godlike" bots when doing weapon combos
LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " wants to fire, inhibited by weaponentity state");
}
}
- else if(ATTACK_FINISHED(this, slot) > time)
+ else if(ATTACK_FINISHED(this, weaponentity) > time)
{
if(f)
{
this.colormod = '8 0 8';
- LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " wants to fire, inhibited by ATTACK_FINISHED (", ftos(ATTACK_FINISHED(this, slot) - time), " seconds left)");
+ LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " wants to fire, inhibited by ATTACK_FINISHED (", ftos(ATTACK_FINISHED(this, weaponentity) - time), " seconds left)");
}
}
else if(this.(weaponentity).tuba_note)
if(!f)
{
this.colormod = '8 8 0';
- LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " thinks it has fired, but apparently did not; ATTACK_FINISHED says ", ftos(ATTACK_FINISHED(this, slot) - time), " seconds left");
+ LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " thinks it has fired, but apparently did not; ATTACK_FINISHED says ", ftos(ATTACK_FINISHED(this, weaponentity) - time), " seconds left");
}
}
#else
#define ATTACK_FINISHED_FOR(ent, w, slot) ((ent).attack_finished_single[slot])
#endif
-#define ATTACK_FINISHED(ent, slot) ATTACK_FINISHED_FOR(ent, ent.(weaponentity).m_weapon.m_id, slot)
-
-// assault game mode: Which team is attacking in this round?
-float assault_attacker_team;
+#define ATTACK_FINISHED(ent, w) ATTACK_FINISHED_FOR(ent, ent.(w).m_weapon.m_id, weaponslot(w))
// speedrun: when 1, player auto teleports back when capture timeout happens
.float speedrunning;
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \
{ \
.entity weaponentity = weaponentities[slot]; \
- W_SwitchWeapon(this, Weapons_from(WEP_FIRST + i), weaponentity); \
+ W_SwitchWeapon_TryOthers(this, Weapons_from(WEP_FIRST + i), weaponentity); \
if(slot == 0 && autocvar_g_weaponswitch_debug != 1) \
break; \
} \
if (mutator_check == MUT_ACCADD_INVALID) return true;
if (mutator_check != MUT_ACCADD_VALID) return false;
- if (!IS_CLIENT(targ)) return false;
+ if (!IS_CLIENT(targ) || !IS_CLIENT(attacker)) return false;
return true;
}
bool accuracy_canbegooddamage(entity attacker)
{
- return !warmup_stage;
+ return !warmup_stage && IS_CLIENT(attacker);
}
W_SwitchWeapon_Force(this, ww, weaponentity);
}
-void W_SwitchWeapon(entity this, Weapon w, .entity weaponentity)
+bool W_SwitchWeapon(entity this, Weapon w, .entity weaponentity)
{
if(this.(weaponentity).m_switchweapon != w)
{
if(client_hasweapon(this, w, weaponentity, true, true))
+ {
W_SwitchWeapon_Force(this, w, weaponentity);
+ return true;
+ }
else
+ {
this.(weaponentity).selectweapon = w.m_id; // update selectweapon anyway
+ return false;
+ }
}
else if(!forbidWeaponUse(this))
{
entity actor = this;
w.wr_reload(w, actor, weaponentity);
}
+
+ return true; // player already has the weapon out or needs to reload
+}
+
+void W_SwitchWeapon_TryOthers(entity this, Weapon w, .entity weaponentity)
+{
+ if(!W_SwitchWeapon(this, w, weaponentity))
+ W_NextWeaponOnImpulse(this, w.impulse, weaponentity);
}
void W_CycleWeapon(entity this, string weaponorder, float dir, .entity weaponentity)
// perform weapon to attack (weaponstate and attack_finished check is here)
void W_SwitchToOtherWeapon(entity this, .entity weaponentity);
-void W_SwitchWeapon(entity this, Weapon imp, .entity weaponentity);
+bool W_SwitchWeapon(entity this, Weapon imp, .entity weaponentity); // returns false if the player does not have the weapon
+void W_SwitchWeapon_TryOthers(entity this, Weapon imp, .entity weaponentity);
void W_CycleWeapon(entity this, string weaponorder, float dir, .entity weaponentity);
if (attacktime >= 0)
{
- int slot = weaponslot(weaponentity);
// don't fire if previous attack is not finished
- if (ATTACK_FINISHED(actor, slot) > time + actor.(weaponentity).weapon_frametime * 0.5) return false;
+ if (ATTACK_FINISHED(actor, weaponentity) > time + actor.(weaponentity).weapon_frametime * 0.5) return false;
entity this = actor.(weaponentity);
// don't fire while changing weapon
if (this.state != WS_READY) return false;
// if the weapon hasn't been firing continuously, reset the timer
if (attacktime >= 0)
{
- int slot = weaponslot(weaponentity);
- if (ATTACK_FINISHED(actor, slot) < time - this.weapon_frametime * 1.5)
+ if (ATTACK_FINISHED(actor, weaponentity) < time - this.weapon_frametime * 1.5)
{
- ATTACK_FINISHED(actor, slot) = time;
+ ATTACK_FINISHED(actor, weaponentity) = time;
// dprint("resetting attack finished to ", ftos(time), "\n");
}
- ATTACK_FINISHED(actor, slot) = ATTACK_FINISHED(actor, slot) + attacktime * W_WeaponRateFactor(actor);
+ float arate = W_WeaponRateFactor(actor);
+ ATTACK_FINISHED(actor, weaponentity) = ATTACK_FINISHED(actor, weaponentity) + attacktime * arate;
if(autocvar_g_weaponswitch_debug_alternate && W_DualWielding(actor))
{
+ int slot = weaponslot(weaponentity);
for(int wepslot = 0; wepslot < MAX_WEAPONSLOTS; ++wepslot)
{
if(slot == wepslot)
.entity wepent = weaponentities[wepslot];
if(actor.(wepent) && actor.(wepent).m_weapon != WEP_Null)
{
- if (ATTACK_FINISHED(actor, wepslot) < time - actor.(wepent).weapon_frametime * 1.5)
- ATTACK_FINISHED(actor, wepslot) = time;
- ATTACK_FINISHED(actor, wepslot) = ATTACK_FINISHED(actor, wepslot) + (attacktime * W_WeaponRateFactor(actor)) * 0.5;
+ if(ATTACK_FINISHED(actor, wepent) > time + actor.(wepent).weapon_frametime * 0.5)
+ continue; // still cooling down!
+ if (ATTACK_FINISHED(actor, wepent) < time - actor.(wepent).weapon_frametime * 1.5)
+ ATTACK_FINISHED(actor, wepent) = time;
+ ATTACK_FINISHED(actor, wepent) = ATTACK_FINISHED(actor, wepent) + (attacktime * arate) / MAX_WEAPONSLOTS;
}
}
}
}
this.bulletcounter += 1;
- // dprint("attack finished ", ftos(ATTACK_FINISHED(actor, slot)), "\n");
+ // dprint("attack finished ", ftos(ATTACK_FINISHED(actor, weaponentity)), "\n");
}
bool weapon_prepareattack(Weapon thiswep, entity actor, .entity weaponentity, bool secondary, float attacktime)
entity oldwep = this.m_weapon;
// set up weapon switch think in the future, and start drop anim
- if (INDEPENDENT_ATTACK_FINISHED || ATTACK_FINISHED(actor, weaponslot(weaponentity)) <= time + this.weapon_frametime * 0.5)
+ if (INDEPENDENT_ATTACK_FINISHED || ATTACK_FINISHED(actor, weaponentity) <= time + this.weapon_frametime * 0.5)
{
sound(actor, CH_WEAPON_SINGLE, SND_WEAPON_SWITCH, VOL_BASE, ATTN_NORM);
this.state = WS_DROP;
// LordHavoc: network timing test code
// if (actor.button0)
- // print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(actor, slot)), " >= ", ftos(this.weapon_nextthink), "\n");
+ // print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(actor, weaponentity)), " >= ", ftos(this.weapon_nextthink), "\n");
Weapon w = this.m_weapon;
{
backtrace(sprintf(
"W_DecreaseAmmo(%.2f): '%s' subtracted too much %s from '%s', resulting with '%.2f' left... "
- "Please notify Samual immediately with a copy of this backtrace!\n",
+ "Please notify the developers immediately with a copy of this backtrace!\n",
ammo_use,
wep.netname,
GetAmmoPicture(wep.ammo_type),
// then quickly switch to another weapon and back. Reloading is canceled, but the reload delay is still there,
// so your weapon is disabled for a few seconds without reason
- // ATTACK_FINISHED(actor, slot) -= w_ent.reload_time - 1;
+ // ATTACK_FINISHED(actor, weaponentity) -= w_ent.reload_time - 1;
w_ready(wpn, actor, weaponentity, PHYS_INPUT_BUTTON_ATCK(actor) | (PHYS_INPUT_BUTTON_ATCK2(actor) << 1));
}
// then quickly switch to another weapon and back. Reloading is canceled, but the reload delay is still there,
// so your weapon is disabled for a few seconds without reason
- // ATTACK_FINISHED(actor, slot) = max(time, ATTACK_FINISHED(actor, slot)) + this.reload_time + 1;
+ // ATTACK_FINISHED(actor, weaponentity) = max(time, ATTACK_FINISHED(actor, weaponentity)) + this.reload_time + 1;
weapon_thinkf(actor, weaponentity, WFRAME_RELOAD, this.reload_time, W_ReloadedAndReady);