Inventory Reference

From GECK
Jump to: navigation, search

In Fallout, objects stored inside of the inventories of actors or containers are not references. However, it can be useful to treat them as references in order to modify them. NVSE provides this functionality through the use of "inventory references", which are temporary references representing a stack of one or more items inside of a container. These references are only valid for one frame. Scripts can obtain an inventory reference in three ways: by iterating over the contents of a container, by retrieving references to items in a container matching a base item using GetInvRefsForItem, or by creating one directly using CreateTempRef.

Iteration Method #1

Iteration can firstly be performed using a ForEach loop. On each pass through the loop, the iterator variable is set to a temporary reference to a stack of identical items within the source container. Items are considered identical if they share the same health, ownership, and/or other values; if any one of these differ then the items are not considered identical and will be returned in different stacks. The order in which stacks are returned is arbitrary, but stacks of the same base object type are guaranteed to be returned consecutively. Note that the number and contents of the stacks returned may not correspond directly to those displayed in the inventory/container menu.

Within the loop, the temporary reference stored in the iterator variable can be treated almost exactly like a normal reference, allowing you to call functions like SetCurrentHealth etc on it. However, as soon as execution returns to the top of the loop the previous value of the iterator becomes invalid - the reference it held no longer exists, and has been replaced by a reference to the next stack of items in the container. When the loop ends, the final reference becomes invalid and the iterator variable is set to null. Therefore, you should never store a temporary reference and try to use it later on.

The temporary nature of inventory references require some extra care in their use. The contents of the source container should not be modified within the loop. In general:

Example

The following code illustrates inventory reference usage:

scriptName ExampleInvRefSCR	; attached to a container/actor reference
ref iter
ref container
short count
begin onActivate
	let container := getSelf
	foreach iter <- container
		let count := iter.GetRefCount
		print "Found " + $count + " " + iter.GetName + "(s)"
		if iter.GetOwner && iter.GetOwner != playerRef
			if iter.IsEquipped == 0		; can't remove equipped items
				; move stolen items to another container
				iter.RemoveMeIR someOtherContainerRef
			endif
		else
			; remove completely
			iter.RemoveMeIR
		endif
		; iter is now invalid because RemoveMeIR was used - so we won't attempt to continue using it
	loop	; now that loop has terminated, iter has been set to null (0)

	; create a temp ref to a weapon with a specific health value and quantity
	let iter := CreateTempRef weapSteelDagger
	iter.SetRefCount 5		; okay to use SetRefCount on a temp ref that is NOT in a container
	iter.SetCurrentHealth 10 	; damage the 5 daggers
	iter.CopyIR container		; container now contains 5 damaged daggers
	let iter := 0			; temp ref will be invalid next frame, set to null to be sure we don't try to re-use it
end

Iteration Method #2

With the JIP LN NVSE plugin, one can also loop through a container's inventory thanks to GetAllItemRefs, which also includes optional filters which can be useful in narrowing how many iterations have to be made. This function returns an Array Variable, and its contents can be accessed via a While or ForEach loop.

For either method, GetType can be used know what the type of the iterated reference is, in case one wants to do different operations for Armor references compared to Weapon references.

Example

array_var aItems
int iIndex
ref rItem

let aItems := playerref.GetAllItemRefs
let iIndex := ar_size aItems
while (iIndex -= 1) >= 0
   let rItem := aItems[iIndex]
   let iType := rItem.GetType

   ; do things using this information.
loop
let aItems := ar_Null

Notes

  • If you move or remove the reference from within a loop using RemoveMeIR, the reference becomes immediately invalid.
  • Never use Remove/Add/Equip/UnequipItem/RemoveAllItems on the source container from within the loop. Using EquipMe and UnequipMe to equip or unequip the current reference is fine.
  • Don't use SetRefCount to modify the quantity of an inventory reference

See Also