Anton Tarasenko
2 years ago
6 changed files with 437 additions and 348 deletions
@ -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) = ")" |
||||||
|
} |
@ -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…
Reference in new issue