MSFD Adding and removing items from the inventory
AddItem, "ObjectID", count_enum
RemoveItem, "ObjectID", count_enum
Actor->AddItem, "item_ID", 1
Container->RemoveItem, "itme_ID", 5
These functions are simple enough, adding or removing items from the player’s or any other inventory, including containers. A RemoveItem call will remove the item from the inventory, it will "vanish".
Notes on AddItem (by DinkumThinkum):
If you add items to an NPC's inventory when the inventory screen is already open, the display won't be updated with the new items, unless the player manually adds or removes displayed items (which forces the game to refresh the inventory display).
The early versions of my Potion Saver coded used 'If MenuMode == 1' to trigger putting potions back into the companion's inventory. This worked fine when the companion was alive and conscious, since the script would add the potions while in the dialogue window, before the companion share inventory window was opened.
However, if the companion was dead or unconscious, clicking on the companion would open the inventory window immediately, and the potions would be added after the window was already open. End result, the potions wouldn't show up in the inventory window.
To avoid the problem, add items to an NPC's inventory as soon as they die, as soon as they fall unconscious, or when the game goes into Menu Mode (check Menu Mode after checking death and unconsciousness). That way, the items will be added before the inventory window opens.
Here's the code I used for this in the Potion Saver:
If ( GetHealth < 1 )
Set DTNPS_HandlePotions to 0
ElseIf ( GetFatigue < 1 )
Set DTNPS_HandlePotions to 0
ElseIf ( MenuMode == 1 )
Set DTNPS_HandlePotions to 0
Else
Set DTNPS_HandlePotions to 1
EndIf
Usage with containers:
If a container has been emptied by the player (in game), AddItem will no longer work. One workaround is to replace the container with a new one each time it's accessed by the player, but this may not be practical as there's no way to detect when the container is empty. Aragon suggested a solution:
The workaround is to attach a script to the container that always adds and removes a dummy item in the same frame that the player activated it. So, my ingredients chest has a script that looks like:
; Open the chest
Activate
; Always add and remove a dummy (this hack keeps the "AddItem" calls working)
AddItem, "misc_de_cloth10", 1
RemoveItem, "misc_de_cloth10", 1
Furthermore, we make the chest with "references persist". Now we can reference it from an ingredients sorter using code like:
set count to ( player->GetItemCount, "ingred_dreugh_wax_01" )
while ( count > 0 )
set count to ( count - 1 )
player->RemoveItem, "ingred_dreugh_wax_01", 1
"_tm_ingredients_chest"->AddItem, "ingred_dreugh_wax_01", 1
endwhile
Another (probably better) workaround suggested by Enmesharra: Add a non-carryable light with no world or inventory art associated with it to the container. It won't show in inventory and thus the container can't be emptied (not tested).
Notes on RemoveItem:
Removing items that are not present in the inventory does not crash the game, but the 'RemoveItem' function will subtract the removed item's weight from the character's encumbrance, EVEN IF the item is NOT in the character's inventory. So if a script uses 'RemoveItem' to remove a 4 lb. item that the character doesn't have, the character's encumbrance will wind up 4 lbs. lower than it should be. The workaround for this bug is to always check for the presence of an item before using 'RemoveItem' to delete it (Thanks DinkumThinkum for this info).
Don't remove an item that is executing a script, from the item's own script: that will crash the game. See the example script.
A workaround for this is to use a separate global or local script to remove the item. However, if the player has two or more copies of an object with an attached script in their inventory, using RemoveItem on that Object ID will frequently corrupt data for one of the remaining copies (you may e.g. see corrupted health or count data). Equipping or using that corrupt object may cause the game to crash (Forum info / DinkumThinkum).
To avoid the two known RemoveItem bugs:
1. If the object is not scripted, use GetItemCount to be sure the player has at least 1.
2. If the object is scripted, use GetItemCount to be sure the player has exactly 1, or make sure the object is unique.
The drop function does not have this bug. It does, however, cause doubling, if used with OnPCEquip / SkipEquip, which can be fixed by adding and removing any item as described for these functions.
Notes on using Additem / Removeitem in dialogue:
These functions can accept global variables, but only in dialogue results, and only if you don’t set the global variable in the same dialog result (Forum info / Argent; According to Argent, the maximum amount he has been able to add using AddItem, var was 65534 (using a long var=2147483520)). In addition to Argent's info about AddItem/RemoveItem accepting variables in dialog action boxes: make sure that the variable in question doesn't change in the same box. Say, var_a equals 3 at the moment when the line is selected in dialogue. If the result field looks like this:
set var_a to var_a + 10 ;
AddItem gold_001, var_a
three drakes will be added to NPC's inventory, and not thirteen. If such need arises, put all calculating operators into one dialogue response's result box, add "choice" operator, and process the AddItem function in the following response. Also, even with long variables, I couldn't correctly add values above 32767 (2^15). (tested on pure Morrowind without expansions) (Forum info / Kir).
Example script:
The following script was discussed on the forums (sorry don’t remember who first made it). It was supposed to ask the player if he wanted to recycle an item when it was equipped, and then replace that item with the "recycled" version.
Begin scr_thing
short button
short OnPcEquip
short state
if ( MenuMode == 1 )
return
endif
if ( OnPCEquip == 1 ) ; when the item is equipped
set state to 1
set OnPCEquip to 0 ; do this once per equip event…
endif
if ( state ==1 )
MessageBox "recycle?" , "yes", "no"
set state to 2
elseif ( state == 2 )
set button to GetButtonPressed
if ( button == 0 )
PlaySound "mysticism cast"
player->RemoveItem "item_a", 1 ;this line crashes the game!!!
player->AddItem "item_b", 1
set state to 0
elseif ( button == 1 )
set state to 0 ; once done, reset everything
endif
endif
end
It worked nice enough without the RemoveItem function in it, but with that line it would crash. The reason was that this script was attached to item_a, and thus the running script would be removed with it, which apparently crashes the game. So the above idea had to be handled via a global script.