Browse Source

Refactor `ReportTool` into `ListBuilder`

feature_improvement
Anton Tarasenko 2 years ago
parent
commit
882830f273
  1. 22
      sources/Commands/ACommandFeature.uc
  2. 17
      sources/Commands/ACommandInventory.uc
  3. 56
      sources/Tools/FormattingReportTool.uc
  4. 197
      sources/Tools/InventoryTool.uc
  5. 241
      sources/Tools/ListBuilder.uc
  6. 252
      sources/Tools/ReportTool.uc

22
sources/Commands/ACommandFeature.uc

@ -190,7 +190,7 @@ protected function ShowFeature(class<Feature> feature)
local int i;
local Text autoConfig;
local MutableText featureName, builder;
local ReportTool reportTool;
local ListBuilder configList;
local array<Text> availableConfigs;
local class<FeatureConfig> configClass;
@ -203,8 +203,7 @@ protected function ShowFeature(class<Feature> feature)
}
featureName = _.text
.FromClassM(feature)
.ChangeDefaultFormatting(
_.text.FormattingFromColor(_.color.TextEmphasis));
.ChangeDefaultColor(_.color.TextEmphasis);
builder = _.text.Empty();
if (feature.static.IsEnabled()) {
builder.Append(F("[ {$TextPositive enabled} ] "));
@ -220,26 +219,25 @@ protected function ShowFeature(class<Feature> feature)
else if (availableConfigs.length > 1) {
builder.Append(P(" with configs:"));
}
reportTool = ReportTool(_.memory.Allocate(class'ReportTool'));
reportTool.Initialize(builder);
callerConsole.Write(builder);
_.memory.Free(builder);
configList = ListBuilder(_.memory.Allocate(class'ListBuilder'));
autoConfig = configClass.static.GetAutoEnabledConfig();
for (i = 0; i < availableConfigs.length; i += 1)
{
builder = _.text.Empty().Append(availableConfigs[i]);
reportTool.Item(builder);
configList.Item(availableConfigs[i]);
if ( autoConfig != none
&& autoConfig.Compare(availableConfigs[i], SCASE_INSENSITIVE))
{
reportTool.Detail(F("{$TextPositive auto enabled}"));
configList.Comment(F("{$TextPositive auto enabled}"));
}
_.memory.Free(builder);
builder = none;
}
reportTool.Report(callerConsole);
builder = configList.GetMutable();
callerConsole.WriteLine(builder);
_.memory.FreeMany(availableConfigs);
_.memory.Free(reportTool);
_.memory.Free(configList);
_.memory.Free(autoConfig);
_.memory.Free(builder);
}
defaultproperties

17
sources/Commands/ACommandInventory.uc

