]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/mapvoting.qc
Merge branch 'TimePath/hudpanels_registry' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mapvoting.qc
index 9a2cb1871706d7cb40978ac6a805ef05b093ee7f..a8e027df1e1769187e919842d46bac97e1c2005a 100644 (file)
@@ -1,18 +1,80 @@
-float GameTypeVote_AvailabilityStatus(string gtname) 
-{ 
-       float type = MapInfo_Type_FromString(gtname);
+#include "mapvoting.qh"
+#include "_all.qh"
+
+#include "g_world.qh"
+#include "command/cmd.qh"
+#include "command/getreplies.qh"
+#include "../common/constants.qh"
+#include "../common/mapinfo.qh"
+#include "../common/playerstats.qh"
+#include "../common/util.qh"
+
+
+// definitions
+
+float mapvote_nextthink;
+float mapvote_keeptwotime;
+float mapvote_timeout;
+string mapvote_message;
+const float MAPVOTE_SCREENSHOT_DIRS_COUNT = 4;
+string mapvote_screenshot_dirs[MAPVOTE_SCREENSHOT_DIRS_COUNT];
+float mapvote_screenshot_dirs_count;
+
+float mapvote_count;
+float mapvote_count_real;
+string mapvote_maps[MAPVOTE_COUNT];
+float mapvote_maps_screenshot_dir[MAPVOTE_COUNT];
+string mapvote_maps_pakfile[MAPVOTE_COUNT];
+float mapvote_maps_suggested[MAPVOTE_COUNT];
+string mapvote_suggestions[MAPVOTE_COUNT];
+float mapvote_suggestion_ptr;
+float mapvote_voters;
+float mapvote_selections[MAPVOTE_COUNT];
+float mapvote_maps_flags[MAPVOTE_COUNT];
+float mapvote_run;
+float mapvote_detail;
+float mapvote_abstain;
+.float mapvote;
+
+entity mapvote_ent;
+
+/**
+ * Returns the gamtype ID from its name, if type_name isn't a real gametype it
+ * checks for sv_vote_gametype_(type_name)_type
+ */
+float GameTypeVote_Type_FromString(string type_name)
+{
+       float type = MapInfo_Type_FromString(type_name);
+       if ( type == 0 )
+               type = MapInfo_Type_FromString(cvar_string(
+                       strcat("sv_vote_gametype_",type_name,"_type")));
+       return type;
+}
+
+int GameTypeVote_AvailabilityStatus(string type_name)
+{
+       int flag = GTV_FORBIDDEN;
+
+       float type = MapInfo_Type_FromString(type_name);
+       if ( type == 0 )
+       {
+               type = MapInfo_Type_FromString(cvar_string(
+                       strcat("sv_vote_gametype_",type_name,"_type")));
+               flag |= GTV_CUSTOM;
+       }
+
        if( type == 0 )
-               return GTV_FORBIDDEN;
-       
+               return flag;
+
        if ( autocvar_nextmap != "" )
        {
-               if ( !MapInfo_Get_ByName(autocvar_nextmap, FALSE, 0) )
-                       return GTV_FORBIDDEN;
+               if ( !MapInfo_Get_ByName(autocvar_nextmap, false, 0) )
+                       return flag;
                if (!(MapInfo_Map_supportedGametypes & type))
-                       return GTV_FORBIDDEN;
+                       return flag;
        }
-       
-       return GTV_AVAILABLE;
+
+       return flag | GTV_AVAILABLE;
 }
 
 float GameTypeVote_GetMask()
@@ -22,7 +84,7 @@ float GameTypeVote_GetMask()
        n = min(MAPVOTE_COUNT, n);
        gametype_mask = 0;
        for(j = 0; j < n; ++j)
-               gametype_mask |= MapInfo_Type_FromString(argv(j));
+               gametype_mask |= GameTypeVote_Type_FromString(argv(j));
        return gametype_mask;
 }
 
@@ -61,7 +123,7 @@ void MapVote_UnzoneStrings()
 }
 
 string MapVote_Suggest(string m)
