Restart vote improvements, voting localization.
Restart votes now need 80% majority to succeed. Restart votes now have a 3 minute cooldown on the caller. Voting stuff has been localized.
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
<VBoxContainer>
|
<VBoxContainer>
|
||||||
<HBoxContainer>
|
<HBoxContainer>
|
||||||
<MarginContainer MarginLeftOverride="8" HorizontalExpand="True">
|
<MarginContainer MarginLeftOverride="8" HorizontalExpand="True">
|
||||||
<Label Text="{Loc 'Call Vote'}" VAlign="Center" StyleClasses="LabelHeading" />
|
<Label Text="{Loc 'ui-vote-create-title'}" VAlign="Center" StyleClasses="LabelHeading" />
|
||||||
</MarginContainer>
|
</MarginContainer>
|
||||||
<MarginContainer MarginRightOverride="8">
|
<MarginContainer MarginRightOverride="8">
|
||||||
<TextureButton Name="CloseButton" StyleClasses="windowCloseButton"
|
<TextureButton Name="CloseButton" StyleClasses="windowCloseButton"
|
||||||
@@ -27,12 +27,12 @@
|
|||||||
|
|
||||||
<MarginContainer SizeFlagsHorizontal="Fill"
|
<MarginContainer SizeFlagsHorizontal="Fill"
|
||||||
MarginLeftOverride="8" MarginRightOverride="8" MarginBottomOverride="2">
|
MarginLeftOverride="8" MarginRightOverride="8" MarginBottomOverride="2">
|
||||||
<Button Name="CreateButton" Text="{Loc 'Call Vote'}" />
|
<Button Name="CreateButton" Text="{Loc 'ui-vote-create-button'}" />
|
||||||
</MarginContainer>
|
</MarginContainer>
|
||||||
|
|
||||||
<PanelContainer StyleClasses="LowDivider" />
|
<PanelContainer StyleClasses="LowDivider" />
|
||||||
<MarginContainer MarginLeftOverride="12">
|
<MarginContainer MarginLeftOverride="12">
|
||||||
<Label StyleClasses="LabelSubText" Text="{Loc 'Powered by Robust™ Anti-Tamper Technology'}" />
|
<Label StyleClasses="LabelSubText" Text="{Loc 'ui-vote-fluff'}" />
|
||||||
</MarginContainer>
|
</MarginContainer>
|
||||||
|
|
||||||
</VBoxContainer>
|
</VBoxContainer>
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ namespace Content.Client.Voting
|
|||||||
|
|
||||||
public static readonly (string name, string id, (string name, string id)[]? secondaries)[] AvailableVoteTypes =
|
public static readonly (string name, string id, (string name, string id)[]? secondaries)[] AvailableVoteTypes =
|
||||||
{
|
{
|
||||||
("Restart round", "restart", null),
|
("ui-vote-type-restart", "restart", null),
|
||||||
("Next gamemode", "preset", null)
|
("ui-vote-type-gamemode", "preset", null)
|
||||||
};
|
};
|
||||||
|
|
||||||
public VoteCallMenu()
|
public VoteCallMenu()
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Content.Client.Voting
|
|||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
Text = Loc.GetString("Call vote");
|
Text = Loc.GetString("ui-vote-menu-button");
|
||||||
OnPressed += OnOnPressed;
|
OnPressed += OnOnPressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,12 +50,12 @@ namespace Content.Client.Voting
|
|||||||
public void UpdateData()
|
public void UpdateData()
|
||||||
{
|
{
|
||||||
VoteTitle.Text = _vote.Title;
|
VoteTitle.Text = _vote.Title;
|
||||||
VoteCaller.Text = Loc.GetString("{0} called a vote:", _vote.Initiator);
|
VoteCaller.Text = Loc.GetString("ui-vote-created", ("initiator", _vote.Initiator));
|
||||||
|
|
||||||
for (var i = 0; i < _voteButtons.Length; i++)
|
for (var i = 0; i < _voteButtons.Length; i++)
|
||||||
{
|
{
|
||||||
var entry = _vote.Entries[i];
|
var entry = _vote.Entries[i];
|
||||||
_voteButtons[i].Text = Loc.GetString("{0} ({1})", entry.Text, entry.Votes);
|
_voteButtons[i].Text = Loc.GetString("ui-vote-button", ("text", entry.Text), ("votes", entry.Votes));
|
||||||
|
|
||||||
if (_vote.OurVote == i)
|
if (_vote.OurVote == i)
|
||||||
_voteButtons[i].Pressed = true;
|
_voteButtons[i].Pressed = true;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Robust.Server.Player;
|
using System.Collections.Generic;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
|
||||||
namespace Content.Server.Voting
|
namespace Content.Server.Voting
|
||||||
{
|
{
|
||||||
@@ -10,6 +11,8 @@ namespace Content.Server.Voting
|
|||||||
bool Finished { get; }
|
bool Finished { get; }
|
||||||
bool Cancelled { get; }
|
bool Cancelled { get; }
|
||||||
|
|
||||||
|
IReadOnlyDictionary<object, int> VotesPerOption { get; }
|
||||||
|
|
||||||
event VoteFinishedEventHandler OnFinished;
|
event VoteFinishedEventHandler OnFinished;
|
||||||
bool IsValidOption(int optionId);
|
bool IsValidOption(int optionId);
|
||||||
void CastVote(IPlayerSession session, int? optionId);
|
void CastVote(IPlayerSession session, int? optionId);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
@@ -15,15 +16,16 @@ namespace Content.Server.Voting
|
|||||||
var alone = _playerManager.PlayerCount == 1 && initiator != null;
|
var alone = _playerManager.PlayerCount == 1 && initiator != null;
|
||||||
var options = new VoteOptions
|
var options = new VoteOptions
|
||||||
{
|
{
|
||||||
Title = Loc.GetString("Restart round"),
|
Title = Loc.GetString("ui-vote-restart-title"),
|
||||||
Options =
|
Options =
|
||||||
{
|
{
|
||||||
(Loc.GetString("Yes"), true),
|
(Loc.GetString("ui-vote-restart-yes"), true),
|
||||||
(Loc.GetString("No"), false)
|
(Loc.GetString("ui-vote-restart-no"), false)
|
||||||
},
|
},
|
||||||
Duration = alone
|
Duration = alone
|
||||||
? TimeSpan.FromSeconds(10)
|
? TimeSpan.FromSeconds(10)
|
||||||
: TimeSpan.FromSeconds(30)
|
: TimeSpan.FromSeconds(30),
|
||||||
|
InitiatorTimeout = TimeSpan.FromMinutes(3)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (alone)
|
if (alone)
|
||||||
@@ -33,23 +35,22 @@ namespace Content.Server.Voting
|
|||||||
|
|
||||||
var vote = CreateVote(options);
|
var vote = CreateVote(options);
|
||||||
|
|
||||||
vote.OnFinished += (_, args) =>
|
vote.OnFinished += (_, _) =>
|
||||||
{
|
{
|
||||||
if (args.Winner == null)
|
var votesYes = vote.VotesPerOption[true];
|
||||||
{
|
var votesNo = vote.VotesPerOption[false];
|
||||||
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restart vote failed due to tie."));
|
var total = votesYes + votesNo;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var win = (bool) args.Winner;
|
var ratioRequired = _cfg.GetCVar(CCVars.VoteRestartRequiredRatio);
|
||||||
if (win)
|
if (votesYes / (float) total >= ratioRequired)
|
||||||
{
|
{
|
||||||
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restart vote succeeded."));
|
_chatManager.DispatchServerAnnouncement(Loc.GetString("ui-vote-restart-succeeded"));
|
||||||
_ticker.RestartRound();
|
_ticker.RestartRound();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restart vote failed."));
|
_chatManager.DispatchServerAnnouncement(
|
||||||
|
Loc.GetString("ui-vote-restart-failed", ("ratio", ratioRequired)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,16 +65,16 @@ namespace Content.Server.Voting
|
|||||||
{
|
{
|
||||||
var presets = new Dictionary<string, string>
|
var presets = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
["traitor"] = "Traitor",
|
["traitor"] = "mode-traitor",
|
||||||
["extended"] = "Extended",
|
["extended"] = "mode-extended",
|
||||||
["sandbox"] = "Sandbox",
|
["sandbox"] = "mode-sandbox",
|
||||||
["suspicion"] = "Suspicion"
|
["suspicion"] = "mode-suspicion",
|
||||||
};
|
};
|
||||||
|
|
||||||
var alone = _playerManager.PlayerCount == 1 && initiator != null;
|
var alone = _playerManager.PlayerCount == 1 && initiator != null;
|
||||||
var options = new VoteOptions
|
var options = new VoteOptions
|
||||||
{
|
{
|
||||||
Title = Loc.GetString("Next gamemode"),
|
Title = Loc.GetString("ui-vote-gamemode-title"),
|
||||||
Duration = alone
|
Duration = alone
|
||||||
? TimeSpan.FromSeconds(10)
|
? TimeSpan.FromSeconds(10)
|
||||||
: TimeSpan.FromSeconds(30)
|
: TimeSpan.FromSeconds(30)
|
||||||
@@ -98,13 +99,13 @@ namespace Content.Server.Voting
|
|||||||
{
|
{
|
||||||
picked = (string) IoCManager.Resolve<IRobustRandom>().Pick(args.Winners);
|
picked = (string) IoCManager.Resolve<IRobustRandom>().Pick(args.Winners);
|
||||||
_chatManager.DispatchServerAnnouncement(
|
_chatManager.DispatchServerAnnouncement(
|
||||||
Loc.GetString("Tie for gamemode vote! Picking... {0}", Loc.GetString(presets[picked])));
|
Loc.GetString("ui-vote-gamemode-tie", ("picked", Loc.GetString(presets[picked]))));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
picked = (string) args.Winner;
|
picked = (string) args.Winner;
|
||||||
_chatManager.DispatchServerAnnouncement(
|
_chatManager.DispatchServerAnnouncement(
|
||||||
Loc.GetString("{0} won the gamemode vote!", Loc.GetString(presets[picked])));
|
Loc.GetString("ui-vote-gamemode-win", ("winner", Loc.GetString(presets[picked]))));
|
||||||
}
|
}
|
||||||
|
|
||||||
_ticker.SetStartPreset(picked);
|
_ticker.SetStartPreset(picked);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
@@ -10,11 +11,13 @@ using Content.Shared.Administration;
|
|||||||
using Content.Shared.Network.NetMessages;
|
using Content.Shared.Network.NetMessages;
|
||||||
using Content.Shared.Utility;
|
using Content.Shared.Utility;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
@@ -23,6 +26,7 @@ namespace Content.Server.Voting
|
|||||||
public sealed partial class VoteManager : IVoteManager
|
public sealed partial class VoteManager : IVoteManager
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IServerNetManager _netManager = default!;
|
[Dependency] private readonly IServerNetManager _netManager = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
@@ -320,7 +324,7 @@ namespace Content.Server.Voting
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
options.InitiatorText = Loc.GetString("The server");
|
options.InitiatorText = Loc.GetString("ui-vote-initiator-server");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,6 +393,8 @@ namespace Content.Server.Voting
|
|||||||
public bool Finished => _reg.Finished;
|
public bool Finished => _reg.Finished;
|
||||||
public bool Cancelled => _reg.Cancelled;
|
public bool Cancelled => _reg.Cancelled;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<object, int> VotesPerOption { get; }
|
||||||
|
|
||||||
public event VoteFinishedEventHandler? OnFinished
|
public event VoteFinishedEventHandler? OnFinished
|
||||||
{
|
{
|
||||||
add => _reg.OnFinished += value;
|
add => _reg.OnFinished += value;
|
||||||
@@ -405,6 +411,8 @@ namespace Content.Server.Voting
|
|||||||
{
|
{
|
||||||
_mgr = mgr;
|
_mgr = mgr;
|
||||||
_reg = reg;
|
_reg = reg;
|
||||||
|
|
||||||
|
VotesPerOption = new VoteDict(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsValidOption(int optionId)
|
public bool IsValidOption(int optionId)
|
||||||
@@ -421,6 +429,62 @@ namespace Content.Server.Voting
|
|||||||
{
|
{
|
||||||
_mgr.CancelVote(_reg);
|
_mgr.CancelVote(_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class VoteDict : IReadOnlyDictionary<object, int>
|
||||||
|
{
|
||||||
|
private readonly VoteReg _reg;
|
||||||
|
|
||||||
|
public VoteDict(VoteReg reg)
|
||||||
|
{
|
||||||
|
_reg = reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<object, int>> GetEnumerator()
|
||||||
|
{
|
||||||
|
return _reg.Entries.Select(e => KeyValuePair.Create(e.Data, e.Votes)).GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count => _reg.Entries.Length;
|
||||||
|
|
||||||
|
public bool ContainsKey(object key)
|
||||||
|
{
|
||||||
|
return TryGetValue(key, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(object key, out int value)
|
||||||
|
{
|
||||||
|
var entry = _reg.Entries.FirstOrNull(a => a.Data.Equals(key));
|
||||||
|
if (entry != null)
|
||||||
|
{
|
||||||
|
value = entry.Value.Votes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int this[object key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!TryGetValue(key, out var votes))
|
||||||
|
{
|
||||||
|
throw new KeyNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return votes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<object> Keys => _reg.Entries.Select(c => c.Data);
|
||||||
|
public IEnumerable<int> Values => _reg.Entries.Select(c => c.Votes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -275,5 +275,13 @@ namespace Content.Shared
|
|||||||
* Context Menu Grouping Types
|
* Context Menu Grouping Types
|
||||||
*/
|
*/
|
||||||
public static readonly CVarDef<int> ContextMenuGroupingType = CVarDef.Create("context_menu", 0, CVar.CLIENTONLY);
|
public static readonly CVarDef<int> ContextMenuGroupingType = CVarDef.Create("context_menu", 0, CVar.CLIENTONLY);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VOTE
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static readonly CVarDef<float> VoteRestartRequiredRatio =
|
||||||
|
CVarDef.Create("vote.restart_required_ratio", 0.8f, CVar.SERVERONLY);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
Resources/Changelog/Parts/restart_votes.yml
Normal file
4
Resources/Changelog/Parts/restart_votes.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
author: PJB
|
||||||
|
changes:
|
||||||
|
- message: Restart votes now need an 80% majority to succeed, and have a longer cooldown for the caller.
|
||||||
|
type: Tweak
|
||||||
4
Resources/Locale/en-US/gamemodes/modes.ftl
Normal file
4
Resources/Locale/en-US/gamemodes/modes.ftl
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
mode-traitor = Traitor
|
||||||
|
mode-extended = Extended
|
||||||
|
mode-sandbox = Sandbox
|
||||||
|
mode-suspicion = Suspicion
|
||||||
30
Resources/Locale/en-US/ui/voting.ftl
Normal file
30
Resources/Locale/en-US/ui/voting.ftl
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
### Voting menu stuff
|
||||||
|
|
||||||
|
# Displayed as initiator of vote when no user creates the vote
|
||||||
|
ui-vote-initiator-server = The server
|
||||||
|
|
||||||
|
ui-vote-restart-title = Restart round
|
||||||
|
ui-vote-restart-succeeded = Restart vote succeeded.
|
||||||
|
ui-vote-restart-failed = Restart vote failed (need { TOSTRING($ratio, "P0") }).
|
||||||
|
ui-vote-restart-yes = Yes
|
||||||
|
ui-vote-restart-no = No
|
||||||
|
|
||||||
|
ui-vote-gamemode-title = Next gamemode
|
||||||
|
ui-vote-gamemode-tie = Tie for gamemode vote! Picking... { $picked }
|
||||||
|
ui-vote-gamemode-win = { $winner } won the gamemode vote!
|
||||||
|
|
||||||
|
ui-vote-created = { $initiator } has called a vote:
|
||||||
|
ui-vote-button = { $text } ({ $votes })
|
||||||
|
|
||||||
|
ui-vote-type-restart = Restart round
|
||||||
|
ui-vote-type-gamemode = Next gamemode
|
||||||
|
|
||||||
|
# Window title of the vote create menu
|
||||||
|
ui-vote-create-title = Call Vote
|
||||||
|
# Submit button in the vote create button
|
||||||
|
ui-vote-create-button = Call Vote
|
||||||
|
# Hue hue hue
|
||||||
|
ui-vote-fluff = Powered by Robust™ Anti-Tamper Technology
|
||||||
|
|
||||||
|
# Button text in lobby/escape menu
|
||||||
|
ui-vote-menu-button = Call vote
|
||||||
Reference in New Issue
Block a user