Administration tools: commands and non gameplay server configuration
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.

225 lines
8.1 KiB

/**
* 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(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 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 BaseText cause,
optional BaseText 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) = ")"
}