-{
+{SELFPARAM();
        float i;
        if(m == "")
                return "That's not how to use this command.";
@@ -136,7 +198,7 @@ void MapVote_AddVotable(string nextMap, float isSuggestion)
 
        mapvote_maps_screenshot_dir[mapvote_count] = i;
        mapvote_maps_pakfile[mapvote_count] = strzone(pakfile);
-       mapvote_maps_availability[mapvote_count] = GTV_AVAILABLE;
+       mapvote_maps_flags[mapvote_count] = GTV_AVAILABLE;
 
        mapvote_count += 1;
 }
@@ -169,10 +231,10 @@ void MapVote_Init()
 
        if(mapvote_suggestion_ptr)
                for(i = 0; i < 100 && mapvote_count < smax; ++i)
-                       MapVote_AddVotable(mapvote_suggestions[floor(random() * mapvote_suggestion_ptr)], TRUE);
+                       MapVote_AddVotable(mapvote_suggestions[floor(random() * mapvote_suggestion_ptr)], true);
 
        for(i = 0; i < 100 && mapvote_count < nmax; ++i)
-               MapVote_AddVotable(GetNextMap(), FALSE);
+               MapVote_AddVotable(GetNextMap(), false);
 
        if(mapvote_count == 0)
        {
@@ -182,7 +244,7 @@ void MapVote_Init()
                        ShuffleMaplist();
                localcmd("\nmenu_cmd sync\n");
                for(i = 0; i < 100 && mapvote_count < nmax; ++i)
-                       MapVote_AddVotable(GetNextMap(), FALSE);
+                       MapVote_AddVotable(GetNextMap(), false);
        }
 
        mapvote_count_real = mapvote_count;
@@ -201,7 +263,7 @@ void MapVote_Init()
 }
 
 void MapVote_SendPicture(float id)
-{
+{SELFPARAM();
        msg_entity = self;
        WriteByte(MSG_ONE, SVC_TEMPENTITY);
        WriteByte(MSG_ONE, TE_CSQC_PICTURE);
@@ -218,9 +280,9 @@ void MapVote_WriteMask()
                float mask,power;
                mask = 0;
                for(i = 0, power = 1; i < mapvote_count; ++i, power *= 2)
-                       if(mapvote_maps_availability[i] == GTV_AVAILABLE )
+                       if(mapvote_maps_flags[i] & GTV_AVAILABLE )
                                mask |= power;
-                       
+
                if(mapvote_count < 8)
                        WriteByte(MSG_ENTITY, mask);
                else if (mapvote_count < 16)
@@ -231,11 +293,57 @@ void MapVote_WriteMask()
        else
        {
                for ( i = 0; i < mapvote_count; ++i )
-                       WriteByte(MSG_ENTITY, mapvote_maps_availability[i]);
+                       WriteByte(MSG_ENTITY, mapvote_maps_flags[i]);
        }
 }
 
-float MapVote_SendEntity(entity to, float sf)
+/*
+ * Sends a single map vote option to the client
+ */
+void MapVote_SendOption(int i)
+{
+       // abstain
+       if(mapvote_abstain && i == mapvote_count - 1)
+       {
+               WriteString(MSG_ENTITY, ""); // abstain needs no text
+               WriteString(MSG_ENTITY, ""); // abstain needs no pack
+               WriteByte(MSG_ENTITY, 0); // abstain needs no screenshot dir
+       }
+       else
+       {
+               WriteString(MSG_ENTITY, mapvote_maps[i]);
+               WriteString(MSG_ENTITY, mapvote_maps_pakfile[i]);
+               WriteByte(MSG_ENTITY, mapvote_maps_screenshot_dir[i]);
+       }
+}
+
+/*
+ * Sends a single gametype vote option to the client
+ */
+void GameTypeVote_SendOption(int i)
+{
+       // abstain
+       if(mapvote_abstain && i == mapvote_count - 1)
+       {
+               WriteString(MSG_ENTITY, ""); // abstain needs no text
+               WriteByte(MSG_ENTITY, GTV_AVAILABLE);
+       }
+       else
+       {
+               string type_name = mapvote_maps[i];
+               WriteString(MSG_ENTITY, type_name);
+               WriteByte(MSG_ENTITY, mapvote_maps_flags[i]);
+               if ( mapvote_maps_flags[i] & GTV_CUSTOM )
+               {
+                       WriteString(MSG_ENTITY, cvar_string(
+                               strcat("sv_vote_gametype_",type_name,"_name")));
+                       WriteString(MSG_ENTITY, cvar_string(
+                               strcat("sv_vote_gametype_",type_name,"_description")));
+               }
+       }
+}
+
+bool MapVote_SendEntity(entity this, entity to, int sf)
 {
        float i;
 
@@ -255,7 +363,7 @@ float MapVote_SendEntity(entity to, float sf)
                WriteByte(MSG_ENTITY, mapvote_abstain);
                WriteByte(MSG_ENTITY, mapvote_detail);
                WriteCoord(MSG_ENTITY, mapvote_timeout);
-               
+
                if ( gametypevote )
                {
                        // gametype vote
@@ -264,7 +372,7 @@ float MapVote_SendEntity(entity to, float sf)
                }
                else if ( autocvar_sv_vote_gametype )
                {
-                        // map vote but gametype has been chosen via voting screen
+                       // map vote but gametype has been chosen via voting screen
                        WriteByte(MSG_ENTITY, 2);
                        WriteString(MSG_ENTITY, MapInfo_Type_ToText(MapInfo_CurrentGametype()));
                }
@@ -273,22 +381,13 @@ float MapVote_SendEntity(entity to, float sf)
 
                MapVote_WriteMask();
 
+               // Send data for the vote options
                for(i = 0; i < mapvote_count; ++i)
                {
-                       if(mapvote_abstain && i == mapvote_count - 1)
-                       {
-                               WriteString(MSG_ENTITY, ""); // abstain needs no text
-                               WriteString(MSG_ENTITY, ""); // abstain needs no pack
-                               WriteByte(MSG_ENTITY, 0); // abstain needs no screenshot dir
-                               WriteByte(MSG_ENTITY, GTV_AVAILABLE);
-                       }
+                       if(gametypevote)
+                               GameTypeVote_SendOption(i);
                        else
-                       {
-                               WriteString(MSG_ENTITY, mapvote_maps[i]);
-                               WriteString(MSG_ENTITY, mapvote_maps_pakfile[i]);
-                               WriteByte(MSG_ENTITY, mapvote_maps_screenshot_dir[i]);
-                               WriteByte(MSG_ENTITY, mapvote_maps_availability[i]);
-                       }
+                               MapVote_SendOption(i);
                }
        }
 
@@ -302,18 +401,18 @@ float MapVote_SendEntity(entity to, float sf)
        {
                if(mapvote_detail)
                        for(i = 0; i < mapvote_count; ++i)
-                               if ( mapvote_maps_availability[i] == GTV_AVAILABLE )
+                               if ( mapvote_maps_flags[i] & GTV_AVAILABLE )
                                        WriteByte(MSG_ENTITY, mapvote_selections[i]);
 
                WriteByte(MSG_ENTITY, to.mapvote);
        }
 
-       return TRUE;
+       return true;
 }
 
 void MapVote_Spawn()
 {
-       Net_LinkEntity(mapvote_ent = spawn(), FALSE, 0, MapVote_SendEntity);
+       Net_LinkEntity(mapvote_ent = spawn(), false, 0, MapVote_SendEntity);
 }
 
 void MapVote_TouchMask()
