This is the second part of my tutorial Become a Software Engineer by modding Fallout 3. If you missed to read the first part I would like to suggest that you read it before continuing, because this post expects you know already what I explained there.
 In this second post I am about to explain how to add behavior to the
Extra Perk mostly by developing
In this second post I am about to explain how to add behavior to the
Extra Perk mostly by developing scripts. On top you
will get an introduction on how to install and use a
Source Code Management System,
which is capable of maintaining a persistent history of important states our mod was in.
It enables us to restore the mod to any of those states later on. This tool
eliminates the fear of breaking our mod when altering it while exploring new
functionality or debugging strange behavior. Doesn't this sound like a
comfortable position to be in?
If you intend to develop the Extra Perk (which I use as an example throughout this tutorial) you should set up a development environment as described in the first part and implement the features of the yet-do-nothing-perk to catch up to the point where this tutorial continues.
Let's recap what to expect from the perk
The requirements can be stated as follows: starting from the moment the Player picks the Extra Perk, he has to be rewarded with an additional perk once per player level, as soon as he gained at least half of the experience points needed to reach the next level. At the same time all experience points he gains have to be reduced by 50%.
Sticking to the Top-Down approach we have to think about the next smallest feature of value we have a good idea of how to implement it. Most often picking a major feature and reducing it repeatedly produces a small feature candidate. Let's try:
- Player is rewarded with an additional perk once per level after half of the experience points required for next level are gained.
- Player is rewarded with an additional perk once per level after experience points are gained.
- Player is rewarded with an additional perk once per level.
The last statement seems much less complicated than the first statement while still being part of the original feature. Another possible outcome as the last statement would have been:
- Player is rewarded with an additional perk after experience points are gained.
Both statements are equally valid but the one above would be a little bit annoying (gaining so many additional perks). Therefore we pick the requirements of statement 3. as our next feature set to be added to the Extra Perk.
What does the blueprint look like?
In theory we would like to register some callback to the main loop (run by the Fallout 3 game engine) at the moment when the Player picks the Extra Perk, to be called on the event when the Player levels up. The functionality of the callback would be to call a function (provided by the G.E.C.K. API) showing up the Perk-Selection-Dialogue which is part of the level-up dialogues we all are familiar with.
But sadly the world is not shaped as we might wish. Using the mechanisms provided by the G.E.C.K. makes things a bit more complicated. Take a brief look at the diagram below:

What you see is the collaboration structure of four objects (belonging to
three different object types) involved in detecting when the Player levels up.
Let's have a closer look at each object and its responsibility.
The rectangle labeled Extra Perk is the
perk object we created in
Part 1
of this tutorial. It has a single responsibility: to start the script
Extra Perk Quest Script which
repeatedly checks if the Player has leveled up. But a perk object
can't start a script by itself so we have to find another way to
accomplish this.
Scripts are always part of a quest, an item
or an effect object. Because of the fact, the Extra Perk
has to start tracking the current level of the Player as soon as the Player
picks the Extra Perk and stop tracking when the Player has reached
the maximum player level, a quest is the proper object to attach
the Extra Perk Quest Script
to.
 The rectangle labeled
Extra Perk Quest is an object of type
quest. Quests can be started either explicitly by
calling the function
startQuest or
implicitly by setting the quest to one of its stages.
When a quest gets started, the script attached to it
will be run repeatedly until the quest is stopped. Knowing this,
we can rephrase the responsibility of the
Extra Perk object as: to start the
Extra Perk Quest. This can be
achieved by adding a perk entry which will set the
quest to a stage, the one acting as the
quest initializer, when the Player picks the
Extra Perk.
 A
A quest may define many stages to track the Player's
progress. The Extra Perk has no need to track any progress but
instead it needs to remember the level of the Player at the moment when he
picked the Extra Perk. Because this has to be done only once, we
will add a stage to the quest acting as an
initializer, setting the variable, defined by the
Extra Perk Quest Script, to the
current level of the Player. The functionality of the initializer is defined by
another script, embedded into the quest and associated
with the initializer stage.
Perhaps you are now overwhelmed by my explanations, but be assured that things are not as scary as they might sound. I will guide you through everything in detail now, so: don't panic!
Starting the quest when picking the perk
 To enable the Extra Perk object to start
the Extra Perk Quest we have to
create a
To enable the Extra Perk object to start
the Extra Perk Quest we have to
create a quest object first. Start up the G.E.C.K. and
mark the Extra Perk.esp as the
Active File.
Hit the  button which will load
the
 button which will load
