Unplayable Items
UNPLAYABLE ITEMS - AKA TOKENS By guidobot101
Ok, so you've probably heard about tokens all over the forums by now and are wondering "what are they" or "what's all the fuss about".
Well they are basically unplayable items that allow you to effectively reprogram any actor or even the player. In fact, despite their modest name, tokens are perhaps the most powerful tool that scripters have in the unextended CS. Tokens themselves are really almost that - i.e. they are an object that exists just to get the attached script to run on a target. What is actually important is the 'token effect'.
To create a token:
1) Choose any item in the game that has the Playable switch. These are essentially clothing and weapons. Most favored choice seems to be a ring but it really doesn't matter since it's 3D object will never see the light of day. In fact a base model marked unplayable cannot be placed in game.
2) Copy your choice by saving with a new unique ID. You probably want to use the actual name as a comment as to what the token effect will do, etc.
3) Uncheck the Playable option.
4) Attach/create your object script - your 'token effect'.
To deploy a token on a target simply do the following command from any active script:
actor.AddItem MyToken 1
So what's the point? Well it's mosty about what you can't do with other objects. Here's a list of important token properties:
1) Tokens are always specific to the actor they are applied to, even if that actor was created by PlaceAtMe. In contrast, spells and abilities are added to the base model. (All [new] actor references of the same base model inherit these effects when they respawn.)
2) Local variables are persistant. Scripted spell effects and abilities reset when the actor comes into scope (same cell) as the player, meaning any local variables are re-instantiated (to 0).
3) You can add a token remotely - i.e. to an actor not even in your cell, so long as it is a persistant ref.
4) Token effect scripts are always active and the OnActivate block can be called when the actor is out-of-scope. This is not true of scripts on actors themselves.
5) When [the marked actor is] in scope the GameMode block activates every frame. When out of scope the GameMode block triggers about every 30 seconds or whenever the player moves to a new cell. Additionally it will always fire when the token is first added - meaning that you have an effective OnAdd method.
6) Unlike standard items, the token is never seen in the target's/player's inventory. (This essentially makes up for the fact that inventory items cannot be disabled.)
7) Like spells, tokens can remove themselves or be removed from a calling script (very handy for instant or 1-time effects).
Here's a very useful example. This token effect allows a merchant to initially have a particular spell in their inventory for sale. It is attached as the script to the token (you just made), called LoadSpellToken.
CODE
scn LoadSpellTokenEffect ref target Begin GameMode ; wait for player presence if GetInSameCell player ; add spells to inventory and remove effect set target to GetContainer target.AddSpell MySpell01 target.AddSpell MySpell02 target.AddSpell MySpell03 RemoveMe endif End
To use this particular version I suggest a Quest script. There are other ways to do this but having a startup quest is a good idea for almost any mod involving scripting. Here a skeleton start up quest script, attached to quest ID MyStartupQuest:
CODE
scn MyStartupQuestScript short doOnce ; ...all other game mod variables Begin GameMode if doOnce Return endif set doOnce to 1 ; this is a real unique ref in the std game (must be persistant and unique) <InGameVendor1>.AddItem LoadSpellToken 1 ; another real unique ref to a second vendor <InGameVendor2>.AddItem LoadSpellToken 1 End
Ok so what have we done here? Basically we've added spells to a particular vendor (or vendors) without ever modding any of the vanilla world - not even an activator/sensor placed next to the vendor!
Note in this example you may be able to do the AddSpell directly from the quest script. However, often you may need to add things multiple times or the particular commands may not work until the actor is in scope - hence the GetInSameCell conditional. Conditionals and global variables are often needed to ensure the timing of when token effects are triggered.
ASIDE: This works equally well for basic items, etc. However, much of the time you want to introduce a persistant scripted item in to the game. This is a bit more tricky since objects easily lose their scripts when being moved from 3D (the world) to 2D (an inventory/container). To do this firstly it is a good idea to have a room of your own to hold stuff, even if you can never get to this area from inside the game. The reason is by doing this you will never cause mod conflicts. You then need to
(1) MyObject.MoveTo player
(2) MyObject.Activate player
(3) MyObject.RemoveMe <VendorHiddenContainer>.
These 3 steps must be done in different (successive) frames. A (hidden) vendor container should be used. If you add directly to the vendor, 9/10 times you can bet that vendor will equip this item immediately - and not let go. (This is handy if you require the item to be pick-pocketed.)
Tokens on the player: Very useful for OBSE key programming. It appears necessary to do this in 2 steps:
(1) set tokenRef to player.AddItem MyPlayerToken 1
(2) tokenRef.Activate player
Again, to keep the attached token effect script, these command have to be done in different frames (use a counter). This is probably because of issues with OB expecting message spam for AddItem when added to the player. However, AddItem might work on it's own for you.
Token Abuse: Because tokens are always active make sure you dont add them repeatedly or to almost very NPC you meet (in-game). Sometimes using a spell, ability or other method to get your active script going is more appropriate.
Token Origin: I wish I could say I invented tokens but I didn't. It appears they started out in thread discussions and were eventually put to use by early adopters such as Shuggsywuggsy-the-ferret. Through thread discussions, I have only helped solidify our understanding of how and when to use them.