@ -122,7 +122,7 @@ protected function ExecutedFor(
if (!callerPlayer.SameAs(player)) {
tool.ReportChanges(callerPlayer, targetConsole, IRT_Target);
}
tool.ReportChanges(callerPlayer, callerConsole, IRT_Caller);
tool.ReportChanges(callerPlayer, callerConsole, IRT_Instigator);
tool.ReportChanges(callerPlayer, othersConsole, IRT_Others);
_.memory.Free(tool);
}
@ -219,12 +219,14 @@ protected function array<Text> LoadAllItemsLists(DynamicArray specifiedLists)
local array<Text> result;
local array<Text> nextItemBatch;
local array<Text> availableLists;
local ReportTool badLists;
local ListBuilder badLists;
local MutableText badListsAsText;
if (specifiedLists == none) {
return result;
}
badLists = ReportTool(_.memory.Allocate(class'ReportTool'));
badLists.Initialize(T(TLISTS_SKIPPED));
badLists = ListBuilder(_.memory.Allocate(class'ListBuilder'));
callerConsole.Write(T(TLISTS_SKIPPED));
availableLists = _.kf.templates.GetAvailableLists();
for (i = 0; i < specifiedLists.Getlength(); i += 1)
{
@ -234,8 +236,9 @@ protected function array<Text> LoadAllItemsLists(DynamicArray specifiedLists)
result[result.length] = nextItemBatch[j];
}
}
badLists.Report(callerConsole);
_.memory.Free(badLists);
badListsAsText = badLists.IntoMutableText();
callerConsole.WriteLine(badListsAsText);
_.memory.Free(badListsAsText);
_.memory.FreeMany(availableLists);
return result;
}
@ -243,7 +246,7 @@ protected function array<Text> LoadAllItemsLists(DynamicArray specifiedLists)
protected function array<Text> LoadItemsList(
BaseText listName,
array<BaseText> availableLists,
ReportTool badLists)
ListBuilder badLists)
{
local int i;
local array<Text> emptyArray;

56
sources/Tools/FormattingReportTool.uc

@ -38,16 +38,18 @@ public final static function Report(
array<FormattingErrorsReport.FormattedStringError> errors)
{
local int i;
local ReportTool reportTool;
reportTool = ReportTool(__().memory.Allocate(class'ReportTool'));
reportTool.Initialize(T(default.TREPORT_HEADER));
local ListBuilder builder;
local MutableText itemList;
builder = ListBuilder(__().memory.Allocate(class'ListBuilder'));
writer.Write(T(default.TREPORT_HEADER));
for (i = 0; i < errors.length; i += 1)
{
if (errors[i].type == FSE_UnmatchedClosingBrackets)
{
ReportCount(
errors[i],
reportTool,
builder,
default.TUNMATCHED_SINGLE,
default.TUNMATCHED_MULTIPLE);
}
@ -55,25 +57,26 @@ public final static function Report(
{
ReportCount(
errors[i],
reportTool,
builder,
default.TEMPTY_TAG_SINGLE,
default.TEMPTY_TAG_MULTIPLE);
}
else if (errors[i].type == FSE_BadColor) {
reportTool.Item(T(default.TBAD_COLOR)).Detail(errors[i].cause);
builder.Item(T(default.TBAD_COLOR)).Comment(errors[i].cause);
}
else if (errors[i].type == FSE_BadShortColorTag) {
reportTool.Item(T(default.TBADSHORT_TAG)).Detail(errors[i].cause);
builder.Item(T(default.TBADSHORT_TAG)).Comment(errors[i].cause);
}
else if (errors[i].type == FSE_BadGradientPoint)
{
reportTool
builder
.Item(T(default.TBAD_GRADIENT_POINT))
.Detail(errors[i].cause);
.Comment(errors[i].cause);
}
}
reportTool.Report(writer);
__().memory.Free(reportTool);
itemList = builder.IntoMutableText();
writer.WriteLine(itemList);
__().memory.Free(itemList);
}
/**
@ -86,6 +89,7 @@ public final static function FreeErrors(
array<FormattingErrorsReport.FormattedStringError> errors)
{
local int i;
for (i = 0; i < errors.length; i += 1) {
__().memory.Free(errors[i].cause);
}
@ -93,40 +97,42 @@ public final static function FreeErrors(
private final static function ReportCause(
FormattingErrorsReport.FormattedStringError error,
ReportTool reportTool,
ListBuilder builder,
int sentence)
{
local MutableText builder;
local MutableText causeBuilder;
if (error.cause == none) {
return;
}
reportTool.Item(T(sentence));
builder = __().text.FromIntM(error.count).Append(T(default.TCASES));
reportTool.Detail(builder);
__().memory.Free(builder);
builder.Item(T(sentence));
causeBuilder = __().text.FromIntM(error.count).Append(T(default.TCASES));
builder.Comment(causeBuilder);
__().memory.Free(causeBuilder);
}
// In the methods below, do not double check the error type in the following
// errors or whether `reportTool != none`
// errors or whether `builder != none`
private final static function ReportCount(
FormattingErrorsReport.FormattedStringError error,
ReportTool reportTool,
ListBuilder builder,
int singleSentence,
int multipleSentence)
{
local MutableText builder;
local MutableText commentBuilder;
if (error.count < 1) {
return;
}
if (error.count == 1)
{
reportTool.Item(T(singleSentence));
builder.Item(T(singleSentence));
return;
}
reportTool.Item(T(multipleSentence));
builder = __().text.FromIntM(error.count).Append(T(default.TCASES));
reportTool.Detail(builder);
__().memory.Free(builder);
builder.Item(T(multipleSentence));
commentBuilder = __().text.FromIntM(error.count).Append(T(default.TCASES));
builder.Comment(commentBuilder);
__().memory.Free(commentBuilder);
}
defaultproperties

197
sources/Tools/InventoryTool.uc

@ -48,7 +48,7 @@ var private EPlayer targetPlayer;
var private EInventory targetInventory;
/**
* `ReportTool`s for 6 different cases:
* `ListBuilder`s for 6 different cases:
* ~ two of "...Verbose" and "...Failed" ones make reports about
* successes and failures of adding and removals to the instigator of
* these changes;
@ -56,14 +56,18 @@ var private EInventory targetInventory;
* successful changes to everybody else present on the server.
* Supposed to be created via `CreateFor()` method.
*/
var private ReportTool itemsAdded;
var private ReportTool itemsRemoved;
var private ReportTool itemsAddedPrivate;
var private ReportTool itemsRemovedPrivate;
var private ReportTool itemsAdditionFailed;
var private ReportTool itemsRemovalFailed;
var const int TITEMS_ADDED_MESSAGE, TITEMS_ADDED_VEROBSE_MESSAGE;
var public ListBuilder itemsAdded;
var public ListBuilder itemsRemoved;
var public ListBuilder itemsAddedPrivate;
var public ListBuilder itemsRemovedPrivate;
var public ListBuilder itemsAdditionFailed;
var public ListBuilder itemsRemovalFailed;
var private TextTemplate templateItemsAdded, templateItemsRemoved;
var private TextTemplate templateItemsAddedVerbose, templateItemsRemovedVerbose;
var private TextTemplate templateAdditionFailed, templateRemovalFailed;
var const int TINSTIGATOR, TTARGET;
var const int TITEMS_REMOVED_MESSAGE, TITEMS_REMOVED_VERBOSE_MESSAGE;
var const int TITEMS_ADDITION_FAILED_MESSAGE, TITEMS_REMOVAL_FAILED_MESSAGE;
var const int TRESOLVED_INTO, TTILDE_QUOTE, TFAULTY_INVENTORY_IMPLEMENTATION;
@ -72,20 +76,35 @@ var const int TDISPLAYING_INVENTORY, THEADER_COLON, TDOT_SPACE, TCOLON_SPACE;
var const int TCOMMA_SPACE, TSPACE, TOUT_OF, THIDDEN_ITEMS, TDOLLAR, TYOU;
var const int TYOURSELF, TTHEMSELVES;
public static function StaticConstructor()
{
if (StaticConstructorGuard()) {
return;
}
default.templateItemsAdded = __().text.MakeTemplate_S(
"%%instigator%% {$TextPositive added} following weapons to"
@ "%%target%%: ");
default.templateItemsRemoved = __().text.MakeTemplate_S(
"Weapons {$TextPositive added} to %%target%%: ");
default.templateItemsAddedVerbose = __().text.MakeTemplate_S(
"%%instigator%% {$TextNegative removed} following weapons from"
@ "%%target%%: ");
default.templateItemsRemovedVerbose = __().text.MakeTemplate_S(
"Weapons {$TextNegative removed} from %%target%%: ");
default.templateAdditionFailed = __().text.MakeTemplate_S(
"Weapons we've {$TextFailure failed} to add to %%target%%: ");
default.templateRemovalFailed = __().text.MakeTemplate_S(
"Weapons we've {$TextFailure failed} to remove from %%target%%:" );
}
protected function Constructor()
{
itemsAdded = ReportTool(_.memory.Allocate(class'ReportTool'));
itemsRemoved = ReportTool(_.memory.Allocate(class'ReportTool'));
itemsAddedPrivate = ReportTool(_.memory.Allocate(class'ReportTool'));
itemsRemovedPrivate = ReportTool(_.memory.Allocate(class'ReportTool'));
itemsAdditionFailed = ReportTool(_.memory.Allocate(class'ReportTool'));
itemsRemovalFailed = ReportTool(_.memory.Allocate(class'ReportTool'));
itemsAdded.Initialize(T(TITEMS_ADDED_MESSAGE));
itemsRemoved.Initialize(T(TITEMS_REMOVED_MESSAGE));
itemsAddedPrivate.Initialize(T(TITEMS_ADDED_VEROBSE_MESSAGE));
itemsRemovedPrivate.Initialize(T(TITEMS_REMOVED_VERBOSE_MESSAGE));
itemsAdditionFailed.Initialize(T(TITEMS_ADDITION_FAILED_MESSAGE));
itemsRemovalFailed.Initialize(T(TITEMS_REMOVAL_FAILED_MESSAGE));
itemsAdded = ListBuilder(_.memory.Allocate(class'ListBuilder'));
itemsRemoved = ListBuilder(_.memory.Allocate(class'ListBuilder'));
itemsAddedPrivate = ListBuilder(_.memory.Allocate(class'ListBuilder'));
itemsRemovedPrivate = ListBuilder(_.memory.Allocate(class'ListBuilder'));
itemsAdditionFailed = ListBuilder(_.memory.Allocate(class'ListBuilder'));
itemsRemovalFailed = ListBuilder(_.memory.Allocate(class'ListBuilder'));
}
protected function Finalizer()
@ -121,6 +140,7 @@ protected function Finalizer()
public static final function InventoryTool CreateFor(EPlayer target)
{
local InventoryTool newInventoryTool;
if (target == none) return none;
if (!target.IsExistent()) return none;
@ -137,6 +157,7 @@ private final function bool TargetPlayerIsInvalid()
{
if (targetPlayer == none) return true;
if (!targetPlayer.IsExistent()) return true;
return false;
}
@ -178,6 +199,7 @@ private function MutableText MakeResolvedIntoLine(
private function TryFillAmmo(EItem item)
{
local EWeapon itemAsWeapon;
if (item == none) {
return;
}
@ -209,6 +231,7 @@ public function AddItem(
local EItem addedItem;
local MutableText resolvedLine;
local Text realItemName, itemTemplate, failureReason;
if (TargetPlayerIsInvalid()) return;
if (userProvidedName == none) return;
@ -226,7 +249,7 @@ public function AddItem(
.CanAddTemplateExplain(itemTemplate, doForce);
if (failureReason != none)
{
itemsAdditionFailed.Item(userProvidedName).Detail(failureReason);
itemsAdditionFailed.Item(userProvidedName).Comment(failureReason);
_.memory.Free(failureReason);
_.memory.Free(itemTemplate);
return;
@ -241,7 +264,7 @@ public function AddItem(
realItemName = addedItem.GetName();
resolvedLine = MakeResolvedIntoLine(userProvidedName, itemTemplate);
itemsAdded.Item(realItemName);
itemsAddedPrivate.Item(realItemName).Detail(resolvedLine);
itemsAddedPrivate.Item(realItemName).Comment(resolvedLine);
_.memory.Free(realItemName);
_.memory.Free(resolvedLine);
_.memory.Free(addedItem);
@ -251,7 +274,7 @@ public function AddItem(
// `CanAddTemplateExplain()` told us that we should not have failed,
// so complain about bad API
itemsAdditionFailed.Item(userProvidedName)
.Detail(T(TFAULTY_INVENTORY_IMPLEMENTATION));
.Comment(T(TFAULTY_INVENTORY_IMPLEMENTATION));
}
_.memory.Free(itemTemplate);
}
@ -280,6 +303,7 @@ public function RemoveItem(
local Text realItemName, itemTemplate;
local MutableText resolvedLine;
local EItem storedItem;
if (TargetPlayerIsInvalid()) return;
if (userProvidedName == none) return;
@ -309,21 +333,21 @@ public function RemoveItem(
{
resolvedLine = MakeResolvedIntoLine(userProvidedName, itemTemplate);
itemsRemoved.Item(realItemName);
itemsRemovedPrivate.Item(realItemName).Detail(resolvedLine);
itemsRemovedPrivate.Item(realItemName).Comment(resolvedLine);
_.memory.Free(resolvedLine);
}
// Try to guess why operation failed
// (no special explanation method is present in the API)
else if (itemWasMissing) { // likely because it was missing
itemsRemovalFailed.Item(userProvidedName).Detail(T(TITEM_MISSING));
itemsRemovalFailed.Item(userProvidedName).Comment(T(TITEM_MISSING));
}
else if (!doForce && !storedItem.IsRemovable()) // simply was not removable
{
itemsRemovalFailed.Item(userProvidedName)
.Detail(T(TITEM_NOT_REMOVABLE));
.Comment(T(TITEM_NOT_REMOVABLE));
}
else { // no idea about the reason
itemsRemovalFailed.Item(userProvidedName).Detail(T(TUNKNOWN));
itemsRemovalFailed.Item(userProvidedName).Comment(T(TUNKNOWN));
}
_.memory.Free(storedItem);
_.memory.Free(realItemName);
@ -340,6 +364,7 @@ private function DetectAndReportRemovedItems(
{
local int i, j;
local bool itemWasRemoved;
for (i = 0; i < itemsBeforeRemoval.length; i += 1)
{
itemWasRemoved = true;
@ -363,7 +388,7 @@ private function DetectAndReportRemovedItems(
itemsRemovedPrivate.Item(itemNames[i]);
}
else if (doForce || itemsBeforeRemoval[i].IsRemovable()) {
itemsRemovalFailed.Item(itemNames[i]).Detail(T(TUNKNOWN));
itemsRemovalFailed.Item(itemNames[i]).Comment(T(TUNKNOWN));
}
}
}
@ -384,6 +409,7 @@ public function RemoveAllItems(bool doKeep, bool doForce, bool includeHidden)
local int i;
local array<Text> itemNames;
local array<EItem> itemsBeforeRemoval, itemsAfterRemoval;
if (TargetPlayerIsInvalid()) {
return;
}
@ -433,6 +459,7 @@ public function RemoveEquippedItems(
local EItem nextItem;
local Text nextItemName;
local array<EItem> equippedItems;
if (TargetPlayerIsInvalid()) {
return;
}
@ -449,13 +476,13 @@ public function RemoveEquippedItems(
{
itemsRemovalFailed
.Item(nextItemName)
.Detail(T(TITEM_NOT_REMOVABLE));
.Comment(T(TITEM_NOT_REMOVABLE));
}
else if (!targetInventory.Remove(nextItem, doKeep, doForce))
{
itemsRemovalFailed
.Item(nextItemName)
.Detail(T(TUNKNOWN));
.Comment(T(TUNKNOWN));
}
_.memory.Free(nextItemName);
nextItemName = none;
@ -472,10 +499,10 @@ public function RemoveEquippedItems(
* the changes.
* @param writer `ConsoleWriter` that will be used to output report.
* Method does nothing if given `writer` is `none`.
* @param publicReport Is this report meant for the public or for
* the player that caused the changes? Former only (briefly) lists
* successful changes, while latter also provides report about failed
* changes.
* @param reportTarget For who is this report meant to? For general public
* and target only actually occured changes are reported (with different
* phrasing), but for instigator changes that tool failed to do will also
* be reported.
*/
public final function ReportChanges(
EPlayer blamedPlayer,
@ -483,6 +510,7 @@ public final function ReportChanges(
InventoryReportTarget reportTarget)
{
local Text blamedName, targetName;
if (TargetPlayerIsInvalid()) return;
if (blamedPlayer == none) return;
@ -495,36 +523,95 @@ public final function ReportChanges(
if (reportTarget == IRT_Instigator) {
targetName = T(TYOURSELF).Copy();
}
else if (reportTarget == IRT_Target) {
targetName = T(TYOU).Copy();
}
else {
targetName = T(TTHEMSELVES).Copy();
}
}
default.templateItemsAdded
.TextArg(T(TINSTIGATOR), blamedName)
.TextArg(T(TTARGET), targetName);
default.templateItemsRemoved
.TextArg(T(TINSTIGATOR), blamedName)
.TextArg(T(TTARGET), targetName);
if (reportTarget == IRT_Others)
{
itemsAdded.Report(writer, blamedName, targetName);
itemsRemoved.Report(writer, blamedName, targetName);
ReportWeaponList(writer, default.templateItemsAdded, itemsAdded);
ReportWeaponList(writer, default.templateItemsRemoved, itemsRemoved);
}
else if (reportTarget == IRT_Target)
{
itemsAdded.Report(writer, blamedName, T(TYOU));
itemsRemoved.Report(writer, blamedName, T(TYOU));
ReportWeaponList(writer, default.templateItemsAdded, itemsAdded);
ReportWeaponList(writer, default.templateItemsRemoved, itemsRemoved);
}
else if (reportTarget == IRT_Instigator)
{
if (targetPlayer.SameAs(blamedPlayer))
{
_.memory.Free(targetName);
targetName = T(TYOURSELF).Copy();
}
itemsAddedPrivate.Report(writer, blamedName, targetName);
itemsRemovedPrivate.Report(writer, blamedName, targetName);
itemsAdditionFailed.Report(writer, blamedName, targetName);
itemsRemovalFailed.Report(writer, blamedName, targetName);
default.templateItemsAddedVerbose
.TextArg(T(TINSTIGATOR), blamedName)
.TextArg(T(TTARGET), targetName);
default.templateItemsRemovedVerbose
.TextArg(T(TINSTIGATOR), blamedName)
.TextArg(T(TTARGET), targetName);
default.templateAdditionFailed
.TextArg(T(TINSTIGATOR), blamedName)
.TextArg(T(TTARGET), targetName);
default.templateremovalFailed
.TextArg(T(TINSTIGATOR), blamedName)
.TextArg(T(TTARGET), targetName);
ReportWeaponList(
writer,
default.templateItemsAddedVerbose,
itemsAddedPrivate);
ReportWeaponList(
writer,
default.templateItemsRemovedVerbose,
itemsRemovedPrivate);
ReportWeaponList(
writer,
default.templateAdditionFailed,
itemsAdditionFailed);
ReportWeaponList(
writer,
default.templateremovalFailed,
itemsRemovalFailed);
}
_.memory.Free(blamedName);
_.memory.Free(targetName);
}
private final function ReportWeaponList(
ConsoleWriter writer,
TextTemplate header,
ListBuilder builder)
{
local MutableText output;
if (writer == none) {
return;
}
if (header != none)
{
output = header.CollectFormattedM();
writer.Write(output);
_.memory.Free(output);
output = none;
}
if (builder != none) {
output = builder.GetMutable();
}
writer.WriteLine(output);
_.memory.Free(output);
}
/* itemsAdded.Initialize(T(TITEMS_ADDED_MESSAGE));
itemsRemoved.Initialize(T(TITEMS_REMOVED_MESSAGE));
itemsAddedPrivate.Initialize(T(TITEMS_ADDED_VEROBSE_MESSAGE));
itemsRemovedPrivate.Initialize(T(TITEMS_REMOVED_VERBOSE_MESSAGE));
itemsAdditionFailed.Initialize(T(TITEMS_ADDITION_FAILED_MESSAGE));
itemsRemovalFailed.Initialize(T(TITEMS_REMOVAL_FAILED_MESSAGE)); */
/**
* Command that outputs summary of the player's inventory.
*
@ -540,6 +627,7 @@ public final function ReportInventory(ConsoleWriter writer, bool includeHidden)
local int lineCounter;
local array<EItem> availableItems;
local Text playerName;
if (writer == none) return;
if (TargetPlayerIsInvalid()) return;
@ -585,6 +673,7 @@ private final function AppendItemInfo(
local Text lineNumberAsText;
local EWeapon itemAsWeapon;
local Mutabletext allAmmoInfo;
if (writer == none) return;
if (item == none) return;
@ -614,6 +703,7 @@ private final function MutableText DisplayAllAmmoInfo(EWeapon weapon)
local int i;
local array<EAmmo> allAmmo;
local MutableText builder;
allAmmo = weapon.GetAvailableAmmo();
if (allAmmo.length == 0) {
return none;
@ -633,6 +723,7 @@ private final function MutableText DisplayAllAmmoInfo(EWeapon weapon)
private final function AppendAmmoInstanceInfo(MutableText builder, EAmmo ammo)
{
local Text ammoName;
if (ammo == none) {
return;
}
@ -647,10 +738,12 @@ private final function AppendAmmoInstanceInfo(MutableText builder, EAmmo ammo)
defaultproperties
{
TITEMS_ADDED_MESSAGE = 0
stringConstants(0) = "%%instigator%% {$TextPositive added} following weapons to %%target%%:"
TITEMS_ADDED_VEROBSE_MESSAGE = 1
stringConstants(1) = "Weapons {$TextPositive added} to %%target%%:"
// TODO remove old constants
// TODO refactor `ReportChanges()`
TINSTIGATOR = 0
stringConstants(0) = "%%instigator%%"
TTARGET = 1
stringConstants(1) = "%%target%%"
TITEMS_REMOVED_MESSAGE = 2
stringConstants(2) = "%%instigator%% {$TextNegative removed} following weapons from %%target%%:"
TITEMS_REMOVED_VERBOSE_MESSAGE = 3

241
sources/Tools/ListBuilder.uc

@ -0,0 +1,241 @@
/**
* Many different Futility's commands need to output lists of items
* separated by commas, each item possibly containing comments in
* the parentheses (also separated by commas). This class provides necessary
* functionality.
* Copyright 2022 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 ListBuilder extends AcediaObject;
/**
* # `ListBuilder`
*
* Many different Futility's commands need to output lists of items
* separated by commas, each item possibly containing comments in
* the parentheses (also separated by commas). This class provides necessary
* functionality.
* Example of such list:
* "item1, item2 (comment1, comment2), item3 (just_comment), item4, item5".
*
* ## Usage
*
* 1. Use `Item()` method to add new items (they will be listed after
* list header + whitespace, separated by commas and whitespaces ", ");
* 2. Use `Comment()` method to specify comments for the item (they will
* be listed between the paranthesisasd after the corresponding item).
* Comments will be added to the last item, added via `Item()` call.
* If no items were added, specified comment will be discarded.
* 3. Use `Get()` / `GetMutable()` methods to return list built so far.
* 4. Use `Reset()` to forget all the items and comments
* (but not list header), allowing to start forming a new report.
*/
// Represents one item + all of its comments
struct FutilityListItem
{
var Text itemTitle;
var array<Text> comments;
};
// All items recorded reported thus far
var private array<FutilityListItem> collectedItems;
var const int TCAUSE, TTARGET, TCOMMA, TSPACE, TCOMMA_SPACE;
var const int TSPACE_OPEN_PARANSIS, TCLOSE_PARANSIS;
protected function Finalizer()
{
Reset();
}
/**
* Adds new `item` to the current report.
*
* @param item Text to be included into the report as an item.
* One should avoid using commas or parantheses inside an `item`, but
* this limitation is not checked or prevented by `Item()` method.
* Does nothing if `item == none` (`Comment()` will continue adding
* comments to the previously added item).
* @return Reference to the caller `ListBuilder` to allow for method chaining.
*/
public final function ListBuilder Item(BaseText item)
{
local FutilityListItem newItem;
if (item == none) {
return self;
}
newItem.itemTitle = item.Copy();
collectedItems[collectedItems.length] = newItem;
return self;
}
/**
* Adds new `comment` to the last added `item` in the current report.
*
* @param comment Text to be included into the report as a comment to
* the last added item. One should avoid using commas or parantheses inside
* a `comment`, but this limitation is not checked or prevented by
* `Comment()` method.
* Does nothing if `comment == none` or no items were added thuis far.
* @return Reference to the caller `ListBuilder` to allow for method chaining.
*/
public final function ListBuilder Comment(BaseText comment)
{
local array<Text> itemComments;
if (comment == none) return self;
if (collectedItems.length == 0) return self;
itemComments = collectedItems[collectedItems.length - 1].comments;
itemComments[itemComments.length] = comment.Copy();
collectedItems[collectedItems.length - 1].comments = itemComments;
return self;
}
/**
* Returns list, assembled from items and their comment specified so far as
* `Text`.
*
* @see `GetMutable()`, `IntoText()`, `IntoMutableText()`
*
* @return Assembled list of specified items with specified comments.
*/
public final function Text Get()
{
local MutableText mutableResult;
mutableResult = GetMutable();
if (mutableResult != none) {
return mutableResult.IntoText();
}
return none;
}
/**
* Returns list, assembled from items and their comment specified so far as
* `MutableText`.
*
* @see `Get()`, `IntoText()`, `IntoMutableText()`
*
* @return Assembled list of specified items with specified comments.
*/
public final function MutableText GetMutable()
{
local int i, j;
local MutableText result;
local array<Text> itemComments;
if (collectedItems.length == 0) {
return _.text.Empty();
}
result = _.text.Empty();
for (i = 0; i < collectedItems.length; i += 1)
{
if (i > 0) {
result.Append(T(TCOMMA_SPACE));
}
result.Append(collectedItems[i].itemTitle);
itemComments = collectedItems[i].comments;
if (itemComments.length > 0) {
result.Append(T(TSPACE_OPEN_PARANSIS));
}
for (j = 0; j < itemComments.length; j += 1)
{
if (j > 0) {
result.Append(T(TCOMMA_SPACE));
}
result.Append(itemComments[j]);
}
if (itemComments.length > 0) {
result.Append(T(TCLOSE_PARANSIS));
}
}
return result;
}
/**
* Converts caller `Listbuilder` into list, assembled from items and their
* comment specified so far as `Text`.
* Caller `ListBuilder()` is atuomatically deallocated.
*
* @see `Get()`, `GetMutable()`, `IntoMutableText()`
*
* @return Assembled list of specified items with specified comments.
*/
public final function Text IntoText()
{
local Text result;
result = Get();
FreeSelf();
return result;
}
/**
* Converts caller `Listbuilder` into list, assembled from items and their
* comment specified so far as `MutableText`.
* Caller `ListBuilder()` is atuomatically deallocated.
*
* @see `Get()`, `GetMutable()`, `IntoText()`
*
* @return Assembled list of specified items with specified comments.
*/
public final function MutableText IntoMutableText()
{
local MutableText result;
result = GetMutable();
FreeSelf();
return result;
}
/**
* Forgets all items or comments specified for the caller `ListBuilder` so far,
* allowing to start forming a new report. Does not reset template header,
* specified in the `Initialize()` method.
*
* @return Reference to the caller `ListBuilder` to allow for method chaining.
*/
public final function ListBuilder Reset()
{
local int i;
for (i = 0; i < collectedItems.length; i += 1)
{
_.memory.Free(collectedItems[i].itemTitle);
_.memory.FreeMany(collectedItems[i].comments);
}
collectedItems.length = 0;
return self;
}
defaultproperties
{
TCAUSE = 0
stringConstants(0) = "%%instigator%%"
TTARGET = 1
stringConstants(1) = "%%target%%"
TCOMMA = 2
stringConstants(2) = ","
TCOMMA_SPACE = 3
stringConstants(3) = ", "
TSPACE_OPEN_PARANSIS = 4
stringConstants(4) = " ("
TCLOSE_PARANSIS = 5
stringConstants(5) = ")"
}

252
sources/Tools/ReportTool.uc

@ -1,252 +0,0 @@
/**
* Auxiliary object for outputting lists of values (with optional comments)
* for Futility's commands. Some of the commands need to report that one of
* the player did something to affect the other and then list the changes.
* This tool is made to simplify forming such reports.
* Produced reports have a form of "<list header, noting who affected who>:
* item1 (detail), item2, item3 (detail1, detail2)".
* Copyright 2022 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 ReportTool extends AcediaObject;
/**
* How to use:
* 1. Specify "list header" via `Initialize()` method right after creating
* a new instance of `ReportTool`. It can contain "%%instigator%%" and
* "%%target%%" substrings, that will be replaces with approprtiate
* parameters of `Report()` method when it is invoked;
* 2. Use `Item()` method to add new items (they will be listed after
* list header + whitespace, separated by commas and whitespaces ", ");
* 3. Use `Detail()` method to specify details for the item (they will be
* listed between the paranthesisasd after the corresponding item).
* Details will be added to the last item, added via `Item()` call.
* If no items were added, specified details will be discarded.
* 4. Use `Report()` method to feed the `ConsoleWriter` with report that
* has been assebled so far.
* 5. Use `Reset()` to forget all the items and details
* (but not list header), allowing to start forming a new report.
*/
// Header template (with possible "%%instigator%%" and "%%target%%"
// placeholders) for the lists this `ReportTool` will generate.
// Doubles as a way to remember whether `ReportTool` was already
// initialized (iff `headerTemplate != none`).
var private Text headerTemplate;
// Represents one item + all of its details.
struct ReportItem
{
var Text itemTitle;
var array<Text> details;
};
// All items recorded reported thus far
var private array<ReportItem> itemsToReport;
var const int TCAUSE, TTARGET, TCOMMA, TSPACE, TSPACE_OPEN_PARANSIS;
var const int TCLOSE_PARANSIS;
protected function Finalizer()
{
Reset();
_.memory.Free(headerTemplate);
headerTemplate = none;
}
/**
* Initialized a new `ReportTool` with appropriate template to serve as
* a header.
*
* Template (`template`) is allowed to contain "%%instigator%%" and
* "%%target%%" placeholder substrings that will be replaced with corresponding
* names of the player that caused a change we are reporting and player
* affefcted by that change.
*
* @param template Template for the header of the reports made by
* the caller `ReportTool`.
* Method does nothing (initialization fails) iff `template == none`.
*/
public final function Initialize(BaseText template)
{
if (template == none) {
return;
}
headerTemplate = template.Copy();
}
/**
* Adds new `item` to the current report.
*
* @param item Text to be included into the report as an item.
* One should avoid using commas or parantheses inside an `item`, but
* this limitation is not checked or prevented by `Item()` method.
* Does nothing if `item == none` (`Detail()` will continue adding details
* to the previously added item).
* @return Reference to the caller `ReportTool` to allow for method chaining.
*/
public final function ReportTool Item(BaseText item)
{
local ReportItem newItem;
if (headerTemplate == none) return self;
if (item == none) return self;
newItem.itemTitle = item.Copy();
itemsToReport[itemsToReport.length] = newItem;
return self;
}
/**
* Adds new `detail` to the last added `item` in the current report.
*
* @param detail Text to be included into the report as a detail to
* the last added item. One should avoid using commas or parantheses inside
* a `detail`, but this limitation is not checked or prevented by
* `Detail()` method.
* Does nothing if `detail == none` or no items were added thuis far.
* @return Reference to the caller `ReportTool` to allow for method chaining.
*/
public final function ReportTool Detail(BaseText detail)
{
local array<Text> detailToReport;
if (headerTemplate == none) return self;
if (detail == none) return self;
if (itemsToReport.length == 0) return self;
detailToReport = itemsToReport[itemsToReport.length - 1].details;
detailToReport[detailToReport.length] = detail.Copy();
itemsToReport[itemsToReport.length - 1].details = detailToReport;
return self;
}
/**
* Outputs report assembled thus far into the provided `ConsoleWriter`.
* Reports will be made only if at least one items was added (see `Item()`).
*
* @param writer `ConsoleWriter` to output report into.
* @param instigator Player that caused the change this report is about.
* Their name will replace "%%instigator%%" substring in the header
* template (if it is contained there).
* @param target Player that was affected by the change this report is
* about. Their name will replace "%%target%%" substring in the header
* template (if it is contained there).
* @return Reference to the caller `ReportTool` to allow for method chaining.
*/
public final function ReportTool Report(
ConsoleWriter writer,
optional BaseText instigator,
optional BaseText target)
{
local int i, j;
local array<Text> detailToReport;
if (headerTemplate == none) return self;
if (itemsToReport.length == 0) return self;
if (writer == none) return self;
AppendHeader(writer, instigator, target);
for (i = 0; i < itemsToReport.length; i += 1)
{
if (i > 0) {
writer.Write(T(TCOMMA));
}
writer.Write(T(TSPACE)).Write(itemsToReport[i].itemTitle);
detailToReport = itemsToReport[i].details;
if (detailToReport.length > 0) {
writer.Write(T(TSPACE_OPEN_PARANSIS));
}
for (j = 0; j < detailToReport.length; j += 1)
{
if (j > 0) {
writer.Write(P(", "));
}
writer.Write(detailToReport[j]);
}
if (detailToReport.length > 0) {
writer.Write(T(TCLOSE_PARANSIS));
}
}
writer.Flush();
return self;
}
private final function AppendHeader(
ConsoleWriter writer,
optional BaseText instigator,
optional BaseText target)
{
local MutableText intro;
local MutableText grayInstigatorName, grayTargetName;
if (headerTemplate == none) return;
if (writer == none) return;
if (instigator != none)
{
grayInstigatorName = instigator
.MutableCopy()
.ChangeDefaultColor(_.color.Gray);
}
if (target != none) {
grayTargetName = target.MutableCopy().ChangeDefaultColor(_.color.Gray);
}
intro = headerTemplate.MutableCopy()
.Replace(T(TCAUSE), grayInstigatorName)
.Replace(T(TTARGET), grayTargetName);
writer.Flush().Write(intro);
_.memory.Free(intro);
_.memory.Free(grayTargetName);
_.memory.Free(grayInstigatorName);
}
/**
* Forgets all items or details specified for the caller `ReportTool` so far,
* allowing to start forming a new report. Does not reset template header,
* specified in the `Initialize()` method.
*
* @return Reference to the caller `ReportTool` to allow for method chaining.
*/
public final function ReportTool Reset()
{
local int i;
for (i = 0; i < itemsToReport.length; i += 1)
{
_.memory.Free(itemsToReport[i].itemTitle);
_.memory.FreeMany(itemsToReport[i].details);
}
if (itemsToReport.length > 0) {
itemsToReport.length = 0;
}
return self;
}
defaultproperties
{
TCAUSE = 0
stringConstants(0) = "%%instigator%%"
TTARGET = 1
stringConstants(1) = "%%target%%"
TCOMMA = 2
stringConstants(2) = ","
TSPACE = 3
stringConstants(3) = " "
TSPACE_OPEN_PARANSIS = 4
stringConstants(4) = " ("
TCLOSE_PARANSIS = 5
stringConstants(5) = ")"
}
Loading…
Cancel
Save