the Extra Perk.esp file as well as the Fallout3.esm
file (which is the
Parent Master
of the former).
Once all objects defined by both files are loaded, type QWE into
the Filter field of the Object Window to filter out
all objects not part of our Extra Perk mod. Select the object
category Quest, which is a child of the object category
Actor Data, right-click on the right panel and choose
New from the context menu.
 First we have to give the new
First we have to give the new quest object an
Editor ID. To do that select the Quest Data tab and
type QWEExtraPerkQuest into the field labeled ID.
The Editor ID will be used later on by the
Extra Perk object as a
handle to
refer to the
Extra Perk Quest object.
 Than we have to add a
Than we have to add a stage to the quest which for
the moment will only start the
Extra Perk Quest when set by the
Extra Perk object. To achieve this select
the Quest Stages tab, right-click on the left panel and choose
New from the context menu. Leave the index number at
0 and hit the  button.
button.
 The last thing we have to do is
triggering
the start of the
Extra Perk Quest on the event when
the Player picked the Extra Perk. This can be achieved by adding a
The last thing we have to do is
triggering
the start of the
Extra Perk Quest on the event when
the Player picked the Extra Perk. This can be achieved by adding a
quest perk entry
to the Extra Perk object. Select the
object category Perk which should show only one perk
object on the right panel (the QWEExtraPerk) due to the
QWE filter applied. Double-click the QWEExtraPerk to
open the perk dialogue. Place the mouse inside the Perk Entries
panel and right-click. Select New from the context menu.
 Select the radio button labeled
Select the radio button labeled Quest and select from the
drop-down menu the QWEExtraPerkQuest. Make sure the
Rank is set to 1 and the Stage to
0. Hit the  button.
The
 button.
The Perk Entries panel should show one entry of type
Quest (make sure your entry looks like the image displayed
below).
 
 
Hit the  button once again and
save
 button once again and
save
 the mod. We are ready to load and test the mod. Start Fallout 3
loading the
the mod. We are ready to load and test the mod. Start Fallout 3
loading the Extra Perk.esp mod as described in
Part 1
of this tutorial. Load a proper save-game where the Player has not already
picked the Extra Perk.
 Open the in-game console and submit the
following command:
Open the in-game console and submit the
following command:
showQuestVars QWEExtraPerkQuest.
The console should print the current state of the quest,
indicating that the Extra Perk Quest
is not running.
Submit the following command next:
advLevel.
This should level you up. Distribute your skill points and pick the
Extra Perk.
 Submit the command which shows the quest variables once again (as
described above). Now the console should print the current state of the
Submit the command which shows the quest variables once again (as
described above). Now the console should print the current state of the
quest, indicating that the
Extra Perk Quest is
running.
We achieved our first goal, starting the quest when the Player
picked the Extra Perk. Let's proceed with adding the
script which repeatedly checks if the Player leveled up.
Running a script repeatedly
We managed to start the
Extra Perk Quest. But without
attaching a script to it no tracking will happen. Running a
script repeatedly allocates a portion of available
CPU time. We should always think about when to release a
critical
resource
before even acquiring it. Consuming CPU time when none is
required is as bad as allocating too much of it.
 As soon as the Player reaches the maximum possible level (20 for vanilla
Fallout 3 and 30 with Broken Steel installed) we
should stop the
Extra Perk Quest which implies not
running the
Extra Perk Quest Script anymore.
As soon as the Player reaches the maximum possible level (20 for vanilla
Fallout 3 and 30 with Broken Steel installed) we
should stop the
Extra Perk Quest which implies not
running the
Extra Perk Quest Script anymore.
Next we have to answer the question: how long may we delay rewarding the Player with his additional perk? The answer will define the amount of seconds we wait between two checks, detecting if the Player leveled up.
In my opinion 10 seconds should be fine, because while in combat nobody wants to get disturbed by a Level-Up menu displayed. And outside of combat nobody should really care about getting his additional perk 10 seconds later if it is unlikely that meanwhile a fight might happen. And gaining experience points from fighting is the main source to consider.
Having found two important answers, we are now ready to implement tracking the
Player's current level. Start the G.E.C.K. as always and ease your
development by using QWE as the
infix to filter objects
displayed in the Object Window. Select the object category
Script, which is a child of the object category
Miscellaneous. Place your mouse inside the right panel,
right-click and choose New from the context menu.
 An empty scripting editor should open up. To define the
An empty scripting editor should open up. To define the
Editor ID for a script the first line must
start with the command
ScriptName
followed by one
space
and the Editor ID we want the script to be identified by. To
be able to attach the script to a quest object, we
have to change the Script Type to
Quest,
using the drop-down list located in the middle of the scripting editor's
toolbar. Hit the save button
 located on the left side of the scripting editor, which will compile the
