Oblivion Mod:Cobl/Modding/Inventory Tracking
Background[edit]
COBL's Inventory Tracking provides an easy way for modders to monitor changes in the player's inventory, essentially creating OnPickup/Drop Item type blocks. This is currently used by the Keychain mod to move any keys the player picks up to the keychain (a remote container). It could also be used to automatically determine whether the loot the player just picked up is worth keeping or should be trashed, automatically equip better armour, or continuously supply arrows as the player runs out.
Requirements[edit]
The player will need OBSE (>= v.0012) and Pluggy (>= v56) to use the Inventory Tracker.
Specifics[edit]
The Inventory Tracker scans the player's inventory every 2 seconds. If the contents have changed since the last scan, the change (item's base reference, count, etc.) is marked on the appropriate list. There are, currently, 5 lists that can be broken down into 2 categories:
- Gains
- Increased items - Player has more of these items since the last scan. Marks the items' base references and changes in count.
- Added items - Items that the player didn't have in the last scan. Marks the items' base references.
- New items - Items that the player has never had before (based on BaseID). Marks the items' base references.
- Loses
- Decreased items - Player has fewer of these items since the last scan. Marks the items' base references and changes in count.
- Removed items - Player has lost the entire stack of these items. Marks the items' base references.
Example[edit]
The player has 5 Iron Arrows, 1 Iron Cuirass, and 50 Gold. Inventory tracking is initialized, makes the first scan, and the lists are updated:
Increased - 5 Iron Arrows, 1 Iron Cuirass, 50 Gold Added - Iron Arrows, Iron Cuirass, Gold New - Iron Arrows, Iron Cuirass, Gold
The player doesn't do anything for the next 2 seconds, IT makes the second scan, and updates the lists:
No changes
The player picks up 20 Gold, 1 Leather Cuirass, drops the Iron Cuirass and 2 Iron Arrows, IT makes the third scan and updates the lists:
Increased - 20 Gold, 1 Leather Cuirass Added - Leather Cuirass New - Leather Cuirass Decreased - 2 Iron Arrows, 1 Iron Cuirass Added - Iron Cuirass
Finally, the player picks up the Iron Cuirass again, IT makes the fourth scan and updates the lists:
Increased - 1 Iron Cuirass Added - Iron Cuirass
Taking requests[edit]
If you'd like the Inventory Tracking to do something else, post it in this section and I'll see what I can do.
Eat/Drink list[edit]
A list of ingredients and potions that the player has eaten or drunk. As of now, the Remove list is indiscriminate about how the item was removed and all of the various methods (via script, dropping the item, selling the item, or eating the item, etc.) are treated the same way.
As of now, I'm thinking this would be a single list and you'd need to use IsFood, IsIngredient, and IsAlchemyItem to determine whether it's food or drink.
Quick Guide[edit]
Initialize the system[edit]
- Write down an EditorID from your mod - anything except Globals will work
- Create a quest with the name of your choice
- Mark it as "Start Game Enabled"
- Create this quest script (replace the ---s with the name of your quest)
scn ---Script long Warning begin GameMode SetStage --- 0 if (Warning == 0) set Warning to 1 messagebox "You need COBL v1.35 or later in order to use this mod. Please visit http://planetelderscrolls.gamespy.com/View.php?view=OblivionMods.Detail&id=3508 for more information and the download." return endif if (Warning == -1) ;Start a quest (see next step), add items, enable objects, etc. to get the player started with your mod StopQuest --- endif end
- Attach the quest script to "YourQuest"
- Goto the Quest Stages tab
- Create a new stage, leave the index as 0
- Create a new Log Entry (don't worry - it won't pop up, it's just needed for the Result Script)
- Paste this in the Result Script box
set cobInvTrackingInitFAR.rInUse to AnyRefFromYourMod ;Use the EditorID that you wrote down earlier ;set cobInvTrackingFAR.RunInCombat to 1 ;If you'd like Inventory Tracking to run during combat cobInvTrackingInitFAR.Activate cobGenActRef, 1 if (cobInvTrackingInit > 1) set Warning to -1 endif
Using the lists[edit]
I suggest using a quest as it will run all the time. You can use an object, but to be safe make sure it's always running (use the "Set" trick - set a variable on itself in GameMode and MenuMode).
- Create a quest with the name of your choice
- Choose which list you want to track
- Create this script: (where you see ---s, replace them with the appropriate name of the list - New, Add, Remove, Inc, or Dec)
scn YourQuestScript float fQuestDelayTime long ScanNumber long iChange ref rItem begin GameMode set fQuestDelayTime to 1.5 if (cobInvTracker.iScan != ScanNumber) set iChange to 0 Label if (iChange < cobInvTracker.---Changes) set rItem to (GetInArray cobInvTracker.a--- iChange) ;if you're using a list with a count, such as Increased or Decreased, check the Count array for the count ;set ItemCount to (GetInArray cobInvTracker.aIncCount iChange) ;Run your code, make checks, etc. set iChange to (iChange + 1) Goto endif set ScanNumber to cobInvTracker.iScan endif end ;Copy the GameMode block for MenuMode, with one special check to keep it from running while the Main Menu is open begin MenuMode if (MenuMode 1044) return endif set fQuestDelayTime to 1.5 if (cobInvTracker.iScan != ScanNumber) ...
- Attach the script to the quest
- If this is on a quest, you can set "fQuestTimeDelay" to 1 or 1.5.
- You should also add a special part to the top of the MenuMode block to make sure it won't run during the Main Menu
Example from Keychain[edit]
Initialization script
scn P1DkeyInitScript ;Checks and requirements ;COBL-ized ;need to activate using dummy ref instead of player long Warning long Warning2 begin GameMode SetStage P1DkeyInit 0 if (Warning == 0) set Warning to 1 messagebox "You need OBSE v0014a or higher in order to use the Keychain. Please visit http://obse.silverlock.org/ for more information and the download." return endif if (Warning2 == 0) set Warning2 to 1 messagebox "You need COBL v1.36 or later in order to use the Keychain. Please visit http://planetelderscrolls.gamespy.com/View.php?view=OblivionMods.Detail&id=3508 for more information and the download." return endif if (Warning == -1) && (Warning2 == -1) StartQuest P1DkeyAdd StopQuest P1DkeyInit endif end ;Result Script ;Stage 0 - Make sure the player has installed and is using OBSE >= 14 and COBL >= v1.36 ;SetStage cobSigSE 0 ;if (cobSigSE.Version > 13) ; set P1DkeyInit.Warning to -1 ;endif ; ;set cobInvTrackingInitFAR.rInUse to P1DkeyChain ;cobInvTrackingInitFAR.Activate cobGenActRef, 1 ;if (cobInvTrackingInit > 1) ; set P1DkeyInit.Warning2 to -1 ;endif
Keychain script (The tracking is split across this and the following Hooking script)
scn P1DkeyChainScript long IsInPlayerPossesion ;If not in player possesion, won't do anything long ScanNumber ;Keeps track of the last inventory tracking scan ... ;Pick up new keys begin MenuMode if IsInPlayerPossesion if (cobInvTracker.iScan != ScanNumber) if (P1DkeyContainer02.GetScale == 1) ;Keychain is "Turned On" if cobInvTracker.AddChanges set P1DkeyHook.UseIT to 1 P1DkeyHook.Activate cobGenActRef, 1 endif ... endif set ScanNumber to cobInvTracker.iScan endif endif end begin GameMode if IsInPlayerPossesion if (cobInvTracker.iScan != ScanNumber) if (P1DkeyContainer02.GetScale == 1) ;Keychain is "Turned On" if cobInvTracker.AddChanges set P1DkeyHook.UseIT to 1 P1DkeyHook.Activate cobGenActRef, 1 endif ... endif set ScanNumber to cobInvTracker.iScan endif endif end
Hooking script
scn P1DkeyHookScript long UseIT ;Use the inventory tracker long iInv ref rItem long KeyCount long StopSpam ;Used to stop message spam as the keys are taken from the player begin onActivate set iInv to 0 set StopSpam to 1 Label if UseIT if (iInv < cobInvTracker.AddChanges) set rItem to (GetInArray cobInvTracker.aAdd iInv) else set rItem to 0 endif else set rItem to (player.GetInventoryObject iInv) endif if rItem if (IsKey rItem) if (rItem != P1DKeychain) ;... set KeyCount to (player.GetItemCount rItem) P1DkeyContainer02.AddItem rItem KeyCount if StopSpam set StopSpam to 0 if UseIT Message " " Message " " else message "Added loose keys to Keychain" message "Added loose keys to Keychain" endif if MenuMode con_ToggleMenus endif endif player.RemoveItem rItem KeyCount Label 1 ;An engine bug may require multiple RemoveItem calls set KeyCount to (player.GetItemCount rItem) if KeyCount player.RemoveItem rItem KeyCount Goto 1 endif if UseIT set iInv to (iInv + 1) endif ... endif Goto endif if MenuMode if (StopSpam == 0) con_ToggleMenus ;Refresh inventory menu if necessary player.EquipItem P1DKeychain player.UnEquipItem P1DKeychain endif endif ;Reset inputs if UseIT set UseIT to 0 endif end
Advanced[edit]
Pluggy[edit]
Pluggy is fairly unique, and I would suggest you read the Intro to Pluggy Arrays and keep the list of functions available as you read this.
Initializing the system[edit]
Use the script as in the Quick Guide. Here's a description of the various parts and options:
Registration System[edit]
Inventory Tracking uses a registration system so it can shut itself down if the player de-activates your mod. Before you activate the Initializer, make sure to set its rInUse variable to a reference from your mod. The reference can be anything new in your mod: base object of an item, specific reference of an object or item that your mod places in the world, a quest, etc. (A specific example that won't work - if you edit a vanilla item, i.e., reduce the weight of a Silver Shortsword, the item is still from "Oblivion.esm" and won't work. If you make a new Silver Shortsword base object, that will work.)
Running in Combat[edit]
By default, Inventory Tracking will stop while the player is in combat. If you need to track items in combat (i.e., lost arrows) then set the RunInCombat variable to 1 before activating the Initializer.
Version Number[edit]
cobInvTrackingInit can be thought of as a version number. Use the following guide to determine which version you need.
Version | COBL version | Changes |
---|---|---|
1 | v1.35 | First version - do not use |
2 | v1.36 | Fixed a MenuMode bug, first usable version |
Some Background info[edit]
Variables[edit]
All of the variables that you'll be using are on the quest "cobInvTracker". They're on the script "cobInvTrackerQS" under the ";Global" section. You will need to refer to them as any other external quest variable and prefix the variable with "cobInvTracker.".
When does it run?[edit]
Inventory Tracking runs during most of GameMode and MenuMode. It won't run while the player is in combat (unless it's been set to run during combat) and won't run during the Options menus or Messageboxes.
Using the lists[edit]
Scan Index (cobInvTracker.iScan)[edit]
The scan index is changed after every new scan. Note that it's changed, not necessarily increased. So the check should be
long ScanNumber ... begin GameMode if (cobInvTracker.iScan != ScanNumber) ;Check the lists for changes set ScanNumber to cobInvTracker.iScan endif end ;Need the same for MenuMode as it continues to run begin MenuMode if (cobInvTracker.iScan != ScanNumber) ;Check the lists for changes set ScanNumber to cobInvTracker.iScan endif end
... begin MenuMode if (MenuMode 1044) return endif ...
List Updates[edit]
After every scan a "Changes" variable is updated for each list (AddChanges, RemoveChanges, etc.). This is the number of changes that occurred for each list. For the examples above
Scan 1
List | Changes |
---|---|
Increased | 3 |
Added | 3 |
New | 3 |
Decreased | 0 |
Removed | 0 |
Scan 2
List | Changes |
---|---|
Increased | 0 |
Added | 0 |
New | 0 |
Decreased | 0 |
Removed | 0 |
Scan 3
List | Changes |
---|---|
Increased | 2 |
Added | 1 |
New | 1 |
Decreased | 2 |
Removed | 1 |
Scan 1
List | Changes |
---|---|
Increased | 1 |
Added | 1 |
New | 0 |
Decreased | 0 |
Removed | 0 |
This number is very important! The arrays will not be "shrunk" after each scan. For instance, on the second scan (inventory doesn't change) the lists actually look like the first:
Increased - 5 Iron Arrows, 1 Iron Cuirass, 50 Gold Added - Iron Arrows, Iron Cuirass, Gold New - Iron Arrows, Iron Cuirass, Gold
However, the Changes variables will all be 0 so you should know that the lists should be ignored.
Use a check, such as
if (iInv < cobInvTracker.AddChanges)
to make sure you don't use information from old scans.
The lists[edit]
The lists themselves are arrays. For instance, on the first scan they will look like this
Increased List
Index | Item (from array aInc) | Count (from array aIncCount) |
---|---|---|
0 | Iron Arrow | 5 |
1 | Iron Cuirass | 1 |
2 | Gold | 50 |
Added List
Index | Item (from array aAdd) |
---|---|
0 | Iron Arrow |
1 | Iron Cuirass |
2 | Gold |
New List
Index | Item (from array aNew) |
---|---|
0 | Iron Arrow |
1 | Iron Cuirass |
2 | Gold |
Use the function GetInArray to retrieve the information.