]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Started GunGame.
authorLyberta <lyberta@lyberta.net>
Thu, 31 Aug 2017 09:03:28 +0000 (12:03 +0300)
committerLyberta <lyberta@lyberta.net>
Thu, 31 Aug 2017 09:03:28 +0000 (12:03 +0300)
gamemodes-server.cfg
qcsrc/client/hud/panel/modicons.qc
qcsrc/common/mapinfo.qh
qcsrc/common/stats.qh
qcsrc/server/g_world.qc
qcsrc/server/mutators/mutator/_mod.inc
qcsrc/server/mutators/mutator/_mod.qh
qcsrc/server/mutators/mutator/gamemode_gungame.qc [new file with mode: 0644]
qcsrc/server/mutators/mutator/gamemode_gungame.qh [new file with mode: 0644]

index 6790a3b4fb9575ab91e070c57bc984ac97609ba2..ab3b84b63e97407044269ca763f06f8ecd73e5db 100644 (file)
@@ -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"
index 65682b3ec7d27006a653449ad69e7b725ba69516..c63683dc805fd444649754408ebf969fd48d3cc8 100644 (file)
@@ -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;
index 2dd84596e46991e8f3f75daeb63b524273825d01..346e4077e39390796ed5c188d7f06de6a377f5c5 100644 (file)
@@ -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;
index 94e408d7f614be2d769fc229625a390bfd357ba0..8dc351122867c070dcd45ab8a4a681311d8931e1 100644 (file)
@@ -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)
 
index 64aa03b5026d5b62f0e24df6fc731389a8b637e9..b727189d04062a38c3cb0be1acaca4ed99a7f75d 100644 (file)
@@ -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");
index 6835f5d560b9a325a96e671c21ec17348915ff2a..4645a343d6f1adae08ced7d9012a00a9570975cf 100644 (file)
@@ -6,6 +6,7 @@
 #include <server/mutators/mutator/gamemode_deathmatch.qc>
 #include <server/mutators/mutator/gamemode_domination.qc>
 #include <server/mutators/mutator/gamemode_freezetag.qc>
+#include <server/mutators/mutator/gamemode_gungame.qc>
 #include <server/mutators/mutator/gamemode_invasion.qc>
 #include <server/mutators/mutator/gamemode_keepaway.qc>
 #include <server/mutators/mutator/gamemode_keyhunt.qc>
index aef0b332abbaa9a3c5c27560d3e0bcca21297005..5cc6e55b6282c5a00745e070493419ee397b542d 100644 (file)
@@ -6,6 +6,7 @@
 #include <server/mutators/mutator/gamemode_deathmatch.qh>
 #include <server/mutators/mutator/gamemode_domination.qh>
 #include <server/mutators/mutator/gamemode_freezetag.qh>
+#include <server/mutators/mutator/gamemode_gungame.qh>
 #include <server/mutators/mutator/gamemode_invasion.qh>
 #include <server/mutators/mutator/gamemode_keepaway.qh>
 #include <server/mutators/mutator/gamemode_keyhunt.qh>
diff --git a/qcsrc/server/mutators/mutator/gamemode_gungame.qc b/qcsrc/server/mutators/mutator/gamemode_gungame.qc
new file mode 100644 (file)
index 0000000..27c6231
--- /dev/null
@@ -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 (file)
index 0000000..e36b592
--- /dev/null
@@ -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;
+}