What is Tamriel Rebuilt?
Random ScreenshotsStryker named new Head of Interiors (5. May 13 18:34)
Stryker named Assistant Head of Characters (3. Feb 13 13:54)
2012 in Review (31. Dec 12 13:51)
Our New Head of Characters is Not! Also Int Reviewing Empty! (13. Dec 12 17:56)
Sacred East updated to Version 1.2 (11. Oct 12 10:30)
New Core Shuffle! (7. Oct 12 23:20)
Sacred East (6. Jun 12 00:36)
New Head of Interiors (19. Mar 12 11:12)
2011 in Review (3. Feb 12 12:20)
Why is our new Head of Quests, awesome! (30. Jun 11 15:20)
Form and Function
I know you must be begging for another break by now, so let's get back on track, and get Audrey to actually do something for us.
Just need to take one more, brief (I promise!) detour.
Now that you've got a good idea for how to ask the questions, all you really need to know next is what kinds of questions you can ask, and what sorts of answers you can give. And all that's really required of you here is to start learning some functions.
A function is what you could think of as a separate script that runs, and returns a result for you. There are functions that help you with questions (they retrieve information for you), and there are functions that help you with answers (they carry out actions). You'll generally already have a feel for what kind of information you need, or what kind of action you need to perform, so what you would need to go in search of is a function that satisfies your needs.
There's a reference of most available functions available right from the script editor, and you should get used to using it as reference. (I am certainly not going to cover all of the functions here for you.) In your script editor, just go to Help, and select Functions. There are basic explanations for most (albeit sometimes rather vague), and even examples for a few. If you're ever not sure if there's a function for what you need, or if a certain function will do what you need (or think it should), then heading to a public forum to get help should be your second alternative. (Testing it for yourself is always your first.)
In the case of our current script, we need:
A function for telling how many of a certain item a player has.
A function for displaying a message to the player.
A function for removing items from a player's inventory.
I've done your homework for you, just this once. The functions you need, respectively, are:
The syntax for each of these functions is highlighted in the Help page I referred you to a moment ago, so go check on them now. Here's how each of the functions will be implemented:
begin DS_hw_audrey_sc if( GetItemCount "food_kwama_egg_02" == 3 ) RemoveItem "food_kwama_egg_02" 3 elseif( GetItemCount "food_kwama_egg_02" < 3 ) MessageBox "Feed me, Seymour!" elseif( GetItemCount "food_kwama_egg_02" > 3 ) RemoveItem "food_kwama_egg_02" 4 endif end
Okay, so I lied. We actually need to make one more detour. The code above isn't quite complete, just yet. We still need a way to point out specifically that we're using these functions on the player (as opposed to, say, Audrey, or some NPC).
Functions are actually performed on objects. Objects are what you already think of as objects, in TESCS. Audrey is an object, the player is an object (which you'll actually find in the NPC tab), even the script you're writing is an object.
You name which object you'd like to run the function upon using the arrow-pointer, "->", like so:
This runs the GetItemCount function on the player, checking to see how many of the food_kwama_egg_02 item the player has. You could just as easily run this function on an NPC, or even a container.
Note that if you don't specify an object for a function to run upon, it will generally be run upon the script's object itself. So the code above would be running all of those functions on Audrey, which isn't going to accomplish what we want. There are some exceptions - and I did say generally just back there - the MessageBox function is one of them. It's pretty obvious that you want the player to see the message, since it's not going to do an NPC or a plant any good.
Here's the updated code, which is now complete and ready to be tested:
begin DS_hw_audrey_sc if( player->GetItemCount "food_kwama_egg_02" == 3 ) player->RemoveItem "food_kwama_egg_02" 3 elseif( player->GetItemCount "food_kwama_egg_02" < 3 ) MessageBox "Feed me, Seymour!" elseif( player->GetItemCount "food_kwama_egg_02" > 3 ) player->RemoveItem "food_kwama_egg_02" 4 endif end
You save a script and prepare it for use by going to Script, Save, or clicking the floppy-disk icon. (I realize some of you younger kids might not know what a floppy disk is. It's like a smaller CD, kind of. Except it's square. On the outside. Yes, I'm being facetious! Geez.)
The script editor for TESCS will actually check your syntax, at this point, and tell you if it thinks anything is wrong. Don't come to rely upon this. It only tells you if it sees something wrong, but it won't see every kind of mistake, and it certainly won't tell you if your code isn't going to do what you want it to do. You shouldn't get any errors if you've used my own code above, verbatim. If you typed it in yourself, check for typos. (And get used to checking for typos. It's generally the most common form of bug, especially when you're still getting started with scripting.)
You'll also need to remember to assign this script to our plant. (And click Save to make it permanent.)
Now save your ESP, apply it as a Data File for some Savegame you have in or around Vivec (or a major Mage Guild), and go have a look at Audrey.
Hungry little guy, aren'cha? I've captured the above specifically as a commemorative of our very first bug.
Turns out we're missing something, something pretty vital, in our script - and as it just so happens, this is the perfect opportunity for me to introduce one very important concept about scripts in Morrowind.
They're constantly running, so long as you're within range of them. (That usually means "within the same cell as" them.) So in fact the script we designed is running from the moment you enter the Mage's Guild, asking the same question(s) over and over again, and (certainly once you've run out of large kwama eggs, if you had any) supplying the same response every time. Scripts can be run several times per second, too, which is why it appears that there are exactly three of the messagebox - three is simply the most messageboxes the game can display at once, and since they keep scrolling by, they never "seem to disappear", as you would generally anticipate it should. (This illustrates a key point to debugging: properly understanding your results.)
What we want instead is for the question-answer block to only apply when the player moves up to Audrey, and activates Audrey.
This means adding another question, within which our original question-answer block will be nested. The question this time is, "Has the player activated Audrey?" and the function we use to check this is OnActivate. The OnActivate function will return 1 immediately after the player activates an object. Since activating an object is an instantaneous event, the OnActivate function will return 0 the very next pass through the script. By "return", I mean we can perform an equality check on what appears to be the function itself, in the same way we've been performing equality checks on the GetItemCount function. (We're actually performing an equality check on the value that this function returns.)
begin DS_hw_audrey_sc if( OnActivate == 1 ) if( player->GetItemCount "food_kwama_egg_02" == 3 ) player->RemoveItem "food_kwama_egg_02" 3 elseif( player->GetItemCount "food_kwama_egg_02" < 3 ) MessageBox "Feed me, Seymour!" elseif( player->GetItemCount "food_kwama_egg_02" > 3 ) player->RemoveItem "food_kwama_egg_02" 4 endif endif end
Not that much more complex, is it? Note how the OnActivate function is being called without an object specified. That's because, in this case, we want it to be called specifically for the current object - Audrey.
At this point there's something that I ought mention, since you may see me using it in later examples of code. The equality check "OnActivate == 1" can technically be abbreviated, to just:
begin DS_hw_audrey_sc if( OnActivate ) if( player->GetItemCount "food_kwama_egg_02" == 3 ) player->RemoveItem "food_kwama_egg_02" 3 elseif( player->GetItemCount "food_kwama_egg_02" < 3 ) MessageBox "Feed me, Seymour!" elseif( player->GetItemCount "food_kwama_egg_02" > 3 ) player->RemoveItem "food_kwama_egg_02" 4 endif endif end
The shortcut takes some careful examination to understand completely, though I've actually already given you enough information to figure it out on your own. (If you want a challenge, then try to do so - or just read on, if you're stumped.)
Any time a question is asked, "if" is looking for either a True or False solution to the particulars you have supplied. In the case of, "if( player->GetItemCount "food_kwama_egg_02" == 3 )", for instance, all that "if" is concerned with is whether the stuff inside the parantheses is True, or False. You can imagine this is determined as a series of "abbreviations" (or deductions):
if( player->GetItemCount "food_kwama_egg_02" == 3 ), if( 3 == 3 ), if( TRUE )
That is, the GetItemCount function first returns 3 (the player has 3 large kwama eggs), the 3 on the left side is compared (an equality check) with the 3 on the right, the comparison ("equal to") is true, and therefore "if" says, "This question was true, so I will execute the answer that appears below." (Or, on the other hand, "This question was false, so I will proceed to the next alternative, and determine whether it is true." until endif is reached.)
The function "OnActivate" returns a value: 1, when the object has been activated. 0, otherwise. To the "if" command, the number 1, all by itself, is technically True, and 0, all by itself, is False. So you could, in fact, write the following very error-free code, and run it:
if( 1 ) MessageBox "True." else MessageBox "You will NEVER see this message!" endif
By simply using the return value of the OnActivate function to determine True or False, I save a little typing, and my code also looks just that much cleaner (and slightly more readable). Plus, it's more "idiomatic", which may not seem too important to you now, except that it seems to be a slightly more arrogant method of scripting. It's up to you, whether you prefer the shortcut, or the fully qualified equality check.
Save up your ESP with the modified (corrected) script, and run another test. Everything should be working as designed, now. Woot!
|The content of this site is © by the Tamriel Rebuilt community. Morrowind, Oblivion, their expansions, and their content is © Bethesda Softworks.|