Scripting Tutorial: Spell Tome
This tutorial will tell you how to create a Spell Tome (or a book that will add a spell to the player's inventory when the book is read). You will create a book, put some text into it, and add a script to it to give the player a spell. If you don't already know how to script anything, or are entirely new to the TES:CS then I suggest that you go and read another tutorial first, then come back here when you know the basic interface. An excellent tutorial for learning the scripting interface is Scripting Tutorial: My First Script.
With that in mind, let's get started!
Tools used in this tutorial
Required |
Starting offEdit
Open the TES:CS and load Oblivion.esm (and optionally whatever previous .esp file you want to add spell tomes to). If you are planning on creating a new plugin data file, go ahead and save it now, call it something like "SpellTomeTutorial". doing this now will avoid any possible crashes when trying to create a new data file later on after you have put in all the hard work putting this together.
Creating the Tome (Book)Edit
Open the Object Window and expand the 'Items' > 'Book' > 'Clutter' categories and click on 'Book'. Now select one of the books in the list (eg 'Book1CheapGuideAnvil'), 'right-click on it, and choose edit. Change the EditorID to something like 'aaaSpellTome' (So that it is easy to find a the top of the books list) and change the name to whatever you want. Also, while you are here, clear any text that is in the box on the right, and make sure that the book has no enchantment, teachings or script (at the moment). Click OK, and when asked if you want to create a new form, choose yes.
The SpellEdit
You cannot create a spell tome without a spell. At this point you can either choose to use an existing spell that came with Oblivion or create a new one. I'm not going to tell you how to create a new spell here, but there are many resources to tell you how. Whichever method you choose, you need the editor ID for the spell. In this tutorial, I am going to use 'StandardFrostDamageTarget1Novice'.
The ScriptEdit
We now need to create the script that we will attach to our book to add the spell. So go ahead and open the scripting window and create a new script. Type this into the window and hit save (NOT THE COMPILE ALL BUTTON!) I will explain how it works in a moment.
scn aaaSpellTomeScript short doonce short buttonpressed int button begin onActivate if doonce == 0 MessageBox "Would you like to learn the Spell of Frost Damage?", "Yes please", "No way, maybe later" set doonce to 1 set buttonpressed to 1 else Message "You have already learned what you can from this Tome" endif end begin GameMode if buttonpressed == 1 set button to GetButtonPressed if button == 1 set doonce to 0 set buttonpressed to 0 Message "Ok - Maybe you can learn later" elseif button == 0 set buttonpressed to 0 player.AddSpell StandardFrostDamageTarget1Novice Message "Use this knowledge wisely" endif endif end
NB: The MessageBox Part should all be on one line - wiki formatting however prevents this.
How the script worksEdit
The first part names the script and declares the variables.
scn aaaSpellTomeScript ;Script name, put near the top of alphabetical list short doonce ;Variable for executing the check only once short buttonpressed ;Has a button been pressed (should we check which one?) int button ;Which button has been pressed?
The OnActivate block executes each time you open the book and asks you if you want the spell if you haven't already learnt it.
begin onActivate if doonce == 0 ;has the player already learnt the spell? ;ask the player if they would like the spell MessageBox "Would you like to learn the Spell of Frost Damage?", "Yes please", "No way, maybe later" set doonce to 1 ;Don't ask them again set buttonpressed to 1 ;tell the script to check what the player answered else ;Tell the player that they have got the spell already. Message "You have already learned what you can from this Tome" endif end
The GameMode Block excutes every frame, checking if a button has been pressed and responding if it has.
begin GameMode if buttonpressed == 1 set button to GetButtonPressed ;find which button has been pressed if button == 1 ;has the player decided not to learn this spell? set doonce to 0 ;tell the script that we should ask the player again set buttonpressed to 0 ;tell it that we have finished checking buttons Message "Ok - Maybe you can learn later" ;confirm the player's choice to him/her elseif button == 0 ;has the player decided to learn the spell? set buttonpressed to 0 ;tell the script we have finished checking buttons ;add the spell (change the name to the EditorID of your spell) player.AddSpell StandardFrostDamageTarget1Novice Message "Use this knowledge wisely" ; confirm the player's choice endif endif end
Putting it all togetherEdit
Now all we must do is wrap the whole lot up together, so let's do it.
Open up your book's editing window and set the script drop-down to the name of your script (it should be at the top). If you cannot find it, edit your script and make sure that you have set the script type to 'object' and that you have saved your script (without generating any errors)
At this point, you can also add text to the book to describe what the book does or tell the player something. Bear in mind that they will read this after deciding whether they want the spell or not.
Click OK on the window and save your mod
TestingEdit
First you must make sure that your Mod is saved, then you need the FormID of your new Spell Tome. Once you have done this, open up the oblivion splash screen and click on datafiles. Make sure that your file is checked and close the window.
Once in game, open up the console and type:
player.addItem [YOURFORMID] 1
replacing [YOURFORMID] with the form ID that you found earlier. Open the book and view the results.
ExtraEdit
ProblemsEdit
The GameMode block will not execute when the menus are opened. The best way around it would be to automatically give the player the spell (as the OnActivate block does run in menus), however, I wanted to show how to use a MessageBox in this context. You could instead use the MenuMode Blocktype, which does run in menus (hence the name) - simple replace:
begin GameMode
with:
begin MenuMode
The script doesn't take into account whether the player has the spell already or not, this could be changed by instead of using the 'doonce' variable, checking if the player has the spell.
BookEdit
If you want the book to open so you can read it, it's simple enough just type Activate after the OnActivate
begin onActivate Activate begin onActivate if doonce == 0 MessageBox "Would you like to learn the Spell of Frost Damage?", "Yes please", "No way, maybe later" set doonce to 1 set buttonpressed to 1 else Message "You have already learned what you can from this Tome" endif end
Now you will be able to read the book.
HomeworkEdit
A similar method can be used on a scroll, using a scripted enchantment instead. This also has the benefit of ensuring that the addition can only be made once.
IronSpine Supplemental - If the script doesn't work?Edit
I precisely followed the instructions of this tutorial, however (for me) the script never triggered. This was not resolved regardless of mode or other minor changes I made trying to figure out why it didn't.
I examined the script of a DLC Tome for comparison. Using that as a template along with the information here I immediately had a successful custom Tome of Alliance with custom spell, in my case a powerful multi-effect spell to cast on friendly NPC for 5min of prolonged assistance in battle.
Use the content of the tutorial and if your script doesn't seem to execute (as mine did not), use the following as a template and see if it starts working.
scn AMLLSpellTomeOfAlliance short buttonPressed short isDone Begin OnEquip Player If isDone == 0 MessageBox "(OnEquip Block) - Would you learn the ways of the Alliance?", "I would.", "No, I would not." EndIf End Begin OnActivate Activate If isActionRef Player == 1 && isDone == 0 MessageBox "(OnActivate Block) - Would you learn the ways of the Alliance?", "I would.", "No, I would not." EndIf End Begin MenuMode Set buttonPressed to GetButtonPressed If buttonPressed > -1 If buttonPressed == 0 ;Add to SpellBook. Player.AddSpell AMLLAlliedDefenderMinorSpell PlaySound SPLAlterationCast Set isDone to 1 EndIf EndIf End
In my case (and perhaps yours) it's OnEquip that triggers, not OnActivate. This is confirmed by the block prefix I added so I could see which is actually being triggered.
Based on my testing, this executes as wanted. Once Yes is selected, subsequent reading of the Tome is just that. Reading. Also, dropping the Tome and picking it back up just yeilds a standard auto read, with take option, and back in inventory just normal reading.
Note the scripts don't appear case-sensitive generally so it's up to you, but for easier reading out of habbit I use Pascal Casing due to my background.
Thanks to the original author of this article for the general knowledge. Tomes open up a hugely interesting way to add true custom spells to the game in a way that feels right and perfectly fits in with the mechanics. Instead of simply using a code to get the object you can of course go stuff it into a bookshelf, chest or anything else and "go get it properly" in-game :)
- IronSpine