alias cl_hook_gamestart_ka
alias cl_hook_gamestart_ft
alias cl_hook_gamestart_inv
+alias cl_hook_gamestart_duel
alias cl_hook_gameend "rpn /cl_matchcount dup load 1 + =" // increase match count every time a game ends
alias cl_hook_shutdown
alias cl_hook_activeweapon
alias sv_hook_gamestart_ka
alias sv_hook_gamestart_ft
alias sv_hook_gamestart_inv
+alias sv_hook_gamestart_duel
alias sv_hook_gamerestart
alias sv_hook_gameend
alias sv_vote_gametype_hook_ons
alias sv_vote_gametype_hook_rc
alias sv_vote_gametype_hook_tdm
+alias sv_vote_gametype_hook_duel
-// Example preset to allow duel to be used for the gametype voting screen
+// Example preset to allow 1v1ctf to be used for the gametype voting screen
// sv_vote_gametype_*_type Must be set to the name of the gametype the option is based on
// sv_vote_gametype_*_name Contains a human-readable name of the gametype
// sv_vote_gametype_*_description Contains a longer description
-//set sv_vote_gametype_duel_type dm
-//set sv_vote_gametype_duel_name Duel
-//set sv_vote_gametype_duel_description "One vs One match"
+//set sv_vote_gametype_1v1ctf_type ctf
+//set sv_vote_gametype_1v1ctf_name "Capture the Flag Duel"
+//set sv_vote_gametype_1v1ctf_description "One vs One match in CTF"
//alias sv_vote_gametype_hook_all "set g_maxplayers 0"
-//alias sv_vote_gametype_hook_duel "set g_maxplayers 2"
+//alias sv_vote_gametype_hook_1v1ctf "set g_maxplayers 2"
// ===========
set g_inv_respawn_delay_max 0
set g_inv_respawn_waves 0
set g_inv_weapon_stay 0
+set g_duel_respawn_delay_small 0
+set g_duel_respawn_delay_small_count 0
+set g_duel_respawn_delay_large 0
+set g_duel_respawn_delay_large_count 0
+set g_duel_respawn_delay_max 0
+set g_duel_respawn_waves 0
+set g_duel_weapon_stay 0
// =========
set g_invasion_teams 0 "number of teams in invasion (note: use mapinfo to set this)"
set g_invasion_team_spawns 1 "use team spawns in teamplay invasion mode"
set g_invasion_type 0 "type of invasion mode - 0: round-based, 1: hunting, 2: complete the stage (note: use mapinfo to set this)"
+
+// ======
+// duel
+// ======
+set g_duel 0 "Duel: frag the opponent more in a one versus one arena battle"
#include <common/gamemodes/gamemode/cts/_mod.inc>
#include <common/gamemodes/gamemode/deathmatch/_mod.inc>
#include <common/gamemodes/gamemode/domination/_mod.inc>
+#include <common/gamemodes/gamemode/duel/_mod.inc>
#include <common/gamemodes/gamemode/freezetag/_mod.inc>
#include <common/gamemodes/gamemode/invasion/_mod.inc>
#include <common/gamemodes/gamemode/keepaway/_mod.inc>
#include <common/gamemodes/gamemode/cts/_mod.qh>
#include <common/gamemodes/gamemode/deathmatch/_mod.qh>
#include <common/gamemodes/gamemode/domination/_mod.qh>
+#include <common/gamemodes/gamemode/duel/_mod.qh>
#include <common/gamemodes/gamemode/freezetag/_mod.qh>
#include <common/gamemodes/gamemode/invasion/_mod.qh>
#include <common/gamemodes/gamemode/keepaway/_mod.qh>
--- /dev/null
+// generated file; do not modify
+#ifdef SVQC
+ #include <common/gamemodes/gamemode/duel/sv_duel.qc>
+#endif
--- /dev/null
+// generated file; do not modify
+#ifdef SVQC
+ #include <common/gamemodes/gamemode/duel/sv_duel.qh>
+#endif
--- /dev/null
+#include "sv_duel.qh"
+
+MUTATOR_HOOKFUNCTION(duel, ReadLevelCvars)
+{
+ warmup_stage = 1;
+ //sv_ready_restart_after_countdown = 0;
+}
+
+MUTATOR_HOOKFUNCTION(duel, GetPlayerLimit)
+{
+ M_ARGV(0, int) = 2; // duel is always 1v1!
+}
+
+MUTATOR_HOOKFUNCTION(duel, Scores_CountFragsRemaining)
+{
+ // announce remaining frags?
+ return true;
+}
--- /dev/null
+#pragma once
+
+#include <common/mutators/base.qh>
+REGISTER_MUTATOR(duel, false)
+{
+ MUTATOR_STATIC();
+ return 0;
+}
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"));
+ }
+ METHOD(Duel, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+ {
+ return (diameter < 16384);
+ }
+ METHOD(Duel, m_isForcedSupported, bool(Gametype this))
+ {
+ // force all DM maps to work in duel?!
+ // TODO: we should really check the size of maps, some DM maps do not work for duel!
+ if(!(MapInfo_Map_supportedGametypes & this.m_flags) && (MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DEATHMATCH.m_flags))
+ return true;
+ return false;
+ }
+ENDCLASS(Duel)
+REGISTER_GAMETYPE(DUEL, NEW(Duel));
+#define g_duel IS_GAMETYPE(DUEL)
+
const int MAPINFO_FEATURE_WEAPONS = 1; // not defined for instagib-only maps
const int MAPINFO_FEATURE_VEHICLES = 2;
const int MAPINFO_FEATURE_TURRETS = 4;
}
// this... is a hack, a temporary one until we get a proper duel gametype
+// TODO: remove duel hack after servers have migrated to the proper duel gametype!
string PlayerStats_GetGametype()
{
if(IS_GAMETYPE(DEATHMATCH) && autocvar_g_maxplayers == 2)
GAMETYPE(MAPINFO_TYPE_NEXBALL) \
GAMETYPE(MAPINFO_TYPE_ONSLAUGHT) \
GAMETYPE(MAPINFO_TYPE_ASSAULT) \
+ /* GAMETYPE(MAPINFO_TYPE_DUEL) */ \
/* GAMETYPE(MAPINFO_TYPE_INVASION) */ \
/**/
});
}
+ //int player_limit = GetPlayerLimit(); // TODO: use this instead of maxclients!
int bots;
// But don't remove bots immediately on level change, as the real players
// usually haven't rejoined yet
this.team_selected = false;
}
+int GetPlayerLimit()
+{
+ int player_limit = autocvar_g_maxplayers;
+ MUTATOR_CALLHOOK(GetPlayerLimit, player_limit);
+ player_limit = M_ARGV(0, int);
+ return player_limit;
+}
+
/**
* Determines whether the player is allowed to join. This depends on cvar
* g_maxplayers, if it isn't used this function always return true, otherwise
++currentlyPlaying;
});
+ int player_limit = GetPlayerLimit();
+
float free_slots = 0;
- if (!autocvar_g_maxplayers)
+ if (!player_limit)
free_slots = maxclients - totalClients;
- else if(currentlyPlaying < autocvar_g_maxplayers)
- free_slots = min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying);
+ else if(currentlyPlaying < player_limit)
+ free_slots = min(maxclients - totalClients, player_limit - currentlyPlaying);
static float join_prevent_msg_time = 0;
if(this && ignore && !free_slots && time > join_prevent_msg_time)
void ClientInit_misc(entity this);
+int GetPlayerLimit();
+
bool joinAllowed(entity this);
void Join(entity this);
gametypename = "team";
if(g_ctf)
gametypename = "ctf";
+ if(g_duel)
+ gametypename = "tournament";
if(maxclients == 1)
gametypename = "single";
// we do not have the other types (oneflag, obelisk, harvester, teamtournament)
BADCVAR("g_dm");
BADCVAR("g_domination");
BADCVAR("g_domination_default_teams");
+ BADCVAR("g_duel");
BADCVAR("g_freezetag");
BADCVAR("g_freezetag_teams");
BADCVAR("g_invasion_teams");
/** targ */ i(entity, MUTATOR_ARGV_0_entity) \
/**/
MUTATOR_HOOKABLE(Unfreeze, EV_Unfreeze);
+
+/**
+ * Called when a player is trying to join, argument is the number of players allowed to join the match
+ */
+#define EV_GetPlayerLimit(i, o) \
+ /** g_maxplayers */ i(int, MUTATOR_ARGV_0_int) \
+ /**/ o(int, MUTATOR_ARGV_0_int) \
+ /**/
+MUTATOR_HOOKABLE(GetPlayerLimit, EV_GetPlayerLimit);