220 lines
7.8 KiB
Ucode
220 lines
7.8 KiB
Ucode
/**
|
|
* Author: dkanus
|
|
* Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore
|
|
* License: GPL
|
|
* Copyright 2023 Anton Tarasenko
|
|
*------------------------------------------------------------------------------
|
|
* This file is part of Acedia.
|
|
*
|
|
* Acedia is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Acedia is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
class ACommandVote extends Command
|
|
dependson(CommandAPI)
|
|
dependson(VotingModel);
|
|
|
|
var private CommandDataBuilder dataBuilder;
|
|
|
|
protected function Constructor() {
|
|
ResetVotingInfo();
|
|
_.commands.OnVotingAdded(self).connect = AddVotingInfo;
|
|
_.commands.OnVotingRemoved(self).connect = HandleRemovedVoting;
|
|
_.chat.OnVoiceMessage(self).connect = VoteWithVoice;
|
|
}
|
|
|
|
protected function Finalizer() {
|
|
super.Finalizer();
|
|
_.memory.Free(dataBuilder);
|
|
dataBuilder = none;
|
|
_.commands.OnVotingAdded(self).Disconnect();
|
|
_.commands.OnVotingRemoved(self).Disconnect();
|
|
_.chat.OnVoiceMessage(self).Disconnect();
|
|
}
|
|
|
|
protected function BuildData(CommandDataBuilder builder) {
|
|
builder.Group(P("core"));
|
|
builder.Summary(P("Allows players to initiate any available voting."
|
|
@ "Voting options themselves are specified as sub-commands."));
|
|
builder.Describe(P("Default command simply displaces information about current vote."));
|
|
|
|
dataBuilder.SubCommand(P("yes"));
|
|
builder.Describe(P("Vote `yes` on the current vote."));
|
|
dataBuilder.SubCommand(P("no"));
|
|
builder.Describe(P("Vote `no` on the current vote."));
|
|
|
|
builder.Option(P("force"));
|
|
builder.Describe(P("Tries to force voting to end immediately with the desired result."));
|
|
}
|
|
|
|
protected function Executed(
|
|
CallData arguments,
|
|
EPlayer instigator,
|
|
CommandPermissions permissions
|
|
) {
|
|
local bool forcingVoting;
|
|
local VotingModel.ForceEndingType forceType;
|
|
local Voting currentVoting;
|
|
|
|
forcingVoting = arguments.options.HasKey(P("force"));
|
|
currentVoting = _.commands.GetCurrentVoting();
|
|
if (arguments.subCommandName.IsEmpty()) {
|
|
DisplayInfoAboutVoting(instigator, currentVoting);
|
|
} else if (arguments.subCommandName.Compare(P("yes"), SCASE_INSENSITIVE)) {
|
|
CastVote(currentVoting, instigator, true);
|
|
forceType = FET_Success;
|
|
} else if (arguments.subCommandName.Compare(P("no"), SCASE_INSENSITIVE)) {
|
|
CastVote(currentVoting, instigator, false);
|
|
forceType = FET_Failure;
|
|
} else if (StartVoting(arguments, currentVoting, instigator)) {
|
|
_.memory.Free(currentVoting);
|
|
currentVoting = _.commands.GetCurrentVoting();
|
|
forceType = FET_Success;
|
|
} else {
|
|
forcingVoting = false;
|
|
}
|
|
if (currentVoting != none && !currentVoting.HasEnded() && forcingVoting) {
|
|
if (currentVoting.ForceEnding(instigator, forceType) == FEO_Forbidden) {
|
|
callerConsole
|
|
.WriteLine(F("You {$TextNegative aren't allowed} to forcibly end current voting"));
|
|
}
|
|
}
|
|
_.memory.Free(currentVoting);
|
|
}
|
|
|
|
private final function VoteWithVoice(EPlayer sender, ChatApi.BuiltInVoiceMessage message) {
|
|
local Voting currentVoting;
|
|
|
|
currentVoting = _.commands.GetCurrentVoting();
|
|
if (message == BIVM_AckYes) {
|
|
CastVote(currentVoting, sender, true);
|
|
}
|
|
if (message == BIVM_AckNo) {
|
|
CastVote(currentVoting, sender, false);
|
|
}
|
|
_.memory.Free(currentVoting);
|
|
}
|
|
|
|
/// Adds sub-command information about given voting with a given name.
|
|
public final function AddVotingInfo(class<Voting> processClass, Text processName) {
|
|
if (processName == none) return;
|
|
if (processClass == none) return;
|
|
if (dataBuilder == none) return;
|
|
|
|
dataBuilder.SubCommand(processName);
|
|
processClass.static.AddInfo(dataBuilder);
|
|
commandData = dataBuilder.BorrowData();
|
|
}
|
|
|
|
public final function HandleRemovedVoting(class<Voting> votingClass) {
|
|
local int i;
|
|
local array<Text> votingsNames;
|
|
|
|
ResetVotingInfo();
|
|
// Rebuild the whole voting data
|
|
votingsNames = _.commands.GetAllVotingsNames();
|
|
for (i = 0; i < votingsNames.length; i += 1) {
|
|
AddVotingInfo(_.commands.GetVotingClass(votingsNames[i]), votingsNames[i]);
|
|
}
|
|
_.memory.FreeMany(votingsNames);
|
|
}
|
|
|
|
/// Clears all sub-command information added from [`Voting`]s.
|
|
public final function ResetVotingInfo() {
|
|
_.memory.Free(dataBuilder);
|
|
dataBuilder = CommandDataBuilder(_.memory.Allocate(class'CommandDataBuilder'));
|
|
BuildData(dataBuilder);
|
|
commandData = dataBuilder.BorrowData();
|
|
}
|
|
|
|
private final function DisplayInfoAboutVoting(EPlayer instigator, Voting currentVoting) {
|
|
if (currentVoting == none) {
|
|
callerConsole.WriteLine(P("No voting is active right now."));
|
|
} else {
|
|
currentVoting.PrintVotingInfoFor(instigator);
|
|
}
|
|
}
|
|
|
|
private final function CastVote(Voting currentVoting, EPlayer voter, bool voteForSuccess) {
|
|
if (currentVoting != none) {
|
|
currentVoting.CastVote(voter, voteForSuccess);
|
|
} else {
|
|
callerConsole.UseColor(_.color.TextWarning).WriteLine(P("No voting is active right now."));
|
|
}
|
|
}
|
|
|
|
// Assumes all arguments aren't `none`.
|
|
private final function bool StartVoting(
|
|
CallData arguments,
|
|
Voting currentVoting,
|
|
EPlayer instigator
|
|
) {
|
|
local Voting newVoting;
|
|
local User callerUser;
|
|
local CommandAPI.VotingConfigInfo pair;
|
|
local CommandAPI.StartVotingResult result;
|
|
|
|
callerUser = instigator.GetIdentity();
|
|
pair = _.commands.ResolveVotingForUser(arguments.subCommandName, callerUser);
|
|
_.memory.Free(callerUser);
|
|
if (pair.votingClass == none) {
|
|
callerConsole
|
|
.UseColor(_.color.TextFailure)
|
|
.Write(P("Unknown voting option \""))
|
|
.Write(arguments.subCommandName)
|
|
.WriteLine(P("\""));
|
|
return false;
|
|
}
|
|
if (pair.usageForbidden) {
|
|
callerConsole
|
|
.UseColor(_.color.TextFailure)
|
|
.Write(P("You aren't allowed to start \""))
|
|
.Write(arguments.subCommandName)
|
|
.WriteLine(P("\" voting"));
|
|
return false;
|
|
}
|
|
result = _.commands.StartVoting(pair, arguments.parameters);
|
|
Log("Result:" @ result);
|
|
// Handle errors.
|
|
// `SVR_UnknownVoting` is impossible, since we've already checked that
|
|
// `pair.votingClass != none`)
|
|
if (result == SVR_AlreadyInProgress) {
|
|
callerConsole
|
|
.UseColor(_.color.TextWarning)
|
|
.WriteLine(P("Another voting is already in progress!"));
|
|
return false;
|
|
}
|
|
if (result == SVR_NoVoters) {
|
|
callerConsole
|
|
.UseColor(_.color.TextWarning)
|
|
.WriteLine(P("There are no players eligible for that voting."));
|
|
return false;
|
|
}
|
|
// Cast a vote from instigator
|
|
newVoting = _.commands.GetCurrentVoting();
|
|
if (newVoting != none) {
|
|
newVoting.CastVote(instigator, true);
|
|
} else {
|
|
callerConsole
|
|
.UseColor(_.color.TextFailure)
|
|
.WriteLine(P("Voting should be available, but it isn't."
|
|
@ "This is unexpected, something broke terribly."));
|
|
_.memory.Free(newVoting);
|
|
return false;
|
|
}
|
|
_.memory.Free(newVoting);
|
|
return true;
|
|
}
|
|
|
|
defaultproperties {
|
|
preferredName = "vote"
|
|
} |