#include "mapvoting.qh"
-#include "_all.qh"
+#include <server/client.qh>
+#include <common/weapons/_all.qh>
+#include <common/stats.qh>
+#include <server/gamelog.qh>
+#include <server/miscfunctions.qh>
#include "g_world.qh"
#include "command/cmd.qh"
#include "command/getreplies.qh"
#include "../common/constants.qh"
+#include <common/net_linked.qh>
#include "../common/mapinfo.qh"
#include "../common/playerstats.qh"
+#include <common/state.qh>
#include "../common/util.qh"
-float GameTypeVote_AvailabilityStatus(string gtname)
+
+// definitions
+
+float mapvote_nextthink;
+float mapvote_keeptwotime;
+float mapvote_timeout;
+const int MAPVOTE_SCREENSHOT_DIRS_COUNT = 4;
+string mapvote_screenshot_dirs[MAPVOTE_SCREENSHOT_DIRS_COUNT];
+int mapvote_screenshot_dirs_count;
+
+int mapvote_count;
+int mapvote_count_real;
+string mapvote_maps[MAPVOTE_COUNT];
+int mapvote_maps_screenshot_dir[MAPVOTE_COUNT];
+string mapvote_maps_pakfile[MAPVOTE_COUNT];
+bool mapvote_maps_suggested[MAPVOTE_COUNT];
+string mapvote_suggestions[MAPVOTE_COUNT];
+int mapvote_suggestion_ptr;
+int mapvote_voters;
+int mapvote_selections[MAPVOTE_COUNT];
+int mapvote_maps_flags[MAPVOTE_COUNT];
+bool mapvote_run;
+bool mapvote_detail;
+bool mapvote_abstain;
+.int 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
+ */
+Gametype GameTypeVote_Type_FromString(string type_name)
+{
+ Gametype type = MapInfo_Type_FromString(type_name, false);
+ if (type == NULL)
+ type = MapInfo_Type_FromString(cvar_string(
+ strcat("sv_vote_gametype_",type_name,"_type")), false);
+ return type;
+}
+
+int GameTypeVote_AvailabilityStatus(string type_name)
{
- float type = MapInfo_Type_FromString(gtname);
- if( type == 0 )
- return GTV_FORBIDDEN;
+ int flag = GTV_FORBIDDEN;
+
+ Gametype type = MapInfo_Type_FromString(type_name, false);
+ if ( type == NULL )
+ {
+ type = MapInfo_Type_FromString(cvar_string(
+ strcat("sv_vote_gametype_",type_name,"_type")), false);
+ flag |= GTV_CUSTOM;
+ }
+
+ if( type == NULL )
+ return flag;
if ( autocvar_nextmap != "" )
{
- if ( !MapInfo_Get_ByName(autocvar_nextmap, false, 0) )
- return GTV_FORBIDDEN;
- if (!(MapInfo_Map_supportedGametypes & type))
- return GTV_FORBIDDEN;
+ if ( !MapInfo_Get_ByName(autocvar_nextmap, false, NULL) )
+ return flag;
+ if (!(MapInfo_Map_supportedGametypes & type.m_flags))
+ return flag;
}
- return GTV_AVAILABLE;
+ return flag | GTV_AVAILABLE;
}
-float GameTypeVote_GetMask()
+int GameTypeVote_GetMask()
{
- float n, j, gametype_mask;
+ int n, j, gametype_mask;
n = tokenizebyseparator(autocvar_sv_vote_gametype_options, " ");
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)).m_flags;
return gametype_mask;
}
if ( autocvar_sv_vote_gametype )
{
MapInfo_Enumerate();
- MapInfo_FilterGametype(GameTypeVote_GetMask(), 0, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
+ _MapInfo_FilterGametype(GameTypeVote_GetMask(), 0, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
}
return MapInfo_FixName(m);
}
void MapVote_ClearAllVotes()
{
- FOR_EACH_CLIENT(other)
- other.mapvote = 0;
+ FOREACH_CLIENT(true, { it.mapvote = 0; });
}
void MapVote_UnzoneStrings()
{
- float j;
- for(j = 0; j < mapvote_count; ++j)
+ for(int j = 0; j < mapvote_count; ++j)
{
- if ( mapvote_maps[j] )
- {
- strunzone(mapvote_maps[j]);
- mapvote_maps[j] = string_null;
- }
- if ( mapvote_maps_pakfile[j] )
- {
- strunzone(mapvote_maps_pakfile[j]);
- mapvote_maps_pakfile[j] = string_null;
- }
+ strfree(mapvote_maps[j]);
+ strfree(mapvote_maps_pakfile[j]);
}
}
-string MapVote_Suggest(string m)
+string MapVote_Suggest(entity this, string m)
{
- float i;
+ int i;
if(m == "")
return "That's not how to use this command.";
if(!autocvar_g_maplist_votable_suggestions)
strunzone(mapvote_suggestions[i]);
mapvote_suggestions[i] = strzone(m);
if(autocvar_sv_eventlog)
- GameLogEcho(strcat(":vote:suggested:", m, ":", ftos(self.playerid)));
+ GameLogEcho(strcat(":vote:suggested:", m, ":", ftos(this.playerid)));
return strcat("Suggestion of ", m, " accepted.");
}
-void MapVote_AddVotable(string nextMap, float isSuggestion)
+void MapVote_AddVotable(string nextMap, bool isSuggestion)
{
- float j, i, o;
+ int j, i, o;
string pakfile, mapfile;
if(nextMap == "")
pakfile = string_null;
for(i = 0; i < mapvote_screenshot_dirs_count; ++i)
{
- mapfile = strcat(mapvote_screenshot_dirs[i], "/", mapvote_maps[i]);
+ mapfile = strcat(mapvote_screenshot_dirs[i], "/", nextMap);
pakfile = whichpack(strcat(mapfile, ".tga"));
if(pakfile == "")
pakfile = whichpack(strcat(mapfile, ".jpg"));
}
if(i >= mapvote_screenshot_dirs_count)
i = 0; // FIXME maybe network this error case, as that means there is no mapshot on the server?
- for(o = strstr(pakfile, "/", 0)+1; o > 0; o = strstr(pakfile, "/", 0)+1)
+ for(o = strstrofs(pakfile, "/", 0)+1; o > 0; o = strstrofs(pakfile, "/", 0)+1)
pakfile = substring(pakfile, o, -1);
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;
}
void MapVote_Init()
{
- float i;
- float nmax, smax;
+ int i;
+ int nmax, smax;
MapVote_ClearAllVotes();
MapVote_UnzoneStrings();
mapvote_count = 0;
mapvote_detail = !autocvar_g_maplist_votable_nodetail;
- mapvote_abstain = autocvar_g_maplist_votable_abstain;
+ mapvote_abstain = boolean(autocvar_g_maplist_votable_abstain);
if(mapvote_abstain)
nmax = min(MAPVOTE_COUNT - 1, autocvar_g_maplist_votable);
mapvote_count_real = mapvote_count;
if(mapvote_abstain)
- MapVote_AddVotable("don't care", 0);
+ MapVote_AddVotable("don't care", false);
//dprint("mapvote count is ", ftos(mapvote_count), "\n");
mapvote_timeout = time + autocvar_g_maplist_votable_timeout;
if(mapvote_count_real < 3 || mapvote_keeptwotime <= time)
mapvote_keeptwotime = 0;
- mapvote_message = "Choose a map and press its key!";
MapVote_Spawn();
}
-void MapVote_SendPicture(float id)
+void MapVote_SendPicture(entity to, int id)
{
- msg_entity = self;
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_PICTURE);
+ msg_entity = to;
+ WriteHeader(MSG_ONE, TE_CSQC_PICTURE);
WriteByte(MSG_ONE, id);
WritePicture(MSG_ONE, strcat(mapvote_screenshot_dirs[mapvote_maps_screenshot_dir[id]], "/", mapvote_maps[id]), 3072);
}
void MapVote_WriteMask()
{
- float i;
if ( mapvote_count < 24 )
{
- float mask,power;
- mask = 0;
- for(i = 0, power = 1; i < mapvote_count; ++i, power *= 2)
- if(mapvote_maps_availability[i] == GTV_AVAILABLE )
- mask |= power;
+ int mask = 0;
+ for(int j = 0; j < mapvote_count; ++j)
+ {
+ if(mapvote_maps_flags[j] & GTV_AVAILABLE)
+ mask |= BIT(j);
+ }
if(mapvote_count < 8)
WriteByte(MSG_ENTITY, mask);
}
else
{
- for ( i = 0; i < mapvote_count; ++i )
- WriteByte(MSG_ENTITY, mapvote_maps_availability[i]);
+ for (int j = 0; j < mapvote_count; ++j)
+ WriteByte(MSG_ENTITY, mapvote_maps_flags[j]);
+ }
+}
+
+/*
+ * 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")));
+ WriteString(MSG_ENTITY, cvar_string(
+ strcat("sv_vote_gametype_",type_name,"_type")));
+ }
}
}
-float MapVote_SendEntity(entity to, int sf)
+bool MapVote_SendEntity(entity this, entity to, int sf)
{
- float i;
+ int i;
if(sf & 1)
sf &= ~2; // if we send 1, we don't need to also send 2
- WriteByte(MSG_ENTITY, ENT_CLIENT_MAPVOTE);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_MAPVOTE);
WriteByte(MSG_ENTITY, sf);
if(sf & 1)
}
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()));
}
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);
}
}
{
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);
mapvote_ent.SendFlags |= 4;
}
-float MapVote_Finished(float mappos)
+bool MapVote_Finished(int mappos)
{
if(alreadychangedlevel)
return false;
string result;
- float i;
- float didntvote;
+ int i;
+ int didntvote;
if(autocvar_sv_eventlog)
{
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)
GameLogEcho(strcat(":vote:suggestion_accepted:", mapvote_maps[mappos]));
}
- FOR_EACH_REALCLIENT(other)
- FixClientCvars(other);
+ FOREACH_CLIENT(IS_REAL_CLIENT(it), { FixClientCvars(it); });
if(gametypevote)
{
void MapVote_CheckRules_1()
{
- float i;
-
- for(i = 0; i < mapvote_count; ++i)
- if( mapvote_maps_availability[i] == GTV_AVAILABLE )
+ for (int 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;
}
mapvote_voters = 0;
- FOR_EACH_REALCLIENT(other)
- {
+ FOREACH_CLIENT(IS_REAL_CLIENT(it), {
++mapvote_voters;
- if(other.mapvote)
+ if (it.mapvote)
{
- i = other.mapvote - 1;
- //dprint("Player ", other.netname, " vote = ", ftos(other.mapvote - 1), "\n");
- mapvote_selections[i] = mapvote_selections[i] + 1;
+ int idx = it.mapvote - 1;
+ //dprint("Player ", it.netname, " vote = ", ftos(idx), "\n");
+ ++mapvote_selections[idx];
}
- }
+ });
}
-float MapVote_CheckRules_2()
+bool MapVote_CheckRules_2()
{
- float i;
- float firstPlace, secondPlace, currentPlace;
- float firstPlaceVotes, secondPlaceVotes, currentVotes;
- float mapvote_voters_real;
+ int i;
+ int firstPlace, secondPlace, currentPlace;
+ int firstPlaceVotes, secondPlaceVotes, currentVotes;
+ int mapvote_voters_real;
string result;
if(mapvote_count_real == 1)
currentPlace = 0;
currentVotes = -1;
for(i = 0; i < mapvote_count_real; ++i)
- if ( mapvote_maps_availability[i] == GTV_AVAILABLE )
+ if ( mapvote_maps_flags[i] & GTV_AVAILABLE )
{
- RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
+ RandomSelection_AddFloat(i, 1, mapvote_selections[i]);
if ( gametypevote && mapvote_maps[i] == MapInfo_Type_ToString(MapInfo_CurrentGametype()) )
{
currentVotes = mapvote_selections[i];
}
}
firstPlaceVotes = RandomSelection_best_priority;
- if ( autocvar_sv_vote_gametype_default_current && currentVotes == firstPlaceVotes )
+ if ( autocvar_sv_vote_gametype_default_current && firstPlaceVotes == 0 )
firstPlace = currentPlace;
else
firstPlace = RandomSelection_chosen_float;
RandomSelection_Init();
for(i = 0; i < mapvote_count_real; ++i)
if(i != firstPlace)
- if ( mapvote_maps_availability[i] == GTV_AVAILABLE )
- RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
+ if ( mapvote_maps_flags[i] & GTV_AVAILABLE )
+ RandomSelection_AddFloat(i, 1, mapvote_selections[i]);
secondPlace = RandomSelection_chosen_float;
secondPlaceVotes = RandomSelection_best_priority;
//dprint("Second place: ", ftos(secondPlace), "\n");
if(mapvote_keeptwotime)
if(time > mapvote_keeptwotime || (mapvote_voters_real - firstPlaceVotes - secondPlaceVotes) < secondPlaceVotes)
{
- float didntvote;
MapVote_TouchMask();
- mapvote_message = "Now decide between the TOP TWO!";
mapvote_keeptwotime = 0;
result = strcat(":vote:keeptwo:", mapvote_maps[firstPlace]);
result = strcat(result, ":", ftos(firstPlaceVotes));
result = strcat(result, ":", mapvote_maps[secondPlace]);
result = strcat(result, ":", ftos(secondPlaceVotes), "::");
- didntvote = mapvote_voters;
+ int didntvote = mapvote_voters;
for(i = 0; i < mapvote_count; ++i)
{
didntvote -= mapvote_selections[i];
result = strcat(result, ":", ftos(mapvote_selections[i]));
if(i < mapvote_count_real)
{
- mapvote_maps_availability[i] = GTV_FORBIDDEN;
+ mapvote_maps_flags[i] &= ~GTV_AVAILABLE;
}
}
}
void MapVote_Tick()
{
- float keeptwo;
- float totalvotes;
- keeptwo = mapvote_keeptwotime;
MapVote_CheckRules_1(); // count
if(MapVote_CheckRules_2()) // decide
return;
- totalvotes = 0;
- FOR_EACH_REALCLIENT(other)
- {
+ int totalvotes = 0;
+ FOREACH_CLIENT(IS_REAL_CLIENT(it), {
// hide scoreboard again
- if(other.health != 2342)
+ if(GetResource(it, RES_HEALTH) != 2342)
{
- other.health = 2342;
- other.impulse = 0;
- if(IS_REAL_CLIENT(other))
- {
- msg_entity = other;
- WriteByte(MSG_ONE, SVC_FINALE);
- WriteString(MSG_ONE, "");
- }
+ SetResourceExplicit(it, RES_HEALTH, 2342);
+ CS(it).impulse = 0;
+
+ msg_entity = it;
+ WriteByte(MSG_ONE, SVC_FINALE);
+ WriteString(MSG_ONE, "");
}
// clear possibly invalid votes
- if ( mapvote_maps_availability[other.mapvote-1] != GTV_AVAILABLE )
- other.mapvote = 0;
+ if ( !(mapvote_maps_flags[it.mapvote-1] & GTV_AVAILABLE) )
+ it.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(CS(it).impulse >= 1 && CS(it).impulse <= mapvote_count)
+ if( mapvote_maps_flags[CS(it).impulse - 1] & GTV_AVAILABLE )
{
- other.mapvote = other.impulse;
- MapVote_TouchVotes(other);
+ it.mapvote = CS(it).impulse;
+ MapVote_TouchVotes(it);
}
- other.impulse = 0;
+ CS(it).impulse = 0;
- if(other.mapvote)
+ if(it.mapvote)
++totalvotes;
- }
+ });
MapVote_CheckRules_1(); // just count
}
MapVote_Tick();
}
-float GameTypeVote_SetGametype(float type)
+bool GameTypeVote_SetGametype(Gametype type)
{
if (MapInfo_CurrentGametype() == type)
return true;
- float tsave = MapInfo_CurrentGametype();
+ Gametype tsave = MapInfo_CurrentGametype();
MapInfo_SwitchGameType(type);
return true;
}
-float gametypevote_finished;
-float GameTypeVote_Finished(float pos)
+bool gametypevote_finished;
+bool GameTypeVote_Finished(int pos)
{
if(!gametypevote || gametypevote_finished)
return false;
- if ( !GameTypeVote_SetGametype(MapInfo_Type_FromString(mapvote_maps[pos])) )
- {
- dprint("Selected gametype is not supported by any map");
- }
-
localcmd("sv_vote_gametype_hook_all\n");
localcmd("sv_vote_gametype_hook_", mapvote_maps[pos], "\n");
+ if ( !GameTypeVote_SetGametype(GameTypeVote_Type_FromString(mapvote_maps[pos])) )
+ {
+ LOG_TRACE("Selected gametype is not supported by any map");
+ }
+
gametypevote_finished = true;
return true;
}
-float GameTypeVote_AddVotable(string nextMode)
+bool GameTypeVote_AddVotable(string nextMode)
{
- float j;
- if ( nextMode == "" || MapInfo_Type_FromString(nextMode) == 0 )
+ if ( nextMode == "" || GameTypeVote_Type_FromString(nextMode) == NULL )
return false;
- for(j = 0; j < mapvote_count; ++j)
+
+ for(int j = 0; j < mapvote_count; ++j)
if(mapvote_maps[j] == nextMode)
return 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;
}
-float GameTypeVote_Start()
+bool GameTypeVote_Start()
{
- float j;
MapVote_ClearAllVotes();
MapVote_UnzoneStrings();
mapvote_count = 0;
mapvote_timeout = time + autocvar_sv_vote_gametype_timeout;
- mapvote_abstain = 0;
+ mapvote_abstain = false;
mapvote_detail = !autocvar_g_maplist_votable_nodetail;
- float n = tokenizebyseparator(autocvar_sv_vote_gametype_options, " ");
+ int n = tokenizebyseparator(autocvar_sv_vote_gametype_options, " ");
n = min(MAPVOTE_COUNT, n);
- float really_available, which_available;
+ int really_available, which_available;
really_available = 0;
which_available = -1;
- for(j = 0; j < n; ++j)
+ for(int 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;