You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
8.0 KiB
224 lines
8.0 KiB
2 years ago
|
/**
|
||
|
* 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 "%cause%" 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 "%cause%" 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 "%cause%" 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(Text 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(Text 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(Text 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`.
|
||
|
*
|
||
|
* @param writer `ConsoleWriter` to output report into.
|
||
|
* @param cause Player that caused the change this report is about.
|
||
|
* Their name will replace "%cause%" 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 Text cause,
|
||
|
optional Text target)
|
||
|
{
|
||
|
local int i, j;
|
||
|
local MutableText intro;
|
||
|
local array<Text> detailToReport;
|
||
|
if (headerTemplate == none) return self;
|
||
|
if (itemsToReport.length == 0) return self;
|
||
|
if (writer == none) return self;
|
||
|
|
||
|
intro = headerTemplate.MutableCopy()
|
||
|
.Replace(T(TCAUSE), cause)
|
||
|
.Replace(T(TTARGET), target);
|
||
|
writer.Flush().Write(intro);
|
||
|
_.memory.Free(intro);
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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) = "%cause%"
|
||
|
TTARGET = 1
|
||
|
stringConstants(1) = "%target%"
|
||
|
TCOMMA = 2
|
||
|
stringConstants(2) = ","
|
||
|
TSPACE = 3
|
||
|
stringConstants(3) = " "
|
||
|
TSPACE_OPEN_PARANSIS = 4
|
||
|
stringConstants(4) = " ("
|
||
|
TCLOSE_PARANSIS = 5
|
||
|
stringConstants(5) = ")"
|
||
|
}
|