From: Lyberta Date: Thu, 31 Aug 2017 09:03:28 +0000 (+0300) Subject: Started GunGame. X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=7d5adb8641aa15da2f9ad7f4ae8aed27e443790f;p=xonotic%2Fxonotic-data.pk3dir.git Started GunGame. --- diff --git a/gamemodes-server.cfg b/gamemodes-server.cfg index 6790a3b4f..ab3b84b63 100644 --- a/gamemodes-server.cfg +++ b/gamemodes-server.cfg @@ -28,6 +28,7 @@ alias sv_hook_gamestart_cts 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 @@ -47,6 +48,7 @@ alias sv_vote_gametype_hook_cts 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 @@ -196,6 +198,13 @@ set g_inv_respawn_delay_large_count 0 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 // ========= @@ -522,3 +531,9 @@ set g_invasion_spawnpoint_spawn_delay 0.5 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" +set g_gg_weapons "vortex mortar machinegun hagar arc electro devastator crylink shotgun blaster" diff --git a/qcsrc/client/hud/panel/modicons.qc b/qcsrc/client/hud/panel/modicons.qc index 65682b3ec..c63683dc8 100644 --- a/qcsrc/client/hud/panel/modicons.qc +++ b/qcsrc/client/hud/panel/modicons.qc @@ -711,6 +711,38 @@ void HUD_Mod_Dom(vector myPos, vector mySize) } } +void HUD_Mod_GG(vector pos, vector mySize) +{ + mod_active = 1; // required in each mod function that always shows something + int stat_weapon = STAT(GUNGAME_LEADING_WEAPON); + 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); + } + string weapon_pic = string_null; + FOREACH(Weapons, it != WEP_Null, + { + if (it.m_id == stat_weapon) + { + weapon_pic = it.model2; + break; + } + }); + if (!weapon_pic) + { + return; + } + drawpic_aspect_skin(pic_pos, weapon_pic, pic_size, '1 1 1', 1, + DRAWFLAG_NORMAL); +} + void HUD_ModIcons_SetFunc() { HUD_ModIcons_GameType = gametype.m_modicons; diff --git a/qcsrc/common/mapinfo.qh b/qcsrc/common/mapinfo.qh index 2dd84596e..346e4077e 100644 --- a/qcsrc/common/mapinfo.qh +++ b/qcsrc/common/mapinfo.qh @@ -480,6 +480,29 @@ CLASS(Invasion, Gametype) 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")); + } + 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; diff --git a/qcsrc/common/stats.qh b/qcsrc/common/stats.qh index 94e408d7f..8dc351122 100644 --- a/qcsrc/common/stats.qh +++ b/qcsrc/common/stats.qh @@ -281,6 +281,9 @@ REGISTER_STAT(DOM_PPS_BLUE, float) 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) diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index 64aa03b50..b727189d0 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -271,6 +271,7 @@ void cvar_changes_init() 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"); diff --git a/qcsrc/server/mutators/mutator/_mod.inc b/qcsrc/server/mutators/mutator/_mod.inc index 6835f5d56..4645a343d 100644 --- a/qcsrc/server/mutators/mutator/_mod.inc +++ b/qcsrc/server/mutators/mutator/_mod.inc @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/server/mutators/mutator/_mod.qh b/qcsrc/server/mutators/mutator/_mod.qh index aef0b332a..5cc6e55b6 100644 --- a/qcsrc/server/mutators/mutator/_mod.qh +++ b/qcsrc/server/mutators/mutator/_mod.qh @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/server/mutators/mutator/gamemode_gungame.qc b/qcsrc/server/mutators/mutator/gamemode_gungame.qc new file mode 100644 index 000000000..27c62313f --- /dev/null +++ b/qcsrc/server/mutators/mutator/gamemode_gungame.qc @@ -0,0 +1,230 @@ +/// \file +/// \brief Source file that contains implementation of the GunGame gamemode. +/// \author Lyberta +/// \copyright GNU GPLv3 or any later version. + +#include "gamemode_gungame.qh" + +//============================ Constants ====================================== + +const string GUNGAME_WEAPONS = "g_gg_weapons"; + +//======================= Global variables ==================================== + +.int gungame_leading_weapon_stat = _STAT(GUNGAME_LEADING_WEAPON); + +int gungame_maxlevel; ///< Player who reaches this level wins. +string gungame_weapons; ///< Holds weapons corresponding to levels. + +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. +/// \return No return. +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. +/// \return No return. +void GunGame_UpdateStats(); + +//========================= Free functions ==================================== + +void GunGame_Initialize() +{ + GunGame_Reset(); +} + +void GunGame_Reset() +{ + if (gungame_weapons) + { + strunzone(gungame_weapons); + } + gungame_weapons = strzone(cvar_string(GUNGAME_WEAPONS)); + gungame_maxlevel = tokenize_console(gungame_weapons); + if (gungame_maxlevel == 0) + { + error("GunGame: Invalid weapon configuration."); + } + GameRules_limit_score(gungame_maxlevel); + gungame_leading_player = NULL; + gungame_leading_level = 0; + gungame_leading_weapon = GunGame_GetWeapon(0); + GunGame_UpdateStats(); +} + +entity GunGame_GetWeapon(int level) +{ + if (level >= gungame_maxlevel) + { + return NULL; + } + tokenize_console(gungame_weapons); + string weapon = argv(level); + FOREACH(Weapons, it != WEP_Null, + { + if (it.netname == weapon) + { + return it; + } + }); + error("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. +/// \return No return. +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(); + //PrintToChatAll(strcat(gungame_leading_player.netname, + // " is leading with level ", ftos(gungame_leading_level))); +} + +void GunGame_UpdateStats() +{ + FOREACH_CLIENT(IS_REAL_CLIENT(it), + { + it.gungame_leading_weapon_stat = 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. +/// \return No return. +void GunGame_GivePlayerWeapon(entity player) +{ + int level = GunGame_GetPlayerLevel(player); + if (level >= gungame_maxlevel) + { + return; + } + entity weapon = GunGame_GetWeapon(level); + player.weapons |= weapon.m_wepset; + centerprint(player, strcat("^3Level ", ftos(level + 1), ": ^2", + weapon.m_name)); +} + +//============================= Hooks ======================================== + +/// \brief Hook that is called to determine if there is a weapon arena. +MUTATOR_HOOKFUNCTION(gg, SetWeaponArena) +{ + //PrintToChatAll("SetWeaponArena"); + M_ARGV(0, string) = "off"; +} + +/// \brief Hook that is called to determine start items of all players. +MUTATOR_HOOKFUNCTION(gg, SetStartItems) +{ + //PrintToChatAll("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, FilterItem) +{ + //PrintToChatAll("FilterItem"); + entity item = M_ARGV(0, entity); + if (item.itemdef.instanceOfWeaponPickup) + { + // Block weapons from spawning. + 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; + } + player.gungame_leading_weapon_stat = 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); + player.weapons = 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) || (GunGame_GetPlayerLevel( + attacker) >= gungame_maxlevel)) + { + return; + } + attacker.weapons = WEPSET(Null); + GunGame_GivePlayerWeapon(attacker); +} + +/// \brief Hook that determines whether remaining frags are announced. +MUTATOR_HOOKFUNCTION(gg, Scores_CountFragsRemaining) +{ + // announce remaining frags + return true; +} diff --git a/qcsrc/server/mutators/mutator/gamemode_gungame.qh b/qcsrc/server/mutators/mutator/gamemode_gungame.qh new file mode 100644 index 000000000..e36b592a0 --- /dev/null +++ b/qcsrc/server/mutators/mutator/gamemode_gungame.qh @@ -0,0 +1,22 @@ +/// \file +/// \brief Header file that describes the GunGame gamemode. +/// \author Lyberta +/// \copyright GNU GPLv3 or any later version. + +#pragma once + +#include "../gamemode.qh" + +/// \brief Initializes global data for the gametype. +/// \return No return. +void GunGame_Initialize(); + +REGISTER_MUTATOR(gg, false) +{ + MUTATOR_STATIC(); + MUTATOR_ONADD + { + GunGame_Initialize(); + } + return 0; +}