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.
796 lines
28 KiB
796 lines
28 KiB
/** |
|
* Auxiliary object for working with player's inventory and making reports |
|
* about it. Simplifies code for inventory commands themselves by |
|
* taking care of actual item addition/removal and reporting about successes, |
|
* failures and inventory status. |
|
* This tool is supposed to be created for one player and provides wrapper |
|
* methods for his usual inventory methods that take care of information |
|
* collection about outcome of operations and then reporting on them. |
|
* 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 InventoryTool extends AcediaObject; |
|
|
|
enum InventoryReportTarget |
|
{ |
|
IRT_Instigator, |
|
IRT_Target, |
|
IRT_Others |
|
}; |
|
|
|
/** |
|
* Every instance of this class is created for a particular player and that |
|
* player cannot be changed. It allows: |
|
* 1. This object allows for editing player's inventory in a way that allows |
|
* it to produce a human-readable report about the changes. |
|
* Call `AddItem()`, `RemoveItem()` or `RemoveAllItems()` and then call |
|
* `ReportChanges()` to write changes made into the `ConsoleWriter`. |
|
* 2. `ReportInventory()` summarizes player's inventory. |
|
*/ |
|
|
|
// References to player (for whom this tool was created)... |
|
var private EPlayer targetPlayer; |
|
// ...and his inventory (for easy access) |
|
var private EInventory targetInventory; |
|
|
|
/** |
|
* `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; |
|
* ~ two other ones (`itemsAdded` and `itemsRemoved`) make reports about |
|
* successful changes to everybody else present on the server. |
|
* Supposed to be created via `CreateFor()` method. |
|
*/ |
|
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, TRESOLVED_INTO, TTILDE_QUOTE; |
|
var const int TITEM_MISSING, TITEM_NOT_REMOVABLE, TUNKNOWN, TVISIBLE; |
|
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 TTHEMSELVES, TFAULTY_INVENTORY_IMPLEMENTATION; |
|
|
|
public static function StaticConstructor() |
|
{ |
|
if (StaticConstructorGuard()) { |
|
return; |
|
} |
|
default.templateItemsAdded = __().text.MakeTemplate_S( |
|
"%%instigator%% {$TextPositive added} following weapons to" |
|
@ "%%target%%: "); |
|
default.templateItemsRemoved = __().text.MakeTemplate_S( |
|
"%%instigator%% {$TextNegative removed} following weapons from" |
|
@ "%%target%%: "); |
|
default.templateItemsAddedVerbose = __().text.MakeTemplate_S( |
|
"Weapons {$TextPositive added} to %%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 = 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() |
|
{ |
|
// Deallocate report tools |
|
_.memory.Free(itemsAdded); |
|
_.memory.Free(itemsRemoved); |
|
_.memory.Free(itemsAddedPrivate); |
|
_.memory.Free(itemsRemovedPrivate); |
|
_.memory.Free(itemsAdditionFailed); |
|
_.memory.Free(itemsRemovalFailed); |
|
itemsAdded = none; |
|
itemsRemoved = none; |
|
itemsAddedPrivate = none; |
|
itemsRemovedPrivate = none; |
|
itemsAdditionFailed = none; |
|
itemsRemovalFailed = none; |
|
// Deallocate player references |
|
_.memory.Free(targetPlayer); |
|
_.memory.Free(targetInventory); |
|
targetPlayer = none; |
|
targetInventory = none; |
|
} |
|
|
|
/** |
|
* Creates new `InventoryTool` instance for a given player `target`. |
|
* |
|
* @param target Player for which to create new `InventoryTool`. |
|
* @return `InventoryTool` created for the given player - not a copy of any |
|
* preexisting instance. `none` iff `target == none` or refers to |
|
* a non-existent player. |
|
*/ |
|
public static final function InventoryTool CreateFor(EPlayer target) |
|
{ |
|
local InventoryTool newInventoryTool; |
|
|
|
if (target == none) return none; |
|
if (!target.IsExistent()) return none; |
|
|
|
newInventoryTool = |
|
InventoryTool(__().memory.Allocate(class'InventoryTool')); |
|
newInventoryTool.targetPlayer = EPlayer(target.Copy()); |
|
newInventoryTool.targetInventory = target.GetInventory(); |
|
return newInventoryTool; |
|
} |
|
|
|
// Checks whether reference to the `EPlayer` that caller `InventoryTool` was |
|
// created for is still valid. |
|
private final function bool TargetPlayerIsInvalid() |
|
{ |
|
if (targetPlayer == none) return true; |
|
if (!targetPlayer.IsExistent()) return true; |
|
|
|
return false; |
|
} |
|
|
|
/** |
|
* Resets `InventoryTool`, forgetting about changes made with it so far. |
|
*/ |
|
public final function Reset() |
|
{ |
|
itemsAddedPrivate.Reset(); |
|
itemsRemovedPrivate.Reset(); |
|
itemsAdded.Reset(); |
|
itemsRemoved.Reset(); |
|
itemsAdditionFailed.Reset(); |
|
itemsRemovalFailed.Reset(); |
|
} |
|
|
|
// Makes "`resolvedWhat` resolved into `intoWhat`" line |
|
// In case `resolvedWhat == intoWhat` just returns copy of |
|
// original `resolvedWhat` |
|
private function MutableText MakeResolvedIntoLine( |
|
BaseText resolvedWhat, |
|
BaseText intoWhat) |
|
{ |
|
if (resolvedWhat == none) { |
|
return none; |
|
} |
|
if (_.text.IsEmpty(intoWhat) || resolvedWhat.Compare(intoWhat)) { |
|
return resolvedWhat.MutableCopy(); |
|
} |
|
return _.text.Empty() |
|
.Append(T(TTILDE_QUOTE)) |
|
.Append(resolvedWhat) |
|
.Append(T(TRESOLVED_INTO)) |
|
.Append(intoWhat) |
|
.Append(T(TTILDE_QUOTE)); |
|
} |
|
|
|
// Tries to fill ammo for the `item` in case it is a weapon |
|
private function TryFillAmmo(EItem item) |
|
{ |
|
local EWeapon itemAsWeapon; |
|
|
|
if (item == none) { |
|
return; |
|
} |
|
itemAsWeapon = EWeapon(item.As(class'EWeapon')); |
|
if (itemAsWeapon != none) |
|
{ |
|
itemAsWeapon.FillAmmo(); |
|
_.memory.Free(itemAsWeapon); |
|
} |
|
} |
|
|
|
/** |
|
* Adds a new item, based on user provided name `userProvidedName`. |
|
* |
|
* @param userProvidedName Name of the inventory, provided by the user. |
|
* If it is started with "$", then tool tried to treat it as |
|
* an alias first. If it either does not start with "$" or does not |
|
* correspond to a valid alias - it is treated as a template. |
|
* @param doForce Set to `true` if we must try to add an item |
|
* even if it normally cannot be added. |
|
* @param doFillAmmo Set to `true` if we must also fill ammo reserves |
|
* of weapons we have added to the full. |
|
*/ |
|
public function AddItem( |
|
BaseText userProvidedName, |
|
bool doForce, |
|
bool doFillAmmo) |
|
{ |
|
local EItem addedItem; |
|
local MutableText resolvedLine; |
|
local Text realItemName, itemTemplate, failureReason; |
|
|
|
if (TargetPlayerIsInvalid()) return; |
|
if (userProvidedName == none) return; |
|
|
|
// Get template in case alias was specified |
|
// (`itemTemplate` cannot be `none`, since `userProvidedName != none`) |
|
if (userProvidedName.StartsWith(T(TDOLLAR))) { |
|
itemTemplate = _.alias.ResolveWeapon(userProvidedName, true); |
|
} |
|
else { |
|
itemTemplate = userProvidedName.Copy(); |
|
} |
|
// The only way we can fail in a valid way is when API says we will |
|
// via `CanAddTemplateExplain()` |
|
failureReason = targetInventory |
|
.CanAddTemplateExplain(itemTemplate, doForce); |
|
if (failureReason != none) |
|
{ |
|
itemsAdditionFailed.Item(userProvidedName).Comment(failureReason); |
|
_.memory.Free(failureReason); |
|
_.memory.Free(itemTemplate); |
|
return; |
|
} |
|
// Actually try to add specified item |
|
addedItem = targetInventory.AddTemplate(itemTemplate, doForce); |
|
if (addedItem != none) |
|
{ |
|
if (doFillAmmo) { |
|
TryFillAmmo(addedItem); |
|
} |
|
realItemName = addedItem.GetName(); |
|
resolvedLine = MakeResolvedIntoLine(userProvidedName, itemTemplate); |
|
itemsAdded.Item(realItemName); |
|
itemsAddedPrivate.Item(realItemName).Comment(resolvedLine); |
|
_.memory.Free(realItemName); |
|
_.memory.Free(resolvedLine); |
|
_.memory.Free(addedItem); |
|
} |
|
else |
|
{ |
|
// `CanAddTemplateExplain()` told us that we should not have failed, |
|
// so complain about bad API |
|
itemsAdditionFailed.Item(userProvidedName) |
|
.Comment(T(TFAULTY_INVENTORY_IMPLEMENTATION)); |
|
} |
|
_.memory.Free(itemTemplate); |
|
} |
|
|
|
/** |
|
* Removes a specified item, based on user provided name `userProvidedName`. |
|
* |
|
* @param userProvidedName Name of inventory, provided by the user. |
|
* If it is started with "$", then tool tried to treat it as |
|
* an alias first. If it either does not start with "$" or does not |
|
* correspond to a valid alias - it is treated as a template. |
|
* @param doKeep Set to `true` if item should be preserved |
|
* (or, at least, attempted to be preserved) and not simply destroyed. |
|
* @param doForce Set to `true` if we must try to remove an item |
|
* even if it normally cannot be removed. |
|
* @param doRemoveAll Set to `true` to remove all instances of given |
|
* template and `false` to only remove one. |
|
*/ |
|
public function RemoveItem( |
|
BaseText userProvidedName, |
|
bool doKeep, |
|
bool doForce, |
|
bool doRemoveAll) |
|
{ |
|
local bool itemWasMissing; |
|
local Text realItemName, itemTemplate; |
|
local MutableText resolvedLine; |
|
local EItem storedItem; |
|
|
|
if (TargetPlayerIsInvalid()) return; |
|
if (userProvidedName == none) return; |
|
|
|
// Get template in case alias was specified |
|
// (`itemTemplate` cannot be `none`, since `userProvidedName != none`) |
|
if (userProvidedName.StartsWith(T(TDOLLAR))) { |
|
itemTemplate = _.alias.ResolveWeapon(userProvidedName, true); |
|
} |
|
else { |
|
itemTemplate = userProvidedName.Copy(); |
|
} |
|
// Check if item is even in the inventory |
|
storedItem = targetInventory.GetTemplateItem(itemTemplate); |
|
if (storedItem == none) |
|
{ |
|
// If not, we still need to attempt to remove it, as it can be |
|
// "merged" into another item |
|
itemWasMissing = true; |
|
realItemName = P("").Copy(); |
|
} |
|
else { |
|
// Need to remember the name before removing the item |
|
realItemName = storedItem.GetName(); |
|
} |
|
if (targetInventory |
|
.RemoveTemplate(itemTemplate, doKeep, doForce, doRemoveAll)) |
|
{ |
|
resolvedLine = MakeResolvedIntoLine(userProvidedName, itemTemplate); |
|
itemsRemoved.Item(realItemName); |
|
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).Comment(T(TITEM_MISSING)); |
|
} |
|
else if (!doForce && !storedItem.IsRemovable()) // simply was not removable |
|
{ |
|
itemsRemovalFailed.Item(userProvidedName) |
|
.Comment(T(TITEM_NOT_REMOVABLE)); |
|
} |
|
else { // no idea about the reason |
|
itemsRemovalFailed.Item(userProvidedName).Comment(T(TUNKNOWN)); |
|
} |
|
_.memory.Free(storedItem); |
|
_.memory.Free(realItemName); |
|
_.memory.Free(itemTemplate); |
|
} |
|
|
|
// Auxiliary method for detecting and reporting about removed items by |
|
/// comparing lists of `EItem` interfeaces created beofer and after removal |
|
private function DetectAndReportRemovedItems( |
|
out array<EItem> itemsAfterRemoval, |
|
array<EItem> itemsBeforeRemoval, |
|
array<BaseText> itemNames, |
|
bool doForce) |
|
{ |
|
local int i, j; |
|
local bool itemWasRemoved; |
|
|
|
for (i = 0; i < itemsBeforeRemoval.length; i += 1) |
|
{ |
|
itemWasRemoved = true; |
|
// If item was not destroyed - double check whether it got removed |
|
if (itemsBeforeRemoval[i].IsExistent()) |
|
{ |
|
for (j = 0; j < itemsAfterRemoval.length; j += 1) |
|
{ |
|
if (itemsBeforeRemoval[i].SameAs(itemsAfterRemoval[j])) |
|
{ |
|
_.memory.Free(itemsAfterRemoval[j]); |
|
itemsAfterRemoval.Remove(j, 1); |
|
itemWasRemoved = false; |
|
break; |
|
} |
|
} |
|
} |
|
if (itemWasRemoved) |
|
{ |
|
itemsRemoved.Item(itemNames[i]); |
|
itemsRemovedPrivate.Item(itemNames[i]); |
|
} |
|
else if (doForce || itemsBeforeRemoval[i].IsRemovable()) { |
|
itemsRemovalFailed.Item(itemNames[i]).Comment(T(TUNKNOWN)); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Removes all items from the player's inventory. |
|
* |
|
* @param doKeep Set to `true` if items should be preserved |
|
* (or, at least, attempted to be preserved) and not simply destroyed. |
|
* @param doForce Set to `true` if we must try to remove an item |
|
* even if it normally cannot be removed. |
|
* @param includeHidden Set to `true` if "hidden" items should also be |
|
* targeted by this method. These are items player cannot directly see in |
|
* their inventory, usually serving some sort of technical role. |
|
*/ |
|
public function RemoveAllItems(bool doKeep, bool doForce, bool includeHidden) |
|
{ |
|
local int i; |
|
local array<Text> itemNames; |
|
local array<EItem> itemsBeforeRemoval, itemsAfterRemoval; |
|
|
|
if (TargetPlayerIsInvalid()) { |
|
return; |
|
} |
|
// Remove all items! |
|
// Remember what items we have had before to output them and |
|
// what items we have after removal to detect what we have actually |
|
// removed. |
|
// This is necessary, since (to an extent depending on flags) |
|
// some items might not be removable. |
|
if (includeHidden) { |
|
itemsBeforeRemoval = targetInventory.GetAllItems(); |
|
} |
|
else { |
|
itemsBeforeRemoval = targetInventory.GetTagItems(T(TVISIBLE)); |
|
} |
|
for (i = 0; i < itemsBeforeRemoval.length; i += 1) { |
|
itemNames[i] = itemsBeforeRemoval[i].GetName(); |
|
} |
|
targetInventory.RemoveAll(doKeep, doForce, includeHidden); |
|
itemsAfterRemoval = targetInventory.GetAllItems(); |
|
// Figure out what items are actually gone and report about them |
|
DetectAndReportRemovedItems( itemsAfterRemoval, |
|
itemsBeforeRemoval, itemNames, |
|
doForce); |
|
_.memory.FreeMany(itemNames); |
|
_.memory.FreeMany(itemsBeforeRemoval); |
|
_.memory.FreeMany(itemsAfterRemoval); |
|
} |
|
|
|
/** |
|
* Removes all equipped items from the player's inventory. |
|
* |
|
* @param doKeep Set to `true` if items should be preserved |
|
* (or, at least, attempted to be preserved) and not simply destroyed. |
|
* @param doForce Set to `true` if we must try to remove an item |
|
* even if it normally cannot be removed. |
|
* @param includeHidden Set to `true` if "hidden" items should also be |
|
* targeted by this method. These are items player cannot directly see in |
|
* their inventory, usually serving some sort of technical role. |
|
*/ |
|
public function RemoveEquippedItems( |
|
bool doKeep, |
|
bool doForce, |
|
bool includeHidden) |
|
{ |
|
local int i; |
|
local EItem nextItem; |
|
local Text nextItemName; |
|
local array<EItem> equippedItems; |
|
|
|
if (TargetPlayerIsInvalid()) { |
|
return; |
|
} |
|
equippedItems = targetInventory.GetEquippedItems(); |
|
for (i = 0; i < equippedItems.length; i += 1) |
|
{ |
|
nextItem = equippedItems[i]; |
|
if (!nextItem.IsExistent()) continue; |
|
if (!includeHidden && !nextItem.HasTag(T(TVISIBLE))) continue; |
|
|
|
nextItemName = nextItem.GetName(); |
|
// Try to guess the reason we cannot remove the item |
|
if (!doForce && !nextItem.IsRemovable()) |
|
{ |
|
itemsRemovalFailed |
|
.Item(nextItemName) |
|
.Comment(T(TITEM_NOT_REMOVABLE)); |
|
} |
|
else if (!targetInventory.Remove(nextItem, doKeep, doForce)) |
|
{ |
|
itemsRemovalFailed |
|
.Item(nextItemName) |
|
.Comment(T(TUNKNOWN)); |
|
} |
|
_.memory.Free(nextItemName); |
|
nextItemName = none; |
|
} |
|
_.memory.FreeMany(equippedItems); |
|
} |
|
|
|
/** |
|
* Tells `InventoryTool` which player is responsible for the changes it is |
|
* reporting. This information is used to choose the phrasing of the reported |
|
* messages. |
|
* |
|
* @param instigator Player that supposedly requested all the changes done by |
|
* the calller `InventoryTool`. |
|
*/ |
|
public final function SetupReportInstigator(EPlayer instigator) |
|
{ |
|
local MutableText instigatorName, targetName; |
|
|
|
if (TargetPlayerIsInvalid()) return; |
|
if (instigator == none) return; |
|
|
|
instigatorName = ColorNickname(instigator.GetName()); |
|
if (!targetPlayer.SameAs(instigator)) { |
|
targetName = ColorNickname(targetPlayer.GetName()); |
|
} |
|
else { |
|
targetName = T(TYOU).MutableCopy(); |
|
} |
|
// For instigator |
|
default.templateItemsAdded.Reset().TextArg(T(TINSTIGATOR), instigatorName); |
|
default.templateItemsRemoved |
|
.Reset() |
|
.TextArg(T(TINSTIGATOR), instigatorName); |
|
// For everybody else |
|
default.templateAdditionFailed.Reset().TextArg(T(TTARGET), targetName); |
|
default.templateRemovalFailed.Reset().TextArg(T(TTARGET), targetName); |
|
default.templateItemsAddedVerbose.Reset().TextArg(T(TTARGET), targetName); |
|
default.templateItemsRemovedVerbose.Reset().TextArg(T(TTARGET), targetName); |
|
_.memory.Free(instigatorName); |
|
_.memory.Free(targetName); |
|
} |
|
|
|
private final function MutableText ColorNickname(/* take */ BaseText nickname) |
|
{ |
|
if (nickname == none) { |
|
return none; |
|
} |
|
return nickname |
|
.IntoMutableText() |
|
.ChangeDefaultColor(_.color.LightGray); |
|
} |
|
|
|
/** |
|
* Reports changes made to the player's inventory so far. |
|
* |
|
* Ability to provide this reports is pretty much the main reason for |
|
* using `InventoryTool` |
|
* @param blamedPlayer Player that should be listed as the one who caused |
|
* the changes. |
|
* @param writer `ConsoleWriter` that will be used to output report. |
|
* Method does nothing if given `writer` is `none`. |
|
* @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 instigator, |
|
ConsoleWriter writer, |
|
InventoryReportTarget reportTarget) |
|
{ |
|
if (TargetPlayerIsInvalid()) { |
|
return; |
|
} |
|
if (reportTarget != IRT_Instigator) |
|
{ |
|
SwapTargetNameInTemplates(instigator, reportTarget); |
|
ReportWeaponList(writer, default.templateItemsRemoved, itemsRemoved); |
|
ReportWeaponList(writer, default.templateItemsAdded, itemsAdded); |
|
return; |
|
} |
|
ReportWeaponList( |
|
writer, |
|
default.templateItemsRemovedVerbose, |
|
itemsRemovedPrivate); |
|
ReportWeaponList( |
|
writer, |
|
default.templateRemovalFailed, |
|
itemsRemovalFailed); |
|
ReportWeaponList( |
|
writer, |
|
default.templateItemsAddedVerbose, |
|
itemsAddedPrivate); |
|
ReportWeaponList( |
|
writer, |
|
default.templateAdditionFailed, |
|
itemsAdditionFailed); |
|
} |
|
|
|
private final function SwapTargetNameInTemplates( |
|
EPlayer instigator, |
|
InventoryReportTarget reportTarget) |
|
{ |
|
local MutableText targetName; |
|
|
|
if (TargetPlayerIsInvalid()) { |
|
return; |
|
} |
|
if (!targetPlayer.SameAs(instigator)) { |
|
targetName = ColorNickname(targetPlayer.GetName()); |
|
} |
|
else if (reportTarget == IRT_Target) { |
|
targetName = T(TYOU).MutableCopy(); |
|
} |
|
else { |
|
targetName = T(TTHEMSELVES).MutableCopy(); |
|
} |
|
default.templateItemsAdded.TextArg(T(TTARGET), targetName); |
|
default.templateItemsRemoved.TextArg(T(TTARGET), targetName); |
|
_.memory.Free(targetName); |
|
} |
|
|
|
private final function ReportWeaponList( |
|
ConsoleWriter writer, |
|
TextTemplate header, |
|
ListBuilder builder) |
|
{ |
|
local MutableText output; |
|
|
|
if (writer == none) return; |
|
if (builder == none) return; |
|
if (builder.IsEmpty()) return; |
|
|
|
if (header != none) |
|
{ |
|
output = header.CollectFormattedM(); |
|
writer.Write(output); |
|
_.memory.Free(output); |
|
output = none; |
|
} |
|
output = builder.GetMutable(); |
|
writer.WriteLine(output); |
|
_.memory.Free(output); |
|
} |
|
|
|
// TODO: Use `ListBuilder` for the below method? |
|
/** |
|
* Command that outputs summary of the player's inventory. |
|
* |
|
* @param writer `ConsoleWriter` into which to output information. |
|
* Method does nothing if given `writer` is `none`. |
|
* @param includeHidden Set to `true` if "hidden" items should also be |
|
* targeted by this method. These are items player cannot directly see in |
|
* their inventory, usually serving some sort of technical role. |
|
*/ |
|
public final function ReportInventory(ConsoleWriter writer, bool includeHidden) |
|
{ |
|
local int i; |
|
local int lineCounter; |
|
local array<EItem> availableItems; |
|
local Text playerName; |
|
|
|
if (writer == none) return; |
|
if (TargetPlayerIsInvalid()) return; |
|
|
|
playerName = targetPlayer.GetName(); |
|
writer.Flush() |
|
.Write(T(TDISPLAYING_INVENTORY)) |
|
.UseColorOnce(_.color.White).Write(playerName) |
|
.Write(T(THEADER_COLON)).Flush(); |
|
lineCounter = 1; |
|
availableItems = targetInventory.GetAllItems(); |
|
// First show visible items |
|
for (i = 0; i < availableItems.length; i += 1) |
|
{ |
|
if (availableItems[i].HasTag(T(TVISIBLE))) |
|
{ |
|
AppendItemInfo(writer, availableItems[i], lineCounter); |
|
lineCounter += 1; |
|
} |
|
} |
|
// Once more pass for non-visible items, to display them at the end |
|
if (includeHidden) |
|
{ |
|
writer.Write(T(THIDDEN_ITEMS)).Flush(); |
|
for (i = 0; i < availableItems.length; i += 1) |
|
{ |
|
if (!availableItems[i].HasTag(T(TVISIBLE))) |
|
{ |
|
AppendItemInfo(writer, availableItems[i], lineCounter); |
|
lineCounter += 1; |
|
} |
|
} |
|
} |
|
_.memory.Free(playerName); |
|
_.memory.FreeMany(availableItems); |
|
} |
|
|
|
private final function AppendItemInfo( |
|
ConsoleWriter writer, |
|
EItem item, |
|
int lineNumber) |
|
{ |
|
local Text itemName; |
|
local Text lineNumberAsText; |
|
local EWeapon itemAsWeapon; |
|
local Mutabletext allAmmoInfo; |
|
|
|
if (writer == none) return; |
|
if (item == none) return; |
|
|
|
itemName = item.GetName(); |
|
lineNumberAsText = _.text.FromInt(lineNumber); |
|
writer.Write(lineNumberAsText) |
|
.Write(T(TDOT_SPACE)) |
|
.UseColorOnce(_.color.TextEmphasis).Write(itemName); |
|
// Try to display additional ammo info if this is a weapon |
|
itemAsWeapon = EWeapon(item.As(class'EWeapon')); |
|
if (itemAsWeapon != none) |
|
{ |
|
allAmmoInfo = DisplayAllAmmoInfo(itemAsWeapon); |
|
if (allAmmoInfo != none) { |
|
writer.Write(T(TCOLON_SPACE)).Write(allAmmoInfo); |
|
} |
|
_.memory.Free(itemAsWeapon); |
|
_.memory.Free(allAmmoInfo); |
|
} |
|
writer.Flush(); |
|
_.memory.Free(itemName); |
|
_.memory.Free(lineNumberAsText); |
|
} |
|
|
|
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; |
|
} |
|
builder = _.text.Empty(); |
|
for (i = 0; i < allAmmo.length; i += 1) |
|
{ |
|
if (i > 0) { |
|
builder.Append(T(TCOMMA_SPACE)); |
|
} |
|
AppendAmmoInstanceInfo(builder, allAmmo[i]); |
|
} |
|
_.memory.FreeMany(allAmmo); |
|
return builder; |
|
} |
|
|
|
private final function AppendAmmoInstanceInfo(MutableText builder, EAmmo ammo) |
|
{ |
|
local Text ammoName; |
|
|
|
if (ammo == none) { |
|
return; |
|
} |
|
ammoName = ammo.GetName(); |
|
builder.AppendString( string(ammo.GetTotalAmount()), |
|
_.text.FormattingFromColor(_.color.TypeNumber)) |
|
.Append(T(TSPACE)).Append(ammoName).Append(T(TOUT_OF)) |
|
.AppendString( string(ammo.GetMaxTotalAmount()), |
|
_.text.FormattingFromColor(_.color.TypeNumber)); |
|
_.memory.Free(ammoName); |
|
} |
|
|
|
defaultproperties |
|
{ |
|
TINSTIGATOR = 0 |
|
stringConstants(0) = "instigator" |
|
TTARGET = 1 |
|
stringConstants(1) = "target" |
|
TRESOLVED_INTO = 2 |
|
stringConstants(2) = "` resolved into `" |
|
TTILDE_QUOTE = 3 |
|
stringConstants(3) = "`" |
|
TFAULTY_INVENTORY_IMPLEMENTATION = 4 |
|
stringConstants(4) = "faulty inventory implementation" |
|
TITEM_MISSING = 5 |
|
stringConstants(5) = "item missing" |
|
TITEM_NOT_REMOVABLE = 6 |
|
stringConstants(6) = "item not removable" |
|
TUNKNOWN = 7 |
|
stringConstants(7) = "unknown" |
|
TVISIBLE = 8 |
|
stringConstants(8) = "visible" |
|
TDISPLAYING_INVENTORY = 9 |
|
stringConstants(9) = "{$TextHeader Displaying inventory for player }" |
|
THEADER_COLON = 10 |
|
stringConstants(10) = "{$TextHeader :}" |
|
TDOT_SPACE = 11 |
|
stringConstants(11) = ". " |
|
TCOLON_SPACE = 12 |
|
stringConstants(12) = ": " |
|
TCOMMA_SPACE = 13 |
|
stringConstants(13) = ", " |
|
TSPACE = 14 |
|
stringConstants(14) = " " |
|
TOUT_OF = 15 |
|
stringConstants(15) = " out of " |
|
THIDDEN_ITEMS = 16 |
|
stringConstants(16) = "{$TextSubHeader Hidden items:}" |
|
TDOLLAR = 17 |
|
stringConstants(17) = "$" |
|
TYOU = 18 |
|
stringConstants(18) = "you" |
|
TTHEMSELVES = 19 |
|
stringConstants(19) = "themselves" |
|
} |