@@ -329,7 +428,7 @@ void MapVote_TouchVotes(entity voter)
 float MapVote_Finished(float mappos)
 {
        if(alreadychangedlevel)
-               return FALSE;
+               return false;
 
        string result;
        float i;
@@ -341,7 +440,7 @@ float MapVote_Finished(float mappos)
                result = strcat(result, ":", ftos(mapvote_selections[mappos]), "::");
                didntvote = mapvote_voters;
                for(i = 0; i < mapvote_count; ++i)
-                       if(mapvote_maps_availability[i] == GTV_AVAILABLE )
+                       if(mapvote_maps_flags[i] & GTV_AVAILABLE )
                        {
                                didntvote -= mapvote_selections[i];
                                if(i != mappos)
@@ -364,33 +463,33 @@ float MapVote_Finished(float mappos)
        {
                if ( GameTypeVote_Finished(mappos) )
                {
-                       gametypevote = FALSE;
+                       gametypevote = false;
                        if(autocvar_nextmap != "")
                        {
                                Map_Goto_SetStr(autocvar_nextmap);
                                Map_Goto(0);
-                               alreadychangedlevel = TRUE;
-                               return TRUE;
+                               alreadychangedlevel = true;
+                               return true;
                        }
                        else
                                MapVote_Init();
                }
-               return FALSE;
+               return false;
        }
-       
+
        Map_Goto_SetStr(mapvote_maps[mappos]);
        Map_Goto(0);
-       alreadychangedlevel = TRUE;
-       
-       return TRUE;
+       alreadychangedlevel = true;
+
+       return true;
 }
 
 void MapVote_CheckRules_1()
 {
        float i;
 
-       for(i = 0; i < mapvote_count; ++i) 
-               if( mapvote_maps_availability[i] == GTV_AVAILABLE )
+       for(i = 0; i < mapvote_count; ++i)
+               if( mapvote_maps_flags[i] & GTV_AVAILABLE )
                {
                        //dprint("Map ", ftos(i), ": "); dprint(mapvote_maps[i], "\n");
                        mapvote_selections[i] = 0;
@@ -427,8 +526,8 @@ float MapVote_CheckRules_2()
        RandomSelection_Init();
        currentPlace = 0;
        currentVotes = -1;
-       for(i = 0; i < mapvote_count_real; ++i) 
-               if ( mapvote_maps_availability[i] == GTV_AVAILABLE )
+       for(i = 0; i < mapvote_count_real; ++i)
+               if ( mapvote_maps_flags[i] & GTV_AVAILABLE )
                {
                        RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
                        if ( gametypevote &&  mapvote_maps[i] == MapInfo_Type_ToString(MapInfo_CurrentGametype()) )
@@ -442,14 +541,14 @@ float MapVote_CheckRules_2()
                firstPlace = currentPlace;
        else
                firstPlace = RandomSelection_chosen_float;
-       
+
        //dprint("First place: ", ftos(firstPlace), "\n");
        //dprint("First place votes: ", ftos(firstPlaceVotes), "\n");
 
        RandomSelection_Init();
        for(i = 0; i < mapvote_count_real; ++i)
                if(i != firstPlace)
-               if ( mapvote_maps_availability[i] == GTV_AVAILABLE )
+               if ( mapvote_maps_flags[i] & GTV_AVAILABLE )
                        RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
        secondPlace = RandomSelection_chosen_float;
        secondPlaceVotes = RandomSelection_best_priority;
@@ -484,7 +583,7 @@ float MapVote_CheckRules_2()
                                                result = strcat(result, ":", ftos(mapvote_selections[i]));
                                                if(i < mapvote_count_real)
                                                {
-                                                       mapvote_maps_availability[i] = GTV_FORBIDDEN;
+                                                       mapvote_maps_flags[i] &= ~GTV_AVAILABLE;
                                                }
                                        }
                        }
@@ -493,7 +592,7 @@ float MapVote_CheckRules_2()
                                GameLogEcho(result);
                }
 
-       return FALSE;
+       return false;
 }
 
 void MapVote_Tick()
