diff --git a/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandFakers.uc b/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandFakers.uc index 9e146bd..d686527 100644 --- a/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandFakers.uc +++ b/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandFakers.uc @@ -24,8 +24,12 @@ class ACommandFakers extends Command var private array fakers; +protected static function StaticFinalizer() { + __().memory.FreeMany(default.fakers); + default.fakers.length = 0; +} + protected function BuildData(CommandDataBuilder builder) { - builder.Name(P("fakers")); builder.Group(P("debug")); builder.Summary(P("Adds fake voters for testing \"vote\" command.")); builder.Describe(P("Displays current fake voters.")); @@ -40,7 +44,11 @@ protected function BuildData(CommandDataBuilder builder) { builder.ParamBoolean(P("vote_for")); } -protected function Executed(CallData arguments, EPlayer instigator) { +protected function Executed( + CallData arguments, + EPlayer instigator, + CommandPermissions permissions +) { if (arguments.subCommandName.IsEmpty()) { DisplayCurrentFakers(); } else if (arguments.subCommandName.Compare(P("amount"), SCASE_INSENSITIVE)) { @@ -52,14 +60,8 @@ protected function Executed(CallData arguments, EPlayer instigator) { } } -public final function UpdateFakersForVoting() { - local Voting currentVoting; - - currentVoting = GetCurrentVoting(); - if (currentVoting != none) { - currentVoting.SetDebugVoters(fakers); - } - _.memory.Free(currentVoting); +public final static function /*borrow*/ array BorrowDebugVoters() { + return default.fakers; } private final function CastVote(int fakerID, bool voteFor) { @@ -71,7 +73,7 @@ private final function CastVote(int fakerID, bool voteFor) { .WriteLine(P("Faker number is out of bounds.")); return; } - currentVoting = GetCurrentVoting(); + currentVoting = _.commands.GetCurrentVoting(); if (currentVoting == none) { callerConsole .UseColor(_.color.TextFailure) @@ -86,6 +88,7 @@ private final function ChangeAmount(int newAmount) { local int i; local Text nextIDName; local UserID nextID; + local Voting currentVoting; if (newAmount < 0) { callerConsole @@ -110,19 +113,12 @@ private final function ChangeAmount(int newAmount) { } fakers.length = newAmount; } - UpdateFakersForVoting(); -} - -private function Voting GetCurrentVoting() { - local Commands_Feature feature; - local Voting result; - - feature = Commands_Feature(class'Commands_Feature'.static.GetEnabledInstance()); - if (feature != none) { - result = feature.GetCurrentVoting(); - feature.FreeSelf(); + default.fakers = fakers; + currentVoting = _.commands.GetCurrentVoting(); + if (currentVoting != none) { + currentVoting.SetDebugVoters(default.fakers); + _.memory.Free(currentVoting); } - return result; } private function DisplayCurrentFakers() { @@ -135,7 +131,7 @@ private function DisplayCurrentFakers() { callerConsole.WriteLine(P("No fakers!")); return; } - currentVoting = GetCurrentVoting(); + currentVoting =_.commands.GetCurrentVoting(); for (i = 0; i < fakers.length; i += 1) { nextNumber = _.text.FromIntM(i); callerConsole @@ -163,4 +159,5 @@ private function DisplayCurrentFakers() { } defaultproperties { + preferredName = "fakers" } \ No newline at end of file diff --git a/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandHelp.uc b/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandHelp.uc index 0540cc7..aa58b4f 100644 --- a/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandHelp.uc +++ b/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandHelp.uc @@ -1,6 +1,6 @@ /** * Command for displaying help information about registered Acedia's commands. - * Copyright 2021-2022 Anton Tarasenko + * Copyright 2021-2023 Anton Tarasenko *------------------------------------------------------------------------------ * This file is part of Acedia. * @@ -18,7 +18,8 @@ * along with Acedia. If not, see . */ class ACommandHelp extends Command - dependson(LoggerAPI); + dependson(LoggerAPI) + dependson(CommandAPI); /** * # `ACommandHelp` @@ -72,6 +73,8 @@ class ACommandHelp extends Command // that uses sub-command names as keys and returns `ArrayList` of aliases. var private HashTable commandToAliasesMap; +var private User callerUser; + var public const int TSPACE, TCOMMAND_NAME_FALLBACK, TPLUS; var public const int TOPEN_BRACKET, TCLOSE_BRACKET, TCOLON_SPACE; var public const int TKEY, TDOUBLE_KEY, TCOMMA_SPACE, TBOOLEAN, TINDENT; @@ -79,7 +82,8 @@ var public const int TBOOLEAN_TRUE_FALSE, TBOOLEAN_ENABLE_DISABLE; var public const int TBOOLEAN_ON_OFF, TBOOLEAN_YES_NO; var public const int TOPTIONS, TCMD_WITH_TARGET, TCMD_WITHOUT_TARGET; var public const int TSEPARATOR, TLIST_REGIRESTED_CMDS, TEMPTY_GROUP; -var public const int TALIASES_FOR, TEMPTY, TDOT; +var public const int TALIASES_FOR, TEMPTY, TDOT, TNO_COMMAND_BEGIN; +var public const int TNO_COMMAND_END, TEMPTY_GROUP_BEGIN, TEMPTY_GROUP_END; protected function Constructor() { @@ -96,13 +100,13 @@ protected function Constructor() protected function Finalizer() { + super.Finalizer(); _.memory.Free(commandToAliasesMap); commandToAliasesMap = none; } protected function BuildData(CommandDataBuilder builder) { - builder.Name(P("help")); builder.Group(P("core")); builder.Summary(P("Displays detailed information about available commands.")); builder.OptionalParams(); @@ -120,13 +124,18 @@ protected function BuildData(CommandDataBuilder builder) builder.ParamTextList(P("groups")); } -protected function Executed(Command.CallData callData, EPlayer callerPlayer) -{ +protected function Executed( + Command.CallData callData, + EPlayer callerPlayer, + CommandPermissions permissions +) { + local bool printedSomething; local HashTable parameters, options; local ArrayList commandsToDisplay, commandGroupsToDisplay; - parameters = callData.parameters; - options = callData.options; + callerUser = callerPlayer.GetIdentity(); + parameters = callData.parameters; + options = callData.options; // Print command list if "--list" option was specified if (options.HasKey(P("list"))) { @@ -135,6 +144,7 @@ protected function Executed(Command.CallData callData, EPlayer callerPlayer) commandGroupsToDisplay, options.HasKey(P("aliases"))); _.memory.Free(commandGroupsToDisplay); + printedSomething = true; } // Help pages. // Only need to print them if: @@ -144,9 +154,11 @@ protected function Executed(Command.CallData callData, EPlayer callerPlayer) if (!options.HasKey(P("list")) || parameters.HasKey(P("commands"))) { commandsToDisplay = parameters.GetArrayList(P("commands")); - DisplayCommandHelpPages(commandsToDisplay); + DisplayCommandHelpPages(commandsToDisplay, printedSomething); _.memory.Free(commandsToDisplay); } + _.memory.Free(callerUser); + callerUser = none; } // If instance of the `Aliases_Feature` is passed as an argument (allowing this @@ -247,17 +259,11 @@ private final function DisplayCommandLists( ArrayList commandGroupsToDisplay, bool displayAliases) { - local int i; - local array commandNames, groupsNames; - local Commands_Feature commandsFeature; + local int i; + local array commandNames, groupsNames; - commandsFeature = - Commands_Feature(class'Commands_Feature'.static.GetEnabledInstance()); - if (commandsFeature == none) { - return; - } if (commandGroupsToDisplay == none) { - groupsNames = commandsFeature.GetGroupsNames(); + groupsNames = _.commands.GetGroupsNames(); } else { @@ -271,7 +277,7 @@ private final function DisplayCommandLists( if (groupsNames[i] == none) { continue; } - commandNames = commandsFeature.GetCommandNamesInGroup(groupsNames[i]); + commandNames = _.commands.GetCommandNamesInGroup(groupsNames[i]); if (commandNames.length > 0) { callerConsole.UseColorOnce(_.color.TextSubHeader); @@ -282,41 +288,45 @@ private final function DisplayCommandLists( callerConsole.WriteLine(groupsNames[i]); } PrintCommandsNamesArray( - commandsFeature, commandNames, displayAliases); _.memory.FreeMany(commandNames); + } else { + callerConsole.UseColor(_.color.TextFailure); + callerConsole.Write(T(TEMPTY_GROUP_BEGIN)); + callerConsole.Write(groupsNames[i]); + callerConsole.WriteLine(T(TEMPTY_GROUP_END)); + callerConsole.ResetColor(); } } _.memory.FreeMany(groupsNames); - commandsFeature.FreeSelf(); } private final function PrintCommandsNamesArray( - Commands_Feature commandsFeature, - array commandsNamesArray, - bool displayAliases) -{ - local int i; - local Command nextCommand; - local Command.Data nextData; + array commandsNamesArray, + bool displayAliases +) { + local int i; + local Command.Data nextData; + local CommandAPI.CommandConfigInfo nextCommandPair; for (i = 0; i < commandsNamesArray.length; i += 1) { - nextCommand = commandsFeature.GetCommand(commandsNamesArray[i]); - if (nextCommand == none) { - continue; - } - nextData = nextCommand.BorrowData(); - callerConsole - .UseColorOnce(_.color.textEmphasis) - .Write(nextData.name) - .Write(T(TCOLON_SPACE)) - .WriteLine(nextData.summary); - if (displayAliases) { - PrintCommandAliases(nextData.name); + nextCommandPair = _.commands.ResolveCommandForUser( + commandsNamesArray[i], + callerUser); + if (nextCommandPair.instance != none && !nextCommandPair.usageForbidden) { + nextData = nextCommandPair.instance.BorrowData(); + callerConsole + .UseColorOnce(_.color.textEmphasis) + .Write(commandsNamesArray[i]) + .Write(T(TCOLON_SPACE)) + .WriteLine(nextData.summary); + if (displayAliases) { + PrintCommandAliases(commandsNamesArray[i]); + } } - _.memory.Free(nextCommand); + _.memory.Free(nextCommandPair.instance); } } @@ -397,46 +407,47 @@ private final function PrintAliasesArray( callerConsole.WriteBlock(); } -private final function DisplayCommandHelpPages(ArrayList commandList) -{ - local int i; - local bool printedSomething; - local Text nextUserProvidedName; - local MutableText referredSubcommand; - local Command nextCommand; +private final function DisplayCommandHelpPages(ArrayList commandList, bool printedSomething) { + local int i; + local Text nextUserProvidedName; + local MutableText referredSubcommand; + local CommandAPI.CommandConfigInfo nextPair; // If arguments were empty - at least display our own help page - if (commandList == none) - { - PrintHelpPageFor(BorrowData().name, none, BorrowData()); + if (commandList == none) { + nextPair.instance = self; + PrintHelpPageFor(usedName, none, nextPair); return; } // Otherwise - print help for specified commands - for (i = 0; i < commandList.GetLength(); i += 1) - { + for (i = 0; i < commandList.GetLength(); i += 1) { nextUserProvidedName = commandList.GetText(i); - nextCommand = GetCommandFromUserProvidedName( + nextPair = GetCommandFromUserProvidedName( nextUserProvidedName, - referredSubcommand); - if (nextCommand != none) - { + /*out*/ referredSubcommand); + if (nextPair.instance != none && !nextPair.usageForbidden) { if (printedSomething) { callerConsole.WriteLine(T(TSEPARATOR)); } PrintHelpPageFor( nextUserProvidedName, referredSubcommand, - nextCommand.BorrowData()); + nextPair); printedSomething = true; + } else if (nextPair.instance != none) { + callerConsole.UseColor(_.color.TextFailure); + callerConsole.Write(T(TNO_COMMAND_BEGIN)); + callerConsole.Write(nextUserProvidedName); + callerConsole.WriteLine(T(TNO_COMMAND_END)); + callerConsole.ResetColor(); } - _.memory.Free(nextCommand); + _.memory.Free(nextPair.instance); _.memory.Free(nextUserProvidedName); _.memory.Free(referredSubcommand); - // `referredSubcommand` is passed as an `out` parameter on + // `referredSubcommand` is passed as an `out` parameter on // every iteration, so we need to prevent the possibility of its value // being used. - // NOTE: `nextCommand` and `nextUserProvidedName` are just - // rewritten. + // NOTE: `nextCommand` and `nextUserProvidedName` are just rewritten. referredSubcommand = none; } } @@ -446,56 +457,49 @@ private final function DisplayCommandHelpPages(ArrayList commandList) // is passed) and is used to return name of the subcommand for returned // `Command` that is specified by `nextUserProvidedName` (only relevant for // aliases that refer to a particular subcommand). -private final function Command GetCommandFromUserProvidedName( - BaseText nextUserProvidedName, +private final function CommandAPI.CommandConfigInfo GetCommandFromUserProvidedName( + BaseText nextUserProvidedName, out MutableText referredSubcommand) { - local Command result; - local Text commandAliasValue; - local Commands_Feature commandsFeature; - local MutableText parsedCommandName; + local CommandAPI.CommandConfigInfo result; + local Text commandAliasValue; + local MutableText parsedCommandName; // Clear `out` parameter no matter what - if (referredSubcommand != none) - { + if (referredSubcommand != none) { referredSubcommand.FreeSelf(); referredSubcommand = none; } - // Try accessing (check availability of) `Commands_Feature` - commandsFeature = - Commands_Feature(class'Commands_Feature'.static.GetEnabledInstance()); - if (commandsFeature == none) { - return none; - } // Try getting command using `nextUserProvidedName` as a literal name - result = commandsFeature.GetCommand(nextUserProvidedName); - if (result != none) - { - commandsFeature.FreeSelf(); + result = _.commands.ResolveCommandForUser(nextUserProvidedName, callerUser); + if (result.instance != none) { return result; } // On failure - try resolving it as an alias commandAliasValue = _.alias.ResolveCommand(nextUserProvidedName); ParseCommandNames(commandAliasValue, parsedCommandName, referredSubcommand); - result = commandsFeature.GetCommand(parsedCommandName); + result = _.commands.ResolveCommandForUser(parsedCommandName, callerUser); + if ( result.instance == none + || !result.instance.IsSubCommandAllowed(referredSubcommand, result.config)) { + _.memory.Free(result.instance); + return result; + } // Empty subcommand name from the alias is essentially no subcommand name - if (referredSubcommand != none && referredSubcommand.IsEmpty()) - { + if (referredSubcommand != none && referredSubcommand.IsEmpty()) { referredSubcommand.FreeSelf(); referredSubcommand = none; } - _.memory.Free(commandAliasValue); - _.memory.Free(parsedCommandName); - commandsFeature.FreeSelf(); + _.memory.Free2(commandAliasValue, parsedCommandName); return result; } private final function PrintHelpPageFor( - BaseText commandAlias, - BaseText referredSubcommand, - Command.Data commandData) -{ + BaseText commandAlias, + BaseText referredSubcommand, + CommandAPI.CommandConfigInfo commandPair +) { local Text commandNameLowerCase, commandNameUpperCase; + // Get capitalized command name commandNameUpperCase = commandAlias.UpperCopy(); // Print header: name + basic info @@ -503,7 +507,7 @@ private final function PrintHelpPageFor( .Write(commandNameUpperCase) .UseColor(_.color.textDefault); commandNameUpperCase.FreeSelf(); - if (commandData.requiresTarget) { + if (commandPair.instance.BorrowData().requiresTarget) { callerConsole.WriteLine(T(TCMD_WITH_TARGET)); } else { @@ -511,31 +515,27 @@ private final function PrintHelpPageFor( } // Print commands and options commandNameLowerCase = commandAlias.LowerCopy(); - PrintCommands(commandData, commandNameLowerCase, referredSubcommand); + PrintCommands(commandPair, commandNameLowerCase, referredSubcommand); commandNameLowerCase.FreeSelf(); - PrintOptions(commandData); + PrintOptions(commandPair.instance.BorrowData()); // Clean up callerConsole.ResetColor().Flush(); } private final function PrintCommands( - Command.Data data, - BaseText commandName, - BaseText referredSubcommand) -{ - local int i; - local array subCommands; + CommandAPI.CommandConfigInfo commandPair, + BaseText commandName, + BaseText referredSubcommand +) { + local int i; + local array subCommands; - subCommands = data.subCommands; - for (i = 0; i < subCommands.length; i += 1) - { - if ( referredSubcommand == none - || referredSubcommand.Compare(subCommands[i].name)) - { - PrintSubCommand( - subCommands[i], - commandName, - referredSubcommand != none); + subCommands = commandPair.instance.BorrowData().subCommands; + for (i = 0; i < subCommands.length; i += 1) { + if (referredSubcommand == none || referredSubcommand.Compare(subCommands[i].name)) { + if (commandPair.instance.IsSubCommandAllowed(subCommands[i].name, commandPair.config)) { + PrintSubCommand(subCommands[i], commandName, referredSubcommand != none); + } } } } @@ -719,4 +719,13 @@ defaultproperties stringConstants(21) = "" TDOT = 22 stringConstants(22) = "." + TNO_COMMAND_BEGIN = 23 + stringConstants(23) = "Command `" + TNO_COMMAND_END = 24 + stringConstants(24) = "` not found!" + TEMPTY_GROUP_BEGIN = 25 + stringConstants(25) = "No commands in group \"" + TEMPTY_GROUP_END = 26 + stringConstants(26) = "\"!" + preferredName = "help" } \ No newline at end of file diff --git a/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandNotify.uc b/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandNotify.uc index 79fe238..4f4c117 100644 --- a/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandNotify.uc +++ b/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandNotify.uc @@ -23,7 +23,6 @@ class ACommandNotify extends Command dependsOn(ChatApi); protected function BuildData(CommandDataBuilder builder) { - builder.Name(P("notify")); builder.Group(P("core")); builder.Summary(P("Notifies players with provided message.")); builder.ParamText(P("message")); @@ -43,7 +42,12 @@ protected function BuildData(CommandDataBuilder builder) { builder.ParamText(P("channel_name")); } -protected function ExecutedFor(EPlayer target, CallData arguments, EPlayer instigator) { +protected function ExecutedFor( + EPlayer target, + CallData arguments, + EPlayer instigator, + CommandPermissions permissions +) { local Text title, message, plainTitle, plainMessage; plainMessage = arguments.parameters.GetText(P("message")); @@ -61,4 +65,5 @@ protected function ExecutedFor(EPlayer target, CallData arguments, EPlayer insti } defaultproperties { + preferredName = "notify" } \ No newline at end of file diff --git a/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandSideEffects.uc b/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandSideEffects.uc index e28845f..b46f07a 100644 --- a/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandSideEffects.uc +++ b/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandSideEffects.uc @@ -36,8 +36,7 @@ protected function Finalizer() { } protected function BuildData(CommandDataBuilder builder) { - builder.Name(P("sideeffects")); - builder.Group(P("core")); + builder.Group(P("debug")); builder.Summary(P("Displays information about current side effects.")); builder.Describe(P("This command allows to display current side effects, optionally filtering" @ "them by specified package names.")); @@ -54,7 +53,11 @@ protected function BuildData(CommandDataBuilder builder) { builder.Describe(P("Display verbose information about each side effect.")); } -protected function Executed(CallData arguments, EPlayer instigator) { +protected function Executed( + CallData arguments, + EPlayer instigator, + CommandPermissions permissions +) { local UserID playerID; local array relevantSideEffects; local ArrayList packagesList, storedSideEffectsList; @@ -190,4 +193,5 @@ private function ShowInfoFor(UserID playerID, int sideEffectIndex) { } defaultproperties { + preferredName = "sideeffects" } \ No newline at end of file diff --git a/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandVote.uc b/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandVote.uc index d11f7e5..3af6170 100644 --- a/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandVote.uc +++ b/sources/BaseAPI/API/Commands/BuiltInCommands/ACommandVote.uc @@ -19,62 +19,93 @@ * You should have received a copy of the GNU General Public License * along with Acedia. If not, see . */ -class ACommandVote extends Command; +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.Name(P("vote")); builder.Group(P("core")); builder.Summary(P("Allows players to initiate any available voting." - @ "Votings themselves are added as sub-commands.")); + @ "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) { +protected function Executed( + CallData arguments, + EPlayer instigator, + CommandPermissions permissions +) { + local bool forcingVoting; + local VotingModel.ForceEndingType forceType; local Voting currentVoting; - local Commands_Feature feature; - feature = Commands_Feature(class'Commands_Feature'.static.GetEnabledInstance()); - if (feature == none) { - callerConsole - .UseColor(_.color.TextFailure) - .WriteLine(P("Feature responsible for commands and voting isn't enabled." - @ "This is unexpected, something broke terribly.")); - return; - } else { - currentVoting = feature.GetCurrentVoting(); - } + 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 { - StartVoting(arguments.subCommandName, feature, currentVoting, instigator); + 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(feature); _.memory.Free(currentVoting); } /// Adds sub-command information about given voting with a given name. -public final function AddVotingInfo(BaseText processName, class processClass) { +public final function AddVotingInfo(class processClass, Text processName) { if (processName == none) return; if (processClass == none) return; if (dataBuilder == none) return; @@ -84,6 +115,19 @@ public final function AddVotingInfo(BaseText processName, class processC commandData = dataBuilder.BorrowData(); } +public final function HandleRemovedVoting(class votingClass) { + local int i; + local array 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); @@ -109,41 +153,54 @@ private final function CastVote(Voting currentVoting, EPlayer voter, bool voteFo } // Assumes all arguments aren't `none`. -private final function StartVoting( - BaseText votingName, - Commands_Feature feature, +private final function bool StartVoting( + CallData arguments, Voting currentVoting, EPlayer instigator ) { - local Command fakersCommand; local Voting newVoting; - local Commands_Feature.StartVotingResult result; + local User callerUser; + local CommandAPI.VotingConfigInfo pair; + local CommandAPI.StartVotingResult result; - result = feature.StartVoting(votingName); - // Handle errors - if (result == SVR_UnknownVoting) { + 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(votingName) + .Write(arguments.subCommandName) .WriteLine(P("\"")); - return; - } else if (result == SVR_AlreadyInProgress) { + 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; + return false; } - // Inform new voting about fake voters, in case we're debugging - if (currentVoting == none && _.environment.IsDebugging()) { - fakersCommand = feature.GetCommand(P("fakers")); - if (fakersCommand != none && fakersCommand.class == class'ACommandFakers') { - ACommandFakers(fakersCommand).UpdateFakersForVoting(); - } - _.memory.Free(fakersCommand); + 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 = feature.GetCurrentVoting(); + newVoting = _.commands.GetCurrentVoting(); if (newVoting != none) { newVoting.CastVote(instigator, true); } else { @@ -151,9 +208,13 @@ private final function StartVoting( .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" } \ No newline at end of file