alias sv_hook_gamestart_ka
alias sv_hook_gamestart_ft
alias sv_hook_gamestart_inv
+alias sv_hook_gamestart_gg
alias sv_hook_gamerestart
alias sv_hook_gameend
alias sv_vote_gametype_hook_dm
alias sv_vote_gametype_hook_dom
alias sv_vote_gametype_hook_ft
+alias sv_vote_gametype_hook_gg
alias sv_vote_gametype_hook_inv
alias sv_vote_gametype_hook_ka
alias sv_vote_gametype_hook_kh
set g_inv_respawn_delay_max 0
set g_inv_respawn_waves 0
set g_inv_weapon_stay 0
+set g_gg_respawn_delay_small 0
+set g_gg_respawn_delay_small_count 0
+set g_gg_respawn_delay_large 0
+set g_gg_respawn_delay_large_count 0
+set g_gg_respawn_delay_max 0
+set g_gg_respawn_waves 0
+set g_gg_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)"
+
+// =========
+// gungame
+// =========
+set g_gg 0 "GunGame: Kill players with all weapons. One weapon at a time."
+set g_gg_weapons "vortex mortar machinegun hagar arc electro devastator crylink shotgun blaster"
+set g_gg_kills_per_weapon 3 "Number of kills needed to advance to the next weapon"
}
}
+// GunGame
+
+/// \brief Duration of transition between the weapons pictures.
+const float gg_weapon_transition_duration = 0.5;
+
+int gg_current_weapon; ///< Current weapon.
+string gg_current_weapon_picture; ///< Current weapon picture.
+int gg_previous_weapon; ///< Previous weapon.
+string gg_previous_weapon_picture; ///< Previous weapon picture.
+float gg_weapon_change_time; ///< Time when the weapon changed.
+
+/// \brief Returns the picture of the weapon.
+/// \param[in] weapon Index of the weapon.
+/// \return Picture of the weapon.
+string GG_GetWeaponPicture(int weapon)
+{
+ FOREACH(Weapons, it != WEP_Null,
+ {
+ if (it.m_id == weapon)
+ {
+ return it.model2;
+ }
+ });
+ return "";
+}
+
+void HUD_Mod_GG(vector pos, vector mySize)
+{
+ // Required in each mod function that always shows something.
+ mod_active = 1;
+ int stat_weapon = STAT(GUNGAME_LEADING_WEAPON);
+ if (stat_weapon != gg_current_weapon)
+ {
+ // New leading weapon.
+ gg_previous_weapon = gg_current_weapon;
+ gg_previous_weapon_picture = gg_current_weapon_picture;
+ gg_current_weapon = stat_weapon;
+ gg_current_weapon_picture = GG_GetWeaponPicture(gg_current_weapon);
+ gg_weapon_change_time = time;
+ }
+ vector pic_pos, pic_size;
+ if (mySize.x > mySize.y)
+ {
+ pic_pos = pos + eX * 0.25 * mySize.x;
+ pic_size = vec2(0.5 * mySize.x, mySize.y);
+ }
+ else
+ {
+ pic_pos = pos + eY * 0.25 * mySize.y;
+ pic_size = vec2(mySize.x, 0.5 * mySize.y);
+ }
+ float weapon_change_elapsed_time = time - gg_weapon_change_time;
+ // Weapon transition phase. 0 at the start of transition. 1 at the end.
+ float phase = bound(0, weapon_change_elapsed_time /
+ gg_weapon_transition_duration, 1);
+
+ // Draw current weapon picture. Fading in if phase is less than 1.
+ if (gg_current_weapon_picture)
+ {
+ drawpic_aspect_skin(pic_pos, gg_current_weapon_picture, pic_size,
+ '1 1 1', phase, DRAWFLAG_NORMAL);
+ }
+ // Draw previous weapon picture on top of current one so it gives a nice
+ // fade out effect.
+ if ((phase < 1) && gg_previous_weapon_picture)
+ {
+ drawpic_aspect_skin_expanding(pic_pos, gg_previous_weapon_picture,
+ pic_size, '1 1 1', 1 - phase, DRAWFLAG_NORMAL, phase);
+ }
+}
+
void HUD_ModIcons_SetFunc()
{
HUD_ModIcons_GameType = gametype.m_modicons;
#include <common/gamemodes/gamemode/deathmatch/_mod.inc>
#include <common/gamemodes/gamemode/domination/_mod.inc>
#include <common/gamemodes/gamemode/freezetag/_mod.inc>
+#include <common/gamemodes/gamemode/gungame/_mod.inc>
#include <common/gamemodes/gamemode/invasion/_mod.inc>
#include <common/gamemodes/gamemode/keepaway/_mod.inc>
#include <common/gamemodes/gamemode/keyhunt/_mod.inc>
#include <common/gamemodes/gamemode/deathmatch/_mod.qh>
#include <common/gamemodes/gamemode/domination/_mod.qh>
#include <common/gamemodes/gamemode/freezetag/_mod.qh>
+#include <common/gamemodes/gamemode/gungame/_mod.qh>
#include <common/gamemodes/gamemode/invasion/_mod.qh>
#include <common/gamemodes/gamemode/keepaway/_mod.qh>
#include <common/gamemodes/gamemode/keyhunt/_mod.qh>
--- /dev/null
+// generated file; do not modify
+#ifdef SVQC
+ #include <common/gamemodes/gamemode/gungame/sv_gungame.qc>
+#endif
--- /dev/null
+// generated file; do not modify
+#ifdef SVQC
+ #include <common/gamemodes/gamemode/gungame/sv_gungame.qh>
+#endif
--- /dev/null
+/// \file
+/// \brief Source file that contains implementation of the GunGame gamemode.
+/// \copyright GNU GPLv2 or any later version.
+
+#include "sv_gungame.qh"
+
+//============================ Constants ======================================
+
+const string GUNGAME_WEAPONS_CVAR = "g_gg_weapons";
+
+//======================= Global variables ====================================
+
+/// \brief Number of kills needed to advance to the next weapon.
+int autocvar_g_gg_kills_per_weapon;
+
+int gungame_win_level; ///< Player who reaches this level wins.
+string gungame_weapons; ///< Holds weapons corresponding to levels.
+
+int gungame_status; ///< Holds global status of the game.
+entity gungame_leading_player; ///< Holds the leading player.
+int gungame_leading_level; ///< Holds the leading level.
+entity gungame_leading_weapon; ///< Holds the leading weapon.
+
+//====================== Forward declarations =================================
+
+/// \brief Resets the state to initial one.
+void GunGame_Reset();
+
+/// \brief Returns the weapon that corresponds to the given level.
+/// \param[in] level Level of the weapon.
+/// \return Weapon corresponding to the given level.
+entity GunGame_GetWeapon(int level);
+
+/// \brief Updates stats of all players.
+void GunGame_UpdateStats();
+
+//========================= Free functions ====================================
+
+void GunGame_Initialize()
+{
+ GunGame_Reset();
+}
+
+void GunGame_Reset()
+{
+ strcpy(gungame_weapons, cvar_string(GUNGAME_WEAPONS_CVAR));
+ gungame_win_level = tokenize_console(gungame_weapons) *
+ autocvar_g_gg_kills_per_weapon;
+ if (gungame_win_level == 0)
+ {
+ LOG_FATAL("GunGame: Invalid weapon configuration.");
+ }
+ gungame_status = WINNING_NO;
+ GameRules_limit_score(gungame_win_level);
+ gungame_leading_player = NULL;
+ gungame_leading_level = 0;
+ gungame_leading_weapon = GunGame_GetWeapon(0);
+ GunGame_UpdateStats();
+}
+
+entity GunGame_GetWeapon(int level)
+{
+ if (level >= gungame_win_level)
+ {
+ return NULL;
+ }
+ tokenize_console(gungame_weapons);
+ string weapon = argv(floor(level / autocvar_g_gg_kills_per_weapon));
+ FOREACH(Weapons, it != WEP_Null,
+ {
+ if (it.netname == weapon)
+ {
+ return it;
+ }
+ });
+ LOG_FATAL("GunGame_GetWeapon: Invalid level or weapon name");
+ return NULL;
+}
+
+/// \brief Returns the player level.
+/// \param[in] player Player to check.
+/// \return Level of the player.
+int GunGame_GetPlayerLevel(entity player)
+{
+ return PlayerScore_Get(player, SP_SCORE);
+}
+
+/// \brief Updates the information about the leading player.
+void GunGame_UpdateLeadingPlayer()
+{
+ entity previous_leader = gungame_leading_player;
+ FOREACH_CLIENT(true,
+ {
+ if (gungame_leading_player == NULL)
+ {
+ gungame_leading_player = it;
+ continue;
+ }
+ if (GunGame_GetPlayerLevel(it) > GunGame_GetPlayerLevel(
+ gungame_leading_player))
+ {
+ gungame_leading_player = it;
+ }
+ });
+ if (gungame_leading_player == NULL)
+ {
+ return;
+ }
+ if ((gungame_leading_player == previous_leader) &&
+ (GunGame_GetPlayerLevel(gungame_leading_player) ==
+ gungame_leading_level))
+ {
+ return;
+ }
+ gungame_leading_level = GunGame_GetPlayerLevel(gungame_leading_player);
+ gungame_leading_weapon = GunGame_GetWeapon(gungame_leading_level);
+ GunGame_UpdateStats();
+}
+
+void GunGame_UpdateStats()
+{
+ FOREACH_CLIENT(IS_REAL_CLIENT(it),
+ {
+ STAT(GUNGAME_LEADING_WEAPON, it) = gungame_leading_weapon.m_id;
+ });
+}
+
+/// \brief Gives the player a weapon that corresponds to their level.
+/// \param[in,out] player Player to give weapon to.
+void GunGame_GivePlayerWeapon(entity player)
+{
+ int level = GunGame_GetPlayerLevel(player);
+ if (level >= gungame_win_level)
+ {
+ return;
+ }
+ entity weapon = GunGame_GetWeapon(level);
+ STAT(WEAPONS, player) |= weapon.m_wepset;
+ int levels_left = gungame_win_level - level;
+ if (levels_left > 3)
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER,
+ CENTER_GUNGAME_NEW_LEVEL, level + 1, weapon.m_id);
+ Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_GUNGAME_NEW_LEVEL,
+ level + 1, weapon.m_id);
+ return;
+ }
+ if (levels_left > 1)
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER,
+ CENTER_GUNGAME_LEVELS_LEFT, levels_left, weapon.m_id);
+ Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_GUNGAME_LEVELS_LEFT,
+ levels_left, weapon.m_id);
+ return;
+ }
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_GUNGAME_LAST_LEVEL,
+ weapon.m_id);
+ Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_GUNGAME_LAST_LEVEL,
+ weapon.m_id);
+}
+
+//============================= Hooks ========================================
+
+/// \brief Hook that is called to determine if there is a weapon arena.
+MUTATOR_HOOKFUNCTION(gg, SetWeaponArena)
+{
+ M_ARGV(0, string) = "off";
+}
+
+/// \brief Hook that is called to determine start items of all players.
+MUTATOR_HOOKFUNCTION(gg, SetStartItems)
+{
+ start_weapons = WEPSET(Null);
+ warmup_start_weapons = WEPSET(Null);
+}
+
+/// \brief Hook that is called when an item is about to spawn.
+MUTATOR_HOOKFUNCTION(gg, FilterItemDefinition)
+{
+ entity item = M_ARGV(0, entity);
+ if (item.instanceOfAmmo)
+ {
+ // Block ammo from spawning.
+ return true;
+ }
+ if (item.instanceOfWeaponPickup)
+ {
+ // Block weapons from spawning.
+ return true;
+ }
+}
+
+/// \brief Hook that is called every frame to check if the game is won and/or
+/// over.
+MUTATOR_HOOKFUNCTION(gg, CheckRules_World)
+{
+ M_ARGV(0, float) = gungame_status;
+ //M_ARGV(2, float) = gungame_win_level;
+ return true;
+}
+
+/// \brief Hook that is called when player connects to the server.
+MUTATOR_HOOKFUNCTION(gg, ClientConnect)
+{
+ entity player = M_ARGV(0, entity);
+ if (!IS_REAL_CLIENT(player))
+ {
+ return true;
+ }
+ STAT(GUNGAME_LEADING_WEAPON, player) = gungame_leading_weapon.m_id;
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(gg, reset_map_global)
+{
+ GunGame_Reset();
+}
+
+/// \brief Hook that is called when player spawns.
+MUTATOR_HOOKFUNCTION(gg, PlayerSpawn, CBC_ORDER_LAST)
+{
+ entity player = M_ARGV(0, entity);
+ STAT(WEAPONS, player) = WEPSET(Null);
+ GunGame_GivePlayerWeapon(player);
+ player.items |= IT_UNLIMITED_AMMO;
+}
+
+/// \brief Hook which is called when the player tries to throw their weapon.
+MUTATOR_HOOKFUNCTION(gg, ForbidThrowCurrentWeapon)
+{
+ return true;
+}
+
+/// \brief Hook that is called when player dies.
+MUTATOR_HOOKFUNCTION(gg, PlayerDies)
+{
+ GunGame_UpdateLeadingPlayer();
+ entity attacker = M_ARGV(1, entity);
+ if (!IS_PLAYER(attacker) || IS_DEAD(attacker))
+ {
+ return;
+ }
+ if (GunGame_GetPlayerLevel(attacker) >= gungame_win_level)
+ {
+ gungame_status = WINNING_YES;
+ return;
+ }
+ STAT(WEAPONS, attacker) = WEPSET(Null);
+ GunGame_GivePlayerWeapon(attacker);
+}
+
+/// \brief Hook that determines whether remaining frags are announced.
+MUTATOR_HOOKFUNCTION(gg, Scores_CountFragsRemaining)
+{
+ // Announce remaining frags.
+ return true;
+}
--- /dev/null
+/// \file
+/// \brief Header file that describes the GunGame gamemode.
+/// \copyright GNU GPLv2 or any later version.
+
+#pragma once
+
+/// \brief Initializes global data for the gametype.
+void GunGame_Initialize();
+
+REGISTER_MUTATOR(gg, false)
+{
+ MUTATOR_STATIC();
+ MUTATOR_ONADD
+ {
+ GunGame_Initialize();
+ }
+ return 0;
+}
ENDCLASS(Invasion)
REGISTER_GAMETYPE(INVASION, NEW(Invasion));
+//=============================================================================
+
+#ifdef CSQC
+void HUD_Mod_GG(vector pos, vector mySize);
+#endif
+CLASS(GunGame, Gametype)
+ INIT(GunGame)
+ {
+ this.gametype_init(this, _("GunGame"), "gg", "g_gg", false, "", "timelimit=20", _("Kill players with all weapons. One weapon at a time"));
+ }
+ METHOD(GunGame, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+ {
+ return true;
+ }
+#ifdef CSQC
+ ATTRIB(GunGame, m_modicons, void(vector pos, vector mySize), HUD_Mod_GG);
+#endif
+ENDCLASS(GunGame)
+REGISTER_GAMETYPE(GUNGAME, NEW(GunGame));
+#define g_gg IS_GAMETYPE(GUNGAME)
+
+//=============================================================================
+
const int MAPINFO_FEATURE_WEAPONS = 1; // not defined for instagib-only maps
const int MAPINFO_FEATURE_VEHICLES = 2;
const int MAPINFO_FEATURE_TURRETS = 4;
MSG_INFO_NOTIF(GODMODE_OFF, N_CONSOLE, 0, 1, "f1", "", "", _("^BGGodmode saved you %s units of damage, cheater!"), "")
+ MSG_INFO_NOTIF(GUNGAME_NEW_LEVEL, N_CONSOLE, 0, 2, "f1 item_wepname2", "", "", _("^BGYou are on level %s: ^F1%s"), "")
+ MSG_INFO_NOTIF(GUNGAME_LEVELS_LEFT, N_CONSOLE, 0, 2, "f1 item_wepname2", "", "", _("^BG%s levels left: ^F1%s"), "")
+ MSG_INFO_NOTIF(GUNGAME_LAST_LEVEL, N_CONSOLE, 0, 1, "item_wepname", "", "", _("^BGLAST LEVEL: ^F1%s"), "")
+
MSG_INFO_NOTIF(ITEM_BUFF, N_CONSOLE, 1, 1, "s1 item_buffname", "", "", _("^BG%s^BG got the %s^BG buff!"), "")
MSG_INFO_NOTIF(ITEM_BUFF_LOST, N_CONSOLE, 1, 1, "s1 item_buffname", "", "", _("^BG%s^BG lost the %s^BG buff!"), "")
MSG_INFO_NOTIF(ITEM_BUFF_DROP, N_CONSOLE, 0, 1, "item_buffname", "", "", _("^BGYou dropped the %s^BG buff!"), "")
MSG_CENTER_NOTIF(FREEZETAG_SELF, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^K1You froze yourself"), "")
MSG_CENTER_NOTIF(FREEZETAG_SPAWN_LATE, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^K1Round already started, you spawn as frozen"), "")
+ MSG_CENTER_NOTIF(GUNGAME_NEW_LEVEL, N_ENABLE, 0, 2, "f1 item_wepname2", CPID_Null, "0 0", _("^F2Level %s: ^F1%s"), "")
+ MSG_CENTER_NOTIF(GUNGAME_LEVELS_LEFT, N_ENABLE, 0, 2, "f1 item_wepname2", CPID_Null, "0 0", _("^F2%s levels left: ^F1%s"), "")
+ MSG_CENTER_NOTIF(GUNGAME_LAST_LEVEL, N_ENABLE, 0, 1, "item_wepname", CPID_Null, "0 0", _("^F2LAST LEVEL: ^F1%s"), "")
+
MSG_CENTER_NOTIF(INVASION_SUPERMONSTER, N_ENABLE, 1, 0, "s1", CPID_Null, "0 0", _("^K1A %s has arrived!"), "")
MSG_CENTER_NOTIF(ITEM_BUFF_DROP, N_ENABLE, 0, 1, "item_buffname", CPID_ITEM, "item_centime 0", _("^BGYou dropped the %s^BG buff!"), "")
ARG_CASE(ARG_CS_SV, "spree_end", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-1, "", "", f1) : "")) \
ARG_CASE(ARG_CS_SV, "spree_lost", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-2, "", "", f1) : "")) \
ARG_CASE(ARG_CS_SV, "item_wepname", Weapons_from(f1).m_name) \
+ ARG_CASE(ARG_CS_SV, "item_wepname2", Weapons_from(f2).m_name) \
ARG_CASE(ARG_CS_SV, "item_buffname", BUFF_NAME(f1)) \
ARG_CASE(ARG_CS_SV, "f3buffname", BUFF_NAME(f3)) \
ARG_CASE(ARG_CS_SV, "item_wepammo", (s1 != "" ? sprintf(_(" with %s"), s1) : "")) \
REGISTER_STAT(DOM_PPS_YELLOW, float)
REGISTER_STAT(DOM_PPS_PINK, float)
+// gungame
+REGISTER_STAT(GUNGAME_LEADING_WEAPON, int)
+
REGISTER_STAT(TELEPORT_MAXSPEED, float, autocvar_g_teleport_maxspeed)
REGISTER_STAT(TELEPORT_TELEFRAG_AVOID, int, autocvar_g_telefrags_avoid)
GAMETYPE(MAPINFO_TYPE_NEXBALL) \
GAMETYPE(MAPINFO_TYPE_ONSLAUGHT) \
GAMETYPE(MAPINFO_TYPE_ASSAULT) \
+ GAMETYPE(MAPINFO_TYPE_GUNGAME) \
/* GAMETYPE(MAPINFO_TYPE_INVASION) */ \
/**/
BADCVAR("g_domination_default_teams");
BADCVAR("g_freezetag");
BADCVAR("g_freezetag_teams");
+ BADCVAR("g_gg");
BADCVAR("g_invasion_teams");
BADCVAR("g_invasion_type");
BADCVAR("g_jailbreak");
--- /dev/null
+// Random items mutator config for GunGame gamemode
+
+// This config is not executed by default, you may want to put it inside
+// sv_hook_gamestart_gg in your server.cfg.
+
+// Map items
+
+set g_random_items_health_probability 10 "Probability of random health items spawning in the map."
+set g_random_items_armor_probability 10 "Probability of random armor items spawning in the map."
+set g_random_items_resource_probability 0 "Probability of random resource items spawning in the map."
+set g_random_items_weapon_probability 0 "Probability of random weapons spawning in the map."
+set g_random_items_powerup_probability 1 "Probability of random powerups spawning in the map."
+set g_random_items_item_health_small_probability 10 "Probability of random small health spawning in the map."
+set g_random_items_item_health_medium_probability 4 "Probability of random medium health spawning in the map."
+set g_random_items_item_health_big_probability 2 "Probability of random big health spawning in the map."
+set g_random_items_item_health_mega_probability 1 "Probability of random mega health spawning in the map."
+set g_random_items_item_armor_small_probability 10 "Probability of random small armor spawning in the map."
+set g_random_items_item_armor_medium_probability 4 "Probability of random medium armor spawning in the map."
+set g_random_items_item_armor_big_probability 2 "Probability of random big armor spawning in the map."
+set g_random_items_item_armor_mega_probability 1 "Probability of random mega armor spawning in the map."
+set g_random_items_item_strength_probability 1 "Probability of random strength spawning in the map."
+set g_random_items_item_shield_probability 1 "Probability of random shield spawning in the map."
+set g_random_items_item_fuel_regen_probability 0 "Probability of random fuel regeneration spawning in the map."
+set g_random_items_item_jetpack_probability 0 "Probability of random jetpack spawning in the map."
+
+// Loot
+
+set g_random_loot_min 0 "Minimum amount of loot items."
+set g_random_loot_max 4 "Maximum amount of loot items."
+set g_random_loot_time 10 "Amount of time the loot will stay in seconds."
+set g_random_loot_spread 200 "How far can loot be thrown."
+set g_random_loot_health_probability 8 "Probability of random health items spawning as loot."
+set g_random_loot_armor_probability 8 "Probability of random armor items spawning as loot."
+set g_random_loot_resource_probability 0 "Probability of random ammo items spawning as loot."
+set g_random_loot_weapon_probability 0 "Probability of random weapons spawning as loot."
+set g_random_loot_powerup_probability 1 "Probability of random powerups spawning as loot."
+set g_random_loot_item_health_small_probability 4 "Probability of random small health spawning as loot."
+set g_random_loot_item_health_medium_probability 3 "Probability of random medium health spawning as loot."
+set g_random_loot_item_health_big_probability 2 "Probability of random big health spawning as loot."
+set g_random_loot_item_health_mega_probability 1 "Probability of random mega health spawning as loot."
+set g_random_loot_item_armor_small_probability 4 "Probability of random small armor spawning as loot."
+set g_random_loot_item_armor_medium_probability 3 "Probability of random medium armor spawning as loot."
+set g_random_loot_item_armor_big_probability 2 "Probability of random big armor spawning as loot."
+set g_random_loot_item_armor_mega_probability 1 "Probability of random mega armor spawning as loot."
+set g_random_loot_item_strength_probability 1 "Probability of random strength spawning as loot."
+set g_random_loot_item_shield_probability 1 "Probability of random shield spawning as loot."
+set g_random_loot_item_fuel_regen_probability 0 "Probability of random fuel regeneration spawning as loot."
+set g_random_loot_item_jetpack_probability 0 "Probability of random jetpack spawning as loot."