@@ -523,11 +622,11 @@ void MapVote_Tick()
                }
 
                // clear possibly invalid votes
-               if ( mapvote_maps_availability[other.mapvote-1] != GTV_AVAILABLE )
+               if ( !(mapvote_maps_flags[other.mapvote-1] & GTV_AVAILABLE) )
                        other.mapvote = 0;
                // use impulses as new vote
                if(other.impulse >= 1 && other.impulse <= mapvote_count)
-                       if( mapvote_maps_availability[other.impulse - 1] == GTV_AVAILABLE )
+                       if( mapvote_maps_flags[other.impulse - 1] & GTV_AVAILABLE )
                        {
                                other.mapvote = other.impulse;
                                MapVote_TouchVotes(other);
@@ -551,7 +650,7 @@ void MapVote_Start()
 
        MapInfo_Enumerate();
        if(MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1))
-               mapvote_run = TRUE;
+               mapvote_run = true;
 }
 
 void MapVote_Think()
@@ -590,7 +689,7 @@ void MapVote_Think()
                        cvar_set("rescan_pending", "0");
                }
 
-               mapvote_initialized = TRUE;
+               mapvote_initialized = true;
                if(DoNextMapOverride(0))
                        return;
                if(!autocvar_g_maplist_votable || player_count <= 0)
@@ -598,7 +697,7 @@ void MapVote_Think()
                        GotoNextMap(0);
                        return;
                }
-               
+
                if(autocvar_sv_vote_gametype) { GameTypeVote_Start(); }
                else if(autocvar_nextmap == "") { MapVote_Init(); }
        }
@@ -609,8 +708,8 @@ void MapVote_Think()
 float GameTypeVote_SetGametype(float type)
 {
        if (MapInfo_CurrentGametype() == type)
-               return TRUE;
-               
+               return true;
+
        float tsave = MapInfo_CurrentGametype();
 
        MapInfo_SwitchGameType(type);
@@ -629,7 +728,7 @@ float GameTypeVote_SetGametype(float type)
                bprint("Cannot use this game type: no map for it found\n");
                MapInfo_SwitchGameType(tsave);
                MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
-               return FALSE;
+               return false;
        }
 
        //localcmd("gametype ", MapInfo_Type_ToString(type), "\n");