script but does not save it! Leave the scripting editor and hit the save
button
located on the left side of the scripting editor, which will compile the
script but does not save it! Leave the scripting editor and hit the save
button  of the G.E.C.K. to save the newly created
of the G.E.C.K. to save the newly created script object
to the Extra Perk.esp file. We just created the
yet-do-nothing
Extra Perk Quest Script.
Open the Extra Perk Quest object
by double-clicking it. Located at the top-middle of the dialogue window you
will find a drop-down list labeled Script. Select the entry named
QWEExtraPerkQuestScript to attach the
Extra Perk Quest Script to the
Extra Perk Quest. Just below the
drop-down list you will find a check-box labeled
Script Processing Delay. If checked, uncheck it
and enter the number 10 into the field labeled
Default to the right. Hit the
 button and save
 button and save
 the changes to the
the changes to the Extra Perk.esp file.

By ticking the check-box, the script attached to the
quest will run every 5 seconds (the initial default
value of fQuestScriptDelayTime defined by the file
FALLOUT.INI). In my opinion it does not make much sense to rely
on a default value
that might change. When you have to decide if the default value is appropriate,
you need to know to which value it is currently set. If changed later on, the
criterion we used to make our decision is of no value anymore. Why would we ever
want to use the unreliable default value? I do not know.
Taking care of critical resources
 The Extra Perk Quest Script
will run every
The Extra Perk Quest Script
will run every 10 seconds after the
Extra Perk Quest was started, infinitely!
To change this we have to add an execution path to the script,
to stop the Extra Perk Quest as soon as the
Player reaches the maximum player level. Let's discuss the script
in detail.
Line 1: int declares a
variable of type integer, which can be referenced by the
identifier
maxPlayerLevel (within the same
script). A
variable
is a storage location able of holding information of some type, which can be
read and modified. In our case the information is an
integer value. When
declared, the value of an integer variable is 0. Later on we will
assign the maximum player level to the
maxPlayerLevel variable, immediately before
starting the Extra Perk Quest.
Line 3:
begin
and 7: end
demarcates a block of statements to be executed sequentially from top to
bottom. A script may be composed of more than one block, each
defining a different
block type.
The
block type acts as a condition, expressing the expectation about
a context to exist, when the statements of the block are executed.
The block type
GameMode
defines the context when (for example) the Player is exploring the world by
moving around or is fighting enemies. It seems that GameMode is the proper
block type for our script, because it is the same
context Fallout 3 chooses to display the Level-Up
dialogue. Rewarding the Player with an additional perk will use that dialogue
as well.
Line 4: if and
6: endif
demarcates a conditional block, to be executed only if the
boolean expression
(the condition) evaluates to true. In our case the boolean
expression is player.getLevel
>= maxPlayerLevel.
The identifier player is globally available
in all scripts. It is a variable of type
reference,
holding the memory address the player object is stored at. The dot separates
the identifier from the function to be called, using the reference as a
parameter. Literally
player.getLevel
means: get the current level of the Player. And more general
R.F means: call the function F and pass the
reference R as an input parameter to F.
The operator >= checks if the term to its
left is either greater than or equal to the term to its right. Therefore the
statements inside the if -
endif block are executed only if the level of
the Player is greater than or equal to the value stored in the variable
maxPlayerLevel (which we will initialize to
the maximum possible player level later on).
You may ask why we use the operator >=
instead of the operator ==, which checks if the
term to its left is equal to the term to its right, when the player level
can't be greater than maxPlayerLevel? This is
the result of
defensive programming.
If the program (Fallout 3 and all the plugins installed) has a
bug, and the player level is raised above the maximum player level (which some
plugins do), we could miss the moment when to stop the script.
The world is not perfect, so better be safe than sorry.
 When the Player reaches the maximum player level, we stop the
When the Player reaches the maximum player level, we stop the
quest. We don't like to reward the Player with additional perks.
Stopping the quest implies stopping the script,
which means we stop consuming valuable CPU time. The statement
stopQuest QWEExtraPerkQuest
does exactly that. The function stopQuest
expects one input parameter, a handle to the quest
to be stopped.
Add all lines to the
Extra Perk Quest Script. If you can't
remember how to, read the previous chapter once again. Don't forget to save the
script (which only compiles it) and save  the
mod.
 the
