X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fmapvoting.qc;h=ac64f630ff1d5181372a33c21fb4e67bde03588a;hp=9242a5b6f4d057aa99e95f356cf80098eb2f6a12;hb=HEAD;hpb=4e21f418ad9e6287efb942c1fa2861a51981110a diff --git a/qcsrc/server/mapvoting.qc b/qcsrc/server/mapvoting.qc index 9242a5b6f..b9d19f611 100644 --- a/qcsrc/server/mapvoting.qc +++ b/qcsrc/server/mapvoting.qc @@ -12,7 +12,6 @@ #include #include #include -#include #include // definitions @@ -48,10 +47,10 @@ entity mapvote_ent; */ Gametype GameTypeVote_Type_FromString(string type_name) { - Gametype type = MapInfo_Type_FromString(type_name, false); + Gametype type = MapInfo_Type_FromString(type_name, false, false); if (type == NULL) type = MapInfo_Type_FromString(cvar_string( - strcat("sv_vote_gametype_",type_name,"_type")), false); + strcat("sv_vote_gametype_",type_name,"_type")), false, false); return type; } @@ -59,11 +58,11 @@ int GameTypeVote_AvailabilityStatus(string type_name) { int flag = GTV_FORBIDDEN; - Gametype type = MapInfo_Type_FromString(type_name, false); + Gametype type = MapInfo_Type_FromString(type_name, false, false); if ( type == NULL ) { type = MapInfo_Type_FromString(cvar_string( - strcat("sv_vote_gametype_",type_name,"_type")), false); + strcat("sv_vote_gametype_",type_name,"_type")), false, false); flag |= GTV_CUSTOM; } @@ -89,6 +88,10 @@ int GameTypeVote_GetMask() gametype_mask = 0; for(j = 0; j < n; ++j) gametype_mask |= GameTypeVote_Type_FromString(argv(j)).m_flags; + + if (gametype_mask == 0) + gametype_mask |= MapInfo_CurrentGametype().m_flags; + return gametype_mask; } @@ -197,9 +200,26 @@ void MapVote_AddVotable(string nextMap, bool isSuggestion) mapvote_count += 1; } +void MapVote_AddVotableMaps(int nmax, int smax) +{ + int available_maps = Maplist_Init(); + int max_attempts = available_maps; + if (available_maps >= 2) + max_attempts = min(available_maps * 5, 100); + + if (smax && mapvote_suggestion_ptr) + for(int i = 0; i < max_attempts && mapvote_count < smax; ++i) + MapVote_AddVotable(mapvote_suggestions[floor(random() * mapvote_suggestion_ptr)], true); + + for (int i = 0; i < max_attempts && mapvote_count < nmax; ++i) + MapVote_AddVotable(GetNextMap(), false); +} + +string voted_gametype_string; +Gametype voted_gametype; +Gametype match_gametype; void MapVote_Init() { - int i; int nmax, smax; MapVote_ClearAllVotes(); @@ -220,26 +240,10 @@ void MapVote_Init() if(mapvote_screenshot_dirs_count == 0) mapvote_screenshot_dirs_count = tokenize_console("maps levelshots"); mapvote_screenshot_dirs_count = min(mapvote_screenshot_dirs_count, MAPVOTE_SCREENSHOT_DIRS_COUNT); - for(i = 0; i < mapvote_screenshot_dirs_count; ++i) + for(int i = 0; i < mapvote_screenshot_dirs_count; ++i) mapvote_screenshot_dirs[i] = strzone(argv(i)); - if(mapvote_suggestion_ptr) - for(i = 0; i < 100 && mapvote_count < smax; ++i) - MapVote_AddVotable(mapvote_suggestions[floor(random() * mapvote_suggestion_ptr)], true); - - for(i = 0; i < 100 && mapvote_count < nmax; ++i) - MapVote_AddVotable(GetNextMap(), false); - - if(mapvote_count == 0) - { - bprint( "Maplist contains no single playable map! Resetting it to default map list.\n" ); - cvar_set("g_maplist", MapInfo_ListAllowedMaps(MapInfo_CurrentGametype(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags())); - if(autocvar_g_maplist_shuffle) - ShuffleMaplist(); - localcmd("\nmenu_cmd sync\n"); - for(i = 0; i < 100 && mapvote_count < nmax; ++i) - MapVote_AddVotable(GetNextMap(), false); - } + MapVote_AddVotableMaps(nmax, smax); mapvote_count_real = mapvote_count; if(mapvote_abstain) @@ -253,6 +257,16 @@ void MapVote_Init() mapvote_keeptwotime = 0; MapVote_Spawn(); + + // If match_gametype is set it means voted_gametype has just been applied (on game type vote end). + // In this case apply back match_gametype here so that the "restart" command, if called, + // properly restarts the map applying the current game type. + // Applying voted_gametype before map vote start is needed to properly initialize map vote. + string gametype_custom_string = ""; + if (gametype_custom_enabled) + gametype_custom_string = loaded_gametype_custom_string; + if (match_gametype) + GameTypeVote_SetGametype(match_gametype, gametype_custom_string, true); } void MapVote_SendPicture(entity to, int id) @@ -337,6 +351,8 @@ void GameTypeVote_SendOption(int i) } } +int mapvote_winner; +float mapvote_winner_time; bool MapVote_SendEntity(entity this, entity to, int sf) { int i; @@ -344,6 +360,9 @@ bool MapVote_SendEntity(entity this, entity to, int sf) if(sf & 1) sf &= ~2; // if we send 1, we don't need to also send 2 + if (!mapvote_winner_time) + sf &= ~8; // no winner yet + WriteHeader(MSG_ENTITY, ENT_CLIENT_MAPVOTE); WriteByte(MSG_ENTITY, sf); @@ -361,14 +380,19 @@ bool MapVote_SendEntity(entity this, entity to, int sf) if ( gametypevote ) { // gametype vote - WriteByte(MSG_ENTITY, 1); + WriteByte(MSG_ENTITY, BIT(0)); // gametypevote_flags WriteString(MSG_ENTITY, autocvar_nextmap); } else if ( autocvar_sv_vote_gametype ) { // map vote but gametype has been chosen via voting screen - WriteByte(MSG_ENTITY, 2); - WriteString(MSG_ENTITY, MapInfo_Type_ToText(MapInfo_CurrentGametype())); + WriteByte(MSG_ENTITY, BIT(1)); // gametypevote_flags + string voted_gametype_name; + if (voted_gametype_string == MapInfo_Type_ToString(voted_gametype)) + voted_gametype_name = MapInfo_Type_ToText(voted_gametype); + else + voted_gametype_name = cvar_string(strcat("sv_vote_gametype_", voted_gametype_string, "_name")); + WriteString(MSG_ENTITY, voted_gametype_name); } else WriteByte(MSG_ENTITY, 0); // map vote @@ -401,6 +425,11 @@ bool MapVote_SendEntity(entity this, entity to, int sf) WriteByte(MSG_ENTITY, to.mapvote); } + if(sf & 8) + { + WriteByte(MSG_ENTITY, mapvote_winner + 1); + } + return true; } @@ -419,6 +448,13 @@ void MapVote_TouchVotes(entity voter) mapvote_ent.SendFlags |= 4; } +void MapVote_Winner(int mappos) +{ + mapvote_ent.SendFlags |= 8; + mapvote_winner_time = time; + mapvote_winner = mappos; +} + bool MapVote_Finished(int mappos) { if(alreadychangedlevel) @@ -462,6 +498,7 @@ bool MapVote_Finished(int mappos) Map_Goto_SetStr(autocvar_nextmap); Map_Goto(0); alreadychangedlevel = true; + strfree(voted_gametype_string); return true; } else @@ -470,8 +507,7 @@ bool MapVote_Finished(int mappos) return false; } - Map_Goto_SetStr(mapvote_maps[mappos]); - Map_Goto(0); + MapVote_Winner(mappos); alreadychangedlevel = true; return true; @@ -516,18 +552,23 @@ bool MapVote_CheckRules_2() RandomSelection_Init(); currentPlace = 0; currentVotes = -1; + string current_gametype_string; + if (gametype_custom_enabled) + current_gametype_string = loaded_gametype_custom_string; + else + current_gametype_string = MapInfo_Type_ToString(MapInfo_CurrentGametype()); for(i = 0; i < mapvote_count_real; ++i) if ( mapvote_maps_flags[i] & GTV_AVAILABLE ) { RandomSelection_AddFloat(i, 1, mapvote_selections[i]); - if ( gametypevote && mapvote_maps[i] == MapInfo_Type_ToString(MapInfo_CurrentGametype()) ) + if ( gametypevote && mapvote_maps[i] == current_gametype_string ) { currentVotes = mapvote_selections[i]; currentPlace = i; } } firstPlaceVotes = RandomSelection_best_priority; - if ( autocvar_sv_vote_gametype_default_current && firstPlaceVotes == 0 ) + if (gametypevote && autocvar_sv_vote_gametype_default_current && firstPlaceVotes == 0) firstPlace = currentPlace; else firstPlace = RandomSelection_chosen_float; @@ -548,8 +589,12 @@ bool MapVote_CheckRules_2() if(firstPlace == -1) error("No first place in map vote... WTF?"); - if(secondPlace == -1 || time > mapvote_timeout || (mapvote_voters_real - firstPlaceVotes) < firstPlaceVotes) + if(secondPlace == -1 || time > mapvote_timeout + || (mapvote_voters_real - firstPlaceVotes) < firstPlaceVotes + || mapvote_selections[mapvote_count - 1] == mapvote_voters) + { return MapVote_Finished(firstPlace); + } if(mapvote_keeptwotime) if(time > mapvote_keeptwotime || (mapvote_voters_real - firstPlaceVotes - secondPlaceVotes) < secondPlaceVotes) @@ -585,7 +630,6 @@ bool MapVote_CheckRules_2() void MapVote_Tick() { - MapVote_CheckRules_1(); // count if(MapVote_CheckRules_2()) // decide return; @@ -647,6 +691,25 @@ void MapVote_Think() if(!mapvote_run) return; + if (mapvote_winner_time) + { + if (time > mapvote_winner_time + 1) + { + if (voted_gametype) + { + // clear match_gametype so that GameTypeVote_SetGametype + // prints the game type switch message + match_gametype = NULL; + GameTypeVote_SetGametype(voted_gametype, voted_gametype_string, true); + } + + Map_Goto_SetStr(mapvote_maps[mapvote_winner]); + Map_Goto(0); + strfree(voted_gametype_string); + } + return; + } + if(alreadychangedlevel) return; @@ -655,6 +718,8 @@ void MapVote_Think() //dprint("tick\n"); mapvote_nextthink = time + 0.5; + if (mapvote_nextthink > mapvote_timeout - 0.1) // make sure there's no delay when map vote times out + mapvote_nextthink = mapvote_timeout + 0.001; if(!mapvote_initialized) { @@ -694,8 +759,25 @@ void MapVote_Think() MapVote_Tick(); } -bool GameTypeVote_SetGametype(Gametype type) +// if gametype_string is "" then gametype_string is inferred from Gametype type +// otherwise gametype_string is the string (short name) of a custom gametype +bool GameTypeVote_SetGametype(Gametype type, string gametype_string, bool call_hooks) { + if (!call_hooks) + { + // custom gametype is disabled because gametype hooks can't be executed + gametype_custom_enabled = false; + } + else + { + if (gametype_string == "") + gametype_string = MapInfo_Type_ToString(type); + gametype_custom_enabled = (gametype_string != MapInfo_Type_ToString(type)); + + localcmd("sv_vote_gametype_hook_all\n"); + localcmd("sv_vote_gametype_hook_", gametype_string, "\n"); + } + if (MapInfo_CurrentGametype() == type) return true; @@ -710,7 +792,9 @@ bool GameTypeVote_SetGametype(Gametype type) // update lsmaps in case the gametype changed, this way people can easily list maps for it if(lsmaps_reply != "") { strunzone(lsmaps_reply); } lsmaps_reply = strzone(getlsmaps()); - bprint("Game type successfully switched to ", MapInfo_Type_ToString(type), "\n"); + + if (!match_gametype) // don't show this msg if we are temporarily switching game type + bprint("Game type successfully switched to ", MapInfo_Type_ToString(type), "\n"); } else { @@ -720,11 +804,7 @@ bool GameTypeVote_SetGametype(Gametype type) return false; } - //localcmd("gametype ", MapInfo_Type_ToString(type), "\n"); - cvar_set("g_maplist", MapInfo_ListAllowedMaps(type, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()) ); - if(autocvar_g_maplist_shuffle) - ShuffleMaplist(); return true; } @@ -735,13 +815,16 @@ bool GameTypeVote_Finished(int pos) if(!gametypevote || gametypevote_finished) return false; - localcmd("sv_vote_gametype_hook_all\n"); - localcmd("sv_vote_gametype_hook_", mapvote_maps[pos], "\n"); + match_gametype = MapInfo_CurrentGametype(); + voted_gametype = GameTypeVote_Type_FromString(mapvote_maps[pos]); + strcpy(voted_gametype_string, mapvote_maps[pos]); - if ( !GameTypeVote_SetGametype(GameTypeVote_Type_FromString(mapvote_maps[pos])) ) - { - LOG_TRACE("Selected gametype is not supported by any map"); - } + GameTypeVote_SetGametype(voted_gametype, voted_gametype_string, true); + + // save to a cvar so it can be applied back when gametype is temporary + // changed on gametype vote end of the next game + if (mapvote_maps_flags[pos] & GTV_CUSTOM) + cvar_set("_sv_vote_gametype_custom", voted_gametype_string); gametypevote_finished = true; @@ -798,13 +881,18 @@ bool GameTypeVote_Start() mapvote_count_real = mapvote_count; - gametypevote = 1; + gametypevote = true; if ( really_available == 0 ) { if ( mapvote_count > 0 ) strunzone(mapvote_maps[0]); - mapvote_maps[0] = strzone(MapInfo_Type_ToString(MapInfo_CurrentGametype())); + string current_gametype_string; + if (gametype_custom_enabled) + current_gametype_string = loaded_gametype_custom_string; + else + current_gametype_string = MapInfo_Type_ToString(MapInfo_CurrentGametype()); + mapvote_maps[0] = strzone(current_gametype_string); //GameTypeVote_Finished(0); MapVote_Finished(0); return false;