@@ -638,48 +737,48 @@ float GameTypeVote_SetGametype(float type)
        if(autocvar_g_maplist_shuffle)
                ShuffleMaplist();
 
-       return TRUE;
+       return true;
 }
 
 float gametypevote_finished;
 float GameTypeVote_Finished(float pos)
 {
        if(!gametypevote || gametypevote_finished)
-               return FALSE;
-       
-       if ( !GameTypeVote_SetGametype(MapInfo_Type_FromString(mapvote_maps[pos])) )
+               return false;
+
+       if ( !GameTypeVote_SetGametype(GameTypeVote_Type_FromString(mapvote_maps[pos])) )
        {
-               dprint("Selected gametype is not supported by any map");
+               LOG_TRACE("Selected gametype is not supported by any map");
        }
-       
+
        localcmd("sv_vote_gametype_hook_all\n");
        localcmd("sv_vote_gametype_hook_", mapvote_maps[pos], "\n");
-       
-       gametypevote_finished = TRUE;
-       
-       return TRUE;
+
+       gametypevote_finished = true;
+
+       return true;
 }
 
 float GameTypeVote_AddVotable(string nextMode)
 {
        float j;
-       if ( nextMode == "" || MapInfo_Type_FromString(nextMode) == 0 )
-               return FALSE;
+       if ( nextMode == "" || GameTypeVote_Type_FromString(nextMode) == 0 )
+               return false;
        for(j = 0; j < mapvote_count; ++j)
                if(mapvote_maps[j] == nextMode)
-                       return FALSE;
-       
+                       return false;
+
        mapvote_maps[mapvote_count] = strzone(nextMode);
-       mapvote_maps_suggested[mapvote_count] = FALSE;
+       mapvote_maps_suggested[mapvote_count] = false;
 
        mapvote_maps_screenshot_dir[mapvote_count] = 0;
        mapvote_maps_pakfile[mapvote_count] = strzone("");
-       mapvote_maps_availability[mapvote_count] = GameTypeVote_AvailabilityStatus(nextMode);
+       mapvote_maps_flags[mapvote_count] = GameTypeVote_AvailabilityStatus(nextMode);
 
        mapvote_count += 1;
-       
-       return TRUE;
-       
+
+       return true;
+
 }
 
 float GameTypeVote_Start()
@@ -687,22 +786,22 @@ float GameTypeVote_Start()
        float j;
        MapVote_ClearAllVotes();
        MapVote_UnzoneStrings();
-       
+
        mapvote_count = 0;
        mapvote_timeout = time + autocvar_sv_vote_gametype_timeout;
        mapvote_abstain = 0;
        mapvote_detail = !autocvar_g_maplist_votable_nodetail;
-       
+
        float n = tokenizebyseparator(autocvar_sv_vote_gametype_options, " ");
        n = min(MAPVOTE_COUNT, n);
-       
+
        float really_available, which_available;
        really_available = 0;
        which_available = -1;
        for(j = 0; j < n; ++j)
        {
                if ( GameTypeVote_AddVotable(argv(j)) )
-               if ( mapvote_maps_availability[j] == GTV_AVAILABLE )
+               if ( mapvote_maps_flags[j] & GTV_AVAILABLE )
                {
                        really_available++;
                        which_available = j;
@@ -710,9 +809,9 @@ float GameTypeVote_Start()
        }
 
        mapvote_count_real = mapvote_count;
-       
+
        gametypevote = 1;
-       
+
        if ( really_available == 0 )
        {
                if ( mapvote_count > 0 )
@@ -720,22 +819,22 @@ float GameTypeVote_Start()
                mapvote_maps[0] = strzone(MapInfo_Type_ToString(MapInfo_CurrentGametype()));
                //GameTypeVote_Finished(0);
                MapVote_Finished(0);
-               return FALSE;
+               return false;
        }
        if ( really_available == 1 )
        {
                //GameTypeVote_Finished(which_available);
                MapVote_Finished(which_available);
-               return FALSE;
+               return false;
        }
-       
+
        mapvote_count_real = mapvote_count;
 
        mapvote_keeptwotime = time + autocvar_sv_vote_gametype_keeptwotime;
        if(mapvote_count_real < 3 || mapvote_keeptwotime <= time)
                mapvote_keeptwotime = 0;
-       
+
        MapVote_Spawn();
-       
-       return TRUE;
+
+       return true;
 }