]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Add Manhunt gamemode: Hunters go in search of the runners
authorLegendaryGuard <rootuser999@gmail.com>
Fri, 22 Oct 2021 23:56:56 +0000 (01:56 +0200)
committerLegendaryGuard <rootuser999@gmail.com>
Fri, 22 Oct 2021 23:56:56 +0000 (01:56 +0200)
14 files changed:
gamemodes-client.cfg
gamemodes-server.cfg
qcsrc/common/gamemodes/gamemode/_mod.inc
qcsrc/common/gamemodes/gamemode/_mod.qh
qcsrc/common/gamemodes/gamemode/mh/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mh/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mh/cl_mh.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mh/cl_mh.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mh/mh.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mh/mh.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mh/sv_mh.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mh/sv_mh.qh [new file with mode: 0644]
qcsrc/menu/xonotic/util.qc
qcsrc/server/world.qc

index c43b9d1d3f2e6fe73fddbb33e8489670350edc4d..4a632e7d6d6da162e2a252cb3adc6564b0d197cb 100644 (file)
@@ -32,6 +32,7 @@ alias cl_hook_gamestart_ka
 alias cl_hook_gamestart_ft
 alias cl_hook_gamestart_inv
 alias cl_hook_gamestart_duel
+alias cl_hook_gamestart_mh
 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
index 17b90c624fde8f8af9a50534ad5e69fae6e27ead..8dcc0a87532b1d0b5f4c45ea4f28aa7c564ee81f 100644 (file)
@@ -29,6 +29,7 @@ alias sv_hook_gamestart_ka
 alias sv_hook_gamestart_ft
 alias sv_hook_gamestart_inv
 alias sv_hook_gamestart_duel
+alias sv_hook_gamestart_mh
 // there is currently no hook for when the match is restarted
 // see sv_hook_readyrestart for previous uses of this hook
 //alias sv_hook_gamerestart
@@ -58,6 +59,7 @@ alias sv_vote_gametype_hook_ons
 alias sv_vote_gametype_hook_rc
 alias sv_vote_gametype_hook_tdm
 alias sv_vote_gametype_hook_duel
+alias sv_vote_gametype_hook_mh
 
 // Example preset to allow 1v1ctf to be used for the gametype voting screen.
 // Aliases can have max 31 chars so the gametype can have max 9 chars.
@@ -208,6 +210,13 @@ 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_mh_respawn_delay_small 0
+set g_mh_respawn_delay_small_count 0
+set g_mh_respawn_delay_large 0
+set g_mh_respawn_delay_large_count 0
+set g_mh_respawn_delay_max 0
+set g_mh_respawn_waves 0
+set g_mh_weapon_stay 0
 
 
 // =========
@@ -559,3 +568,17 @@ set g_duel 0 "Duel: frag the opponent more in a one versus one arena battle"
 //set g_duel_warmup 180 "Have a short warmup period before beginning the actual duel"
 set g_duel_with_powerups 0 "Enable powerups to spawn in the duel gamemode"
 set g_duel_not_dm_maps 0 "when this is set, DM maps will NOT be listed in duel"
+
+// =========
+//  manhunt
+// =========
+set g_mh 0 "Manhunt: Hunters go in search of the runners"
+set g_mh_not_dm_maps 0 "when this is set, DM maps will NOT be listed in MH"
+set g_mh_not_lms_maps 0 "when this is set, LMS maps will NOT be listed in MH"
+
+// TODO: change this?
+set g_mh_teams 2 "how many teams are in team deathmatch (set by mapinfo)"
+set g_mh_team_spawns 0 "when 1, players spawn from the team spawnpoints of the map, if any"
+set g_mh_teams_override 0      "how many teams are in manhunt"
+set g_mh_point_limit -1 "MH point limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
+set g_mh_point_leadlimit -1 "MH point lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
index a33ec87a01a34a5a8406f57aa3c3d52829cf3994..4f539ba30b99e268f93f09df10b0b004b0123c0d 100644 (file)
@@ -12,6 +12,7 @@
 #include <common/gamemodes/gamemode/keepaway/_mod.inc>
 #include <common/gamemodes/gamemode/keyhunt/_mod.inc>
 #include <common/gamemodes/gamemode/lms/_mod.inc>
