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
// sv_vote_gametype_*_type Must be set to the name of the gametype the option is based on
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 1 "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;
+}
{
int r = MapInfo_Get_ByName_NoFallbacks(pFilename, pAllowGenerate, pGametypeToSet);
+ // 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 & MAPINFO_TYPE_DUEL.m_flags) && (MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DEATHMATCH.m_flags))
+ _MapInfo_Map_ApplyGametypeEx ("", pGametypeToSet, MAPINFO_TYPE_DUEL);
+
if(cvar("g_tdm_on_dm_maps"))
{
// if this is set, all DM maps support TDM too
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 < 4096);
+ }
+ENDCLASS(Duel)
+REGISTER_GAMETYPE(DUEL, NEW(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;
// add/remove bots if needed to make sure there are at least
// minplayers+bot_number, or remove all bots if no one is playing
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);
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);