mod.
Initializing the quest script
What's left is initializing the quest script. It won't work
correctly as long as the variable
maxPlayerLevel is not set to the maximum
player level.
There are two common approaches to implement a do-once-task: embedding the
initialization code into the script defining the variable,
guarded by a conditional block that ensures the initialization takes place
exactly once, or defining a stage, acting as the
script initializer, triggered when the quest gets
started.
The first approach increases readability by placing the initialization code
close to the code where the variable is defined. But it requires to define an
additional variable (acting as a
flag) only to
track if the initialization took place or not. It also introduces a
conditional block which gets evaluated every time the script is
run.
The second approach increases complexity while distributing the initialization code and the definition of the variable to two different places. But if the execution stack is easily remembered,
- Obtaining a new perk rank activates perk entry
- Perk entrydoes set- questto initializer- stage
- Initializer stageruns associated stagescript
- Stage scriptinitializes quest scriptvariable
each object participating in the collaboration has a well-defined responsibility. The do-once-task gets executed once without the need to add additional code to make this happen. Less code means fewer opportunities to add bugs as well as better maintainability. Reuse of mature code is less likely to have bugs than code freshly introduced.
We already added the initializer stage (the one with an index of
0) to the Extra Perk Quest,
triggering the start of the quest. Now we will associate a
script with the stage, getting executed when the
quest is set to the stage.
 The
The script consists of only one statement (as shown above) which initializes one variable. The pair of commands set and to assigns a value to a variable.
The variable we want to assign a value to is defined in a different script, so we have to refer to it using a fully qualified name. A script of type Quest is treated as belonging to the quest it is assigned to (each quest gets its own instances of the variables defined by the script). Therefore we have to qualify the variable identifier maxPlayerLevel by the Editor ID QWEExtraPerkQuest, being the handle of the quest, the script belongs to.
The value we want to assign to the variable is a value defined by the variable iMaxCharacterLevel, part of the game settings of Fallout 3. Those variables can be accessed using the function getGameSetting expecting one input parameter, the identifier of the variable for which to return its value. So identifiers of variables part of the game settings do not fetch their values, but are used as handles passed to the function getGameSetting which fetches their values instead.
It is questionable if caching the value of the game setting variable iMaxCharacterLevel is the right thing to do. If the value would be changed (for example by installing the DLC Broken Steel), the value stored in the variable QWEExtraPerkQuest.maxPlayerLevel would remain unchanged. I leave it to you to remove the definition of the variable maxPlayerLevel from the QWEExtraPerkQuestScript and replace all its occurrences with the function call getGameSetting iMaxCharacterLevel as a practice. The tutorial will continue using the variable maxPlayerLevel to explain how scripts associated with stages work.
 Open the
Open the QWEExtraPerkQuest object in the G.E.C.K. by double-clicking it and switch to the stage tab by clicking the  button at the top of the window. Select the
 button at the top of the window. Select the stage having an index of 0 (which acts as the initializer), place the mouse inside the Quest Stage Items panel to the right, right click and select New from the context menu showing up. Make sure the newly created Log Entry it is selected and open the associated script by clicking the  button located to the right of a panel labeled
 button located to the right of a panel labeled Result Script.
 
Add the single statement to the embedded stage script and hit the  button. Close the
 button. Close the quest object dialogue and save  the mod.
 the mod.
 Start Fallout 3 loading the
Start Fallout 3 loading the Extra Perk.esp as well. Load a proper save-game and enter the in-game console once again. Submit the command: advLevel and pick the Extra Perk after distributing all skill points. Now submit the command: sqv QWEExtraPerkQuest which should display the value of the maxPlayerLevel variable together with the running status of the quest. The variable was initialized by the script associated with the quest stage having an index of 0.
 Now submit the command:
Now submit the command: player.setLevel 30 (or 20 if Broken Steel is not installed). Leave the console and wait about 10 seconds. Enter the in-game console again and check the quest variables one more time. You should be able to inspect that the quest is not running anymore. If this is the case, the statements defined by the conditional block of the QWEExtraPerkQuestScript were executed, as intended. Congratulations!
Conclusion
We established the collaboration structure composed of four objects, required to repeatedly run a script, started when the Player picked the Extra Perk and stopped when the Player reached the maximum player level. We took care to acquire not too much CPU time and stopped consuming CPU time as soon as the perk completed his task.
I promised to explain more in this post than I have. But the post has already grown to a size much larger than anticipated by me (although I skipped some topics about software engineering I would have liked to explain). The other topics will not be skipped but postponed to Part 3 of this tutorial.
I hope you enjoyed this post nevertheless. Feel free to contact me either by e-mail or leave a comment at the Fallout 3 Nexus Site. If you think this tutorial is worth to be recommended, please consider to endorse it.
Logged Off: Harmlezz