+#include <common/gamemodes/gamemode/mh/_mod.inc>
 #include <common/gamemodes/gamemode/nexball/_mod.inc>
 #include <common/gamemodes/gamemode/onslaught/_mod.inc>
 #include <common/gamemodes/gamemode/race/_mod.inc>
index ffd71d59d3f1092453b6d83f8048003693dfa531..43f7c4a952f97fc1d892929f4253c9a5a616ca90 100644 (file)
@@ -12,6 +12,7 @@
 #include <common/gamemodes/gamemode/keepaway/_mod.qh>
 #include <common/gamemodes/gamemode/keyhunt/_mod.qh>
 #include <common/gamemodes/gamemode/lms/_mod.qh>
+#include <common/gamemodes/gamemode/mh/_mod.qh>
 #include <common/gamemodes/gamemode/nexball/_mod.qh>
 #include <common/gamemodes/gamemode/onslaught/_mod.qh>
 #include <common/gamemodes/gamemode/race/_mod.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/mh/_mod.inc b/qcsrc/common/gamemodes/gamemode/mh/_mod.inc
new file mode 100644 (file)
index 0000000..c711415
--- /dev/null
@@ -0,0 +1,8 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/mh/mh.qc>
+#ifdef CSQC
+    #include <common/gamemodes/gamemode/mh/cl_mh.qc>
+#endif
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/mh/sv_mh.qc>
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/mh/_mod.qh b/qcsrc/common/gamemodes/gamemode/mh/_mod.qh
new file mode 100644 (file)
index 0000000..019427c
--- /dev/null
@@ -0,0 +1,8 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/mh/mh.qh>
+#ifdef CSQC
+    #include <common/gamemodes/gamemode/mh/cl_mh.qh>
+#endif
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/mh/sv_mh.qh>
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/mh/cl_mh.qc b/qcsrc/common/gamemodes/gamemode/mh/cl_mh.qc
new file mode 100644 (file)
index 0000000..db54ce2
--- /dev/null
@@ -0,0 +1,83 @@
+#include "cl_mh.qh"
+
+#include <client/draw.qh>
+
+// TODO: change this?
+
+void HUD_Mod_MH_Export(int fh)
+{
+       HUD_Write_Cvar("hud_panel_modicons_mh_layout");
+}
+
+void DrawMHItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
+{
+       TC(int, layout); TC(int, i);
+       int stat = -1;
+       string pic = "";
+       vector color = '0 0 0';
+       switch(i)
+       {
+               case 0: stat = STAT(REDALIVE); pic = "player_red"; color = '1 0 0'; break;
+               case 1: stat = STAT(BLUEALIVE); pic = "player_blue"; color = '0 0 1'; break;
+               case 2: stat = STAT(YELLOWALIVE); pic = "player_yellow"; color = '1 1 0'; break;
+               default:
+               case 3: stat = STAT(PINKALIVE); pic = "player_pink"; color = '1 0 1'; break;
+       }
+
+       if(mySize.x/mySize.y > aspect_ratio)
+       {
+               i = aspect_ratio * mySize.y;
+               myPos.x = myPos.x + (mySize.x - i) / 2;
+               mySize.x = i;
+       }
+       else
+       {
+               i = 1/aspect_ratio * mySize.x;
+               myPos.y = myPos.y + (mySize.y - i) / 2;
+               mySize.y = i;
+       }
+
+       if(layout)
+       {
+               drawpic_aspect_skin(myPos, pic, vec2(0.5 * mySize.x, mySize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(myPos + eX * 0.5 * mySize.x, ftos(stat), vec2(0.5 * mySize.x, mySize.y), color, panel_fg_alpha, DRAWFLAG_NORMAL);
+       }
+       else
+               drawstring_aspect(myPos, ftos(stat), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+void HUD_Mod_MH_Draw(vector myPos, vector mySize, int layout)
+{
+       int rows, columns;
+       float aspect_ratio;
+       aspect_ratio = (layout) ? 2 : 1;
+       rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
+       columns = ceil(team_count/rows);
+
+       int i;
+       float row = 0, column = 0;
+       vector pos = '0 0 0', itemSize;
+       itemSize = vec2(mySize.x / columns, mySize.y / rows);
+       for(i=0; i<team_count; ++i)
+       {
+               pos.x = myPos.x + column * itemSize.x;
+               pos.y = myPos.y + row * itemSize.y;
+
+               DrawMHItem(pos, itemSize, aspect_ratio, layout, i);
+
+               ++row;
+               if(row >= rows)
+               {
+                       row = 0;
+                       ++column;
+               }
+       }
+}
+
+// Clan Arena and Freeze Tag HUD modicons
+void HUD_Mod_MH(vector myPos, vector mySize)
+{
+       mod_active = 1; // required in each mod function that always shows something
+
+       HUD_Mod_MH_Draw(myPos, mySize, autocvar_hud_panel_modicons_mh_layout);
+}
diff --git a/qcsrc/common/gamemodes/gamemode/mh/cl_mh.qh b/qcsrc/common/gamemodes/gamemode/mh/cl_mh.qh
new file mode 100644 (file)
index 0000000..b198d4f
--- /dev/null
@@ -0,0 +1,7 @@
+#pragma once
+
+int autocvar_hud_panel_modicons_mh_layout;
+
+void HUD_Mod_MH(vector myPos, vector mySize);
+void HUD_Mod_MH_Draw(vector myPos, vector mySize, int layout);
+void HUD_Mod_MH_Export(int fh);
diff --git a/qcsrc/common/gamemodes/gamemode/mh/mh.qc b/qcsrc/common/gamemodes/gamemode/mh/mh.qc
new file mode 100644 (file)
index 0000000..601967f
--- /dev/null
@@ -0,0 +1 @@
+#include "mh.qh"
diff --git a/qcsrc/common/gamemodes/gamemode/mh/mh.qh b/qcsrc/common/gamemodes/gamemode/mh/mh.qh
new file mode 100644 (file)
index 0000000..abbb8c2
--- /dev/null
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <common/mapinfo.qh>
+
+#ifdef CSQC
+void HUD_Mod_MH(vector pos, vector mySize);
+void HUD_Mod_MH_Export(int fh);
+#endif
+CLASS(Manhunt, Gametype)
+    INIT(Manhunt)
+    {
+        this.gametype_init(this, _("Manhunt"),"mh","g_mh",GAMETYPE_FLAG_TEAMPLAY | GAMETYPE_FLAG_USEPOINTS | GAMETYPE_FLAG_PRIORITY,"","timelimit=15 pointlimit=10 teams=2 leadlimit=0",_("Help your team score the most frags against the enemy team"));
+    }
+    METHOD(Manhunt, m_parse_mapinfo, bool(string k, string v))
+    {
+        if (!k) {
+            cvar_set("g_mh_teams", cvar_defstring("g_mh_teams"));
+            return true;
+        }
+        switch (k) {
+            case "teams":
+                cvar_set("g_mh_teams", v);
+                return true;
+        }
+        return false;
+    }
+    METHOD(Manhunt, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+    {
+        if(spawnpoints >= 8 && diameter > 4096)
+            return true;
+        return false;
+    }
+    METHOD(Manhunt, m_isForcedSupported, bool(Gametype this))
+    {
+        if(!cvar("g_mh_not_dm_maps"))
+        {
+            // if this is unset, all DM maps support MMM too
+            if(!(MapInfo_Map_supportedGametypes & this.m_flags) && (MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DEATHMATCH.m_flags))
+                return true; // TODO: references another gametype (alternatively, we could check which gamemodes are always enabled and append this if any are supported)
+        }
+
+        return false;
+    }
+    METHOD(Manhunt, m_setTeams, void(string sa))
+    {
+        cvar_set("g_mh_teams", sa);
+    }
+    METHOD(Manhunt, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+    {
+        TC(Gametype, this);
+        returns(menu, _("Point limit:"),     5,  100,  5, "g_mh_point_limit",         "g_mh_teams_override",         _("The amount of points needed before the match will end"));
+    }
+    ATTRIB(Manhunt, m_legacydefaults, string, "50 20 2 0");
+ENDCLASS(Manhunt)
+REGISTER_GAMETYPE(MANHUNT, NEW(Manhunt));
+#define g_mh IS_GAMETYPE(MANHUNT)
diff --git a/qcsrc/common/gamemodes/gamemode/mh/sv_mh.qc b/qcsrc/common/gamemodes/gamemode/mh/sv_mh.qc
new file mode 100644 (file)
index 0000000..65771d8
--- /dev/null
@@ -0,0 +1,64 @@
+#include "sv_mh.qh"
+
+// TODO: change this?
+int autocvar_g_mh_teams;
+int autocvar_g_mh_teams_override;
+
+spawnfunc(mh_team)
+{
+       if(!g_mh || !this.cnt) { delete(this); return; }
+
+       this.team = this.cnt + 1;
+}
+
+// code from here on is just to support maps that don't have team entities
+void mh_SpawnTeam (string teamname, int teamcolor)
+{
+       entity this = new_pure(mh_team);
+       this.netname = teamname;
+       this.cnt = teamcolor - 1;
+       this.team = teamcolor;
+       this.spawnfunc_checked = true;
+       //spawnfunc_mh_team(this);
+}
+
+void mh_DelayedInit(entity this)
+{
+       // TODO: change this?
+
+       // if no teams are found, spawn defaults
+       if(find(NULL, classname, "mh_team") == NULL)
+       {
+               LOG_TRACE("No \"mh_team\" entities found on this map, creating them anyway.");
+
+               int numteams = autocvar_g_mh_teams_override;
+               if(numteams < 2) { numteams = autocvar_g_mh_teams; }
+
+               int teams = BITS(bound(2, numteams, 2));
+               if(teams & BIT(0))
+                       mh_SpawnTeam("Red", NUM_TEAM_1);
+               if(teams & BIT(1))
+                       mh_SpawnTeam("Blue", NUM_TEAM_2);
+       }
+}
+
+void mh_Initialize()
+{
+       GameRules_teams(true);
+       GameRules_spawning_teams(autocvar_g_mh_team_spawns);
+       GameRules_limit_score(autocvar_g_mh_point_limit);
+       GameRules_limit_lead(autocvar_g_mh_point_leadlimit);
+
+       InitializeEntity(NULL, mh_DelayedInit, INITPRIO_GAMETYPE);
+}
+
+MUTATOR_HOOKFUNCTION(mh, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+{
+       M_ARGV(1, string) = "mh_team";
+}
+
+MUTATOR_HOOKFUNCTION(mh, Scores_CountFragsRemaining)
+{
+       // announce remaining frags
+       return true;
+}
diff --git a/qcsrc/common/gamemodes/gamemode/mh/sv_mh.qh b/qcsrc/common/gamemodes/gamemode/mh/sv_mh.qh
new file mode 100644 (file)
index 0000000..4dcdafc
--- /dev/null
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <common/mutators/base.qh>
+
+// TODO: change this?
+int autocvar_g_mh_point_limit;
+int autocvar_g_mh_point_leadlimit;
+bool autocvar_g_mh_team_spawns;
+void mh_Initialize();
+
+REGISTER_MUTATOR(mh, false)
+{
+    MUTATOR_STATIC();
+       MUTATOR_ONADD
+       {
+               mh_Initialize();
+       }
+       return 0;
+}
index e77049d200153e9c2f15fb0ca097edd1c1649fe3..d3203fb65f5222372a6557e2d9d08ad77d1e5153 100644 (file)
@@ -681,6 +681,7 @@ float updateCompression()
        GAMETYPE(MAPINFO_TYPE_NEXBALL) \
        GAMETYPE(MAPINFO_TYPE_ONSLAUGHT) \
        GAMETYPE(MAPINFO_TYPE_ASSAULT) \
+       GAMETYPE(MAPINFO_TYPE_MANHUNT) \
        /* GAMETYPE(MAPINFO_TYPE_DUEL) */ \
        /* GAMETYPE(MAPINFO_TYPE_INVASION) */ \
        /**/
index 02c059ea808c0d00ab4c3113c5fccb9e1249990a..f85591a9d9fc55d853f23572c6995e623e1d10ab 100644 (file)
@@ -287,6 +287,8 @@ void cvar_changes_init()
                BADCVAR("g_keyhunt");
                BADCVAR("g_keyhunt_teams");
                BADCVAR("g_lms");
+               BADCVAR("g_mh");
+               BADCVAR("g_mh_not_dm_maps");
                BADCVAR("g_nexball");
                BADCVAR("g_onslaught");
                BADCVAR("g_race");