Building a better Miria mod

Or: How to get the wife you always wanted

Skill level: Beginner (general familiarity with the basics of using the Fallout 2 Mapper and compiling scripts is required to understand this project).

Tools needed: Fallout 2 Restoration Project 2.0, Fallout Mapper, script compiler/decompiler (I use Noid's compiler), plain text editor (Windows Notepad works fine for what we'll be doing).

Note: The latest version of the completed Miria mod discussed here is available for download (link) for those who may prefer an independent study approach to learning. The download version requires killap's FO2 RP version 2.3 or later, while the tutorial below shows readers how to make a Miria mod for any version.

Introduction

The Fallout 2 modding scene is a difficult place for the beginner. There are a few old tutorials, full of links to files that no longer exist, that cover the absolute baby-step basics of doing a few things (even those are barely adequate, as when I first started modding it took me a week just to figure out how to install the Mapper). Then there are a few tutorials written at a very advanced level that presume the reader already has an in-depth knowledge of the ins-and-outs of the technical details, which can be hard to follow for those starting out. Sadly, there are very few articles written at an intermediate beginner-level giving examples of a project that someone who is still learning the basics can complete on their own.

Of all the "minor" mods made for Fallout 2 by members of the community over the years, perhaps none has been more popular than the "Miria Mod" originally created by Stone-D and updated/added to by others from time to time. With the long-awaited release of killap's Fallout 2 Restoration Project version 2.0, Miria fans will likely start trickling into the various forums once again asking for an updated Miria mod compatible with RP 2.0. Happily, they will find one--modder Grandson of Sam has put out a new version of his "Miria for Real," the latest incarnation of the old Miria mod, that works with RP 2.0. However, the script for this mod is in pretty bad shape and contains several bugs--in fact it's a poor copy of an old Megamod 2.34.0 Miria script with bugs MIB88 fixed long ago for his mod (along with other problems that still remain and are unique to the Miria mod scripts). Although this state of affairs isn't Grandson of Sam's fault as he says in his readme files that he didn't make or modify the mcmiria.int script, I think poor Miria deserves better. After all, we wouldn't want her getting jealous over all the other critters who are getting updated scripts for the Restoration Project.

This also seems like as good a time as any encourage some of the Miria fans out there who are casual players to learn a few things about the modding scene (who knows, perhaps if they learn a few of the basics they'll be inspired to contribute some work of their own down the road).

With all these things in mind, I offer the following example of how to build a better Miria mod. The project is designed to work with killap's Restoration Project 2.0, and I encourage anyone who would like to have some enhancements for Miria in their own game to look at the examples below and have a try at building your own mod. It's fairly easy, and by making your own mod you're certain to end up with something you like since you're in complete control.

There are two parts to the traditional Miria mod:

1) Some level-up protos that enable Miria to advance her skills and toughness, thereby making her a more useful party member compared to the Gotcha!/joke-character approach used by BIS in vanilla Fallout 2; and

2) A new script and dialogue file for Miria, allowing her to:

a) function like a "normal" party member; she can be asked to wait, change her following distance, etc;
b) use the npc armor-change mod idea so her appearance reflects the armor she's currently wearing;
c) enhance her character somewhat by giving her unique and expanded dialogue.

We'll start from scratch in this tutorial and accomplish all those goals. However, we'll also be aiming for more--the new script and additional dialogue I've written for Miria works to greatly enhance the depth of her character, making her more like a "real" (that is, simulated) wife. I mostly worked to enhance Miria in the following ways:

--Miria has certain desires; she wants your attention and affection. She also has an opinion-level about whether or not the two of you have a good marriage; as a blushing newlywed bride she starts off with an average opinion of you, and her opinion will change over time based on how you treat her. If you give her what she wants her opinion will rise, but if you treat her badly or simply ignore her needs her opinion will drop. This should be considered as mainly an enhancement for role-playing, as at the present time Miria doesn't leave you if you consistently treat her badly. I'd like to change that in the future, but for now I just think of her as a traditional type of girl who's committed to the institution of marriage. In real life plenty of people stay with lousy or abusive spouses for years, so I don't think it's a major design flaw. Furthermore, put yourself in Miria's shoes: she's a relatively-naive 19 year-old girl who's led a simple life, yet you've suddenly whisked her away into a wasteland full of dangers and strange people; even if she's not happy with you she would likely stick around just to stay alive/not get captured by slavers/etc.

--As you travel to various places across the wasteland, Miria will take a look around; eventually she may find a spot she likes enough to decide that someday she'd like to settle down there. If Miria's opinion of her marriage to you is high enough, she'll tell you about these dreams for the future and how you fit into her plans after you retire from the world-saving business. This is essentially another role-playing enhancement element. You're free to decide if you'd like to be a good spouse who is committed to making your wife happy, or if on the other hand she'll have to conform to your own vision of the future and just "deal with it." If you ruin her plans (for example, she wanted to move to NCR but you wiped out everyone in the town), she'll adapt by offering a more general plan.

--The script assumes that if you have a lot of bad karma, you're trying to play a wicked character. Therefore your dialogue options with Miria will change to an abusive tone, which is presumably what you'd like to see in that sort of scenario.

Before we get started, I must mention one thing this mod will NOT do--it contains no facility at all for interacting with Miria as a stupid (intelligence less than 4) character. I've never played that kind of game and never plan to, so I didn't spend any of my time incorporating it as an option into my Miria script. However if you enjoy playing a low intelligence character, hopefully what you learn as you read on will enable you to make the necessary modifications yourself.

Part One: Miria is ambitious, and she wants to get better

The first part of the traditional Miria mod (or, indeed, the first step in creating any new joinable npc) is to make some new critter .pro files. These pro files contain all the "stats" and other unique details for each npc and are stored in the game folder Fallout2\data\proto\critters. In the vanilla game Miria only has one pro file (since she isn't able to gain levels in the vanilla game), compared to other npcs who may join the player like Vic (who in theory can level up six times and therefore has seven pro files--one base and six levelups) or Cassidy (who can in theory levelup four times and thus has five pro files).

The traditional Miria mod allows our future wife to level up six times, and this seems to work out well for her in practice. Therefore we'll make six new pro files for Miria in the Fallout 2 Mapper.

Before we get started, we'll need to go to our Fallout2\data\proto\critters folder for our RP 2 installation. All the files there should be set with "read-only" attribute. Since we want to edit some pro files, we'll need to reset them (remove the read-only attribute). Select all the files in the folder, right click on them, select "Properties" on the Windows context menu that appears, remove the check from the box that says read-only, and click "OK." Later when we're done editing our pro files, it will be very important that we remember to set the files back to read-only or Fallout 2 may erase them all when we start the game. To set the read-only attribute, just select all the files in the data\proto\critters folder, right click on them, select Properties from the context menu, put a check in the Read-Only box, and click OK.

Another thing we'll need to do before making our new pro files is to setup the Fallout 2 Mapper for pro file editing. By default the Mapper won't cooperate if you try to edit pro files, so we need to change a few settings in the mapper2.cfg file found in the folder where you have your Fallout 2 Mapper installed. Open this file with a text editor and change the second section of settings to it looks like this:

 [mapper]
default_f8_as_game=1
fix_map_inventory=0
fix_map_objects=0
ignore_rebuild_errors=0
librarian=1
override_librarian=1
rebuild_protos=0
run_mapper_as_game=0
save_text_maps=0
show_pid_numbers=0
sort_script_list=1
use_art_not_protos=0


By setting "override_librarian" to =1, we'll now be able to edit or add pro files in the Mapper; however, the Mapper won't save new or edited game map files unless override_librarian is set to =0. Therefore later (after we finish making our pro files) you'll want to change that particular setting back to zero so the Mapper will be ready to edit maps next time you want to use it for that purpose.

Open the Mapper and select "Critters" from the first menu on the left to bring up the list of critter pro files (Image 1).

Use the arrows to navigate to the very last critter in the list, or just press the "End" button on your keyboard to jump to the end. Click the right arrow to move the list one extra spot to the right, if necessary, so that an empty blue box is available for our new pro at the end of the list (Image 2).

Click on the empty blue box, and then press the Edit button. A grey box will pop up where we will create our first new pro file.

We'll want to enter a name for the pro file, pick a sprite/animation that it will use in the game, set the xp value for Miria if she's killed, make it so we can trade with her, set a bonus to her hit points, set her AI packet (used to govern her behavior in combat), her kill type for the "critters killed" stats, and set a few bonuses to her damage threshold and damage resistance. Basically, just click on a box to enter information in that field and set things up so it looks like this when you're done (Image 3):

One thing to note about the "hit points" field is that this is a bonus to the critter's base hit points. For human (man or woman) type critters, this is usually 29. Therefore by setting the bonus at 29, when Miria levels up for the first time she'll have 58 hit points.

While changing the various settings you may have clicked on the box that says "Advanced." This will bring up a screen where we set Miria's base SPECIAL statistics, as well as her skill point levels. That's something we definitely want to do, so click the Advanced button to bring up something that looks like the in-game character creation screen. Adjust the various stats so the whole thing looks like this when you're done (don't forget to change her sex to female while you're here). (Image 4)

I mentioned before that Miria's base hit points were 29, and by adding another 29 bonus hit points we're setting her to have 58 hit points at her first level-up. Why then does the stat screen say she has 30 (of 58) hit points? Only the makers of the Fallout 2 Mapper know.

I asked you to change various settings on the pro settings (grey box) screen and the Advanced (character creation) screen to match my screenshots to familiarize you with how to change the various settings, but the real fun of making your own mod is to make it your own mod. While I used the following ideas for setting up Miria's levels in my own game in order to make her character conform to my idea of what she should be, you don't need to use my ideas if you don't care for them. Perhaps you'd rather have Miria as a kung-fu master with insanely high unarmed and melee weapon skills, or perhaps you'd like her to be an expert grenade tosser with a high throwing skill. Perhaps you're concerned about keeping her alive and want her to have more hit-points, or you'd like her to serve as your personal physician by giving her high first aid and doctor skills. Whatever you decide, the main thing to keep in mind is that Miria will level-up six times during the course of the game since we're creating six protos for her. Therefore you'll want her skills to gradually rise at each level-up rather than jump to 300 right away. Here's a level-up progression I think is reasonable for Miria, which hardly leaves her as any kind of superwoman when she's at her highest level.

At each additional level-up, Miria gains:

• 20 hit points;
• 20 xp value points;
• a two percent increase to her damage resistance;
• a one point increase in her damage threshold;
• 15 points in her small guns and energy weapons skills;
• 5 points in her unarmed, melee weapons, speech, barter, and outdoorsman skills;
• 4 points in her first aid and doctor skills;
• 2 points in her throwing, sneak, traps, and repair skills;
• 1 point in her big guns, lockpick, steal, and science skills;
• 0 points in her gambling skill (she prefers a sure thing to taking chances).

At certain level-ups, Miria also gains an additional SPECIAL point:

• +1 to her endurance at her first level-up (she's getting into shape running around the wasteland with the Chosen One);
• +1 to her strength at her second level-up (lugging around all the Chosen One's gear is building up her legs and arms);
• +1 to her perception at her third level-up (she's learning to keep her eyes and ears open since danger is everywhere);
• +1 to her agility at her fourth level-up (dodging all those bullets has helped her with her quickness);
• +1 to her luck at her fifth level-up (if a person stays alive long enough to level-up five times in the wasteland, luck must be on their side).

All these gains are added in either the grey box or the character creation screens we looked at above.

Also keep in mind that in many cases if a party member has a higher skill level than the player-character, the player-character will perform a skill-check at the follower's skill level rather than his or her own (for example, when Vic offers to repair things for you since his repair skill is probably higher than yours when you first pick him up in the Den).

When you're finished editing Miria's first level-up pro file, click the "Done" tab in the grey box. Your new pro will appear at the end of the list on the main Mapper screen (Image 5).

If you'd like to change something you just did, click on the picture of Miria and press the Edit button to bring up the grey box again. Otherwise, press the right arrow to bring up another empty blue box at the end of the list, click on it, and then click the Edit button to start working on another new pro file for Miria's second level-up. If you decided to use my skill progression system for Miria, your boxes for this new pro would look like this when you're done (Images 6 and 7):

Note that we increase her numbers cumulatively; in other words she keeps all the gains she got for her first level-up, plus more gains for this new (second) level-up. She gained +1 to her endurance at level one, so we set her endurance to +1 at level two as well (in addition to +1 to her strength, which is her bonus for reaching level two).

Hopefully you have the hang of making new critter pros by now, so go ahead and make four more new pros for her third, fourth, fifth, and sixth level-ups (giving you a total of six new pro files when you're finished). When you're done, exit the Mapper and (as mentioned earlier) set your mapper2.cfg file back to override_librarian=0. Before you forget, this would also be a good time to set all the pro files in your Fallout2\data\proto\critters folder back to Read-only status.

If you've downloaded a Miria mod before, you probably noticed that several files associated with her level gains were included: pro_crit.msg, critters.lst, party.txt, and six numbered files ending with the .pro extension. Since we made our own new .pro files in the Mapper rather than a second-party program, we now have those. The mapper automatically updated our existing pro_crit.msg and critters.lst files as we made the pros (you can open those two files in a text editor to check if you like, the new entries will be at the end of the files), so we now have those. The only other thing we need for Miria to use her new levels is to update the file party.txt, found in the folder Fallout2\data\Data wherever you installed RP 2.0. Open that file in a text editor, find the section dealing with Miria, and change her entry so it looks like this:

 [Party Member 10]   ; pMMaria_PID
party_member_pid=16777380
area_attack_mode=always, sometimes, be_sure, be_careful, be_absolutely_sure
attack_who=whomever_attacking_me, strongest, weakest, whomever, closest
best_weapon=no_pref, melee, melee_over_ranged, ranged_over_melee, ranged, unarmed
chem_use=clean, stims_when_hurt_little, stims_when_hurt_lots, sometimes, anytime, always
distance=stay_close, charge, snipe, on_your_own, stay
run_away_mode=none, coward, finger_hurts, bleeding, not_feeling_good, tourniquet, never
disposition=none, custom, coward, defensive, aggressive, berserk
level_minimum=5
level_up_every=3
level_pids=16777761,16777762,16777763,16777764,16777765,16777766


The line "party_member_pid=16777380" identifies the base level pro file for Miria. In their quest to be mysterious and have something to talk about at parties, the Fallout 2 programmers decided it would be fun to sometimes refer to a pro file by a second number called a "prototype id" (or pid) that is calculated by adding 16777216 to the pro file number. Therefore since Miria's base level pro file in Fallout2\data\proto\critters is 164 (well, 00000164.pro), her pid is 16777380. This calculation is also used in the last line of the above entry, "level_pids=". Assuming you hadn't previously made any new pro files for your RP 2.0 installation, the six new pro files we made earlier were numbers 545, 546, 547, 548, 549, and 550. Adding 16777216 to each of those numbers gives us the "pid" shown on the level_pids= line.

In case you were wondering, 164 is the number of the pro used by the Miria you meet and marry on the Modoc Main Street map. She uses that pro for the rest of the game in vanilla Fallout 2 (since she doesn't level up in that version), or until she levels up the first time and begins to use the first new pro we made for her in our modded game. Strictly speaking it's not necessary for us to edit pro 164 while making our Miria mod since it works fine as it is, but if we wanted to be consistent we could edit Miria's "starting" statistics found as found in pro 164 to bring them into line with our mod (e.g. set her SPECIAL to 4,7,4,8,5,7,5, etc). If we do this, however, the Mapper will place an updated version of pro 164 in our "patch" folder--Fallout2\data\proto\critters--and base pro files for npcs who level up must always be in the file "master.dat" while definitely NOT being present in our patch folder. If the base pro (164 in Miria's case) is in Fallout2\data\proto\critters, the npc will have problems with forgetting their current level and generally exhibit buggy behavior. If you don't know how to place files into master.dat (or even better, how to get rid of master.dat altogether by replacing it with a folder--that's what I do) then research the matter a bit before worrying about Miria's base-level pro 164. As I mentioned, editing pro 164 isn't necessary for our mod to work--it's just a little bonus feature.

Apart from the lines dealing with pids, you can customize the other entries for Miria in party.txt if you like. The line "level_minimum" sets the minimum level the player-character must reach before Miria is eligible to level up. I set this to five, but you may want to put it at 0, 1, 7, 22, or whatever strikes your fancy. The line "level_up_every" governs how often Miria gains a level; in this case, I've set her to be eligible to gain a level of her own every time the player-character gains three levels. I'm not sure what you'd hope to gain by editing the other lines such as "attack_who"; at the moment these give the player the option to issue a full range of commands to Miria in the "Combat Settings" screen while playing the game, but if you wanted to restrict yourself you could erase some of the entries (not a whole line, just an entry like "no_pref" or "on_your_own").

One additional customization for a Miria who can gain levels would be to open up the file misc.msg in Fallout2\data\English\text\game, find the two entries for her float text when she gains a level, and change them to something more interesting than "I learned something new!"

Congratulations! You now know how to make pro files for Miria or any other new npcs you may wish to add to the game. If we were to stop modding at this point, Miria would gain levels like other party members but still behave in her old clingy, stereo-typical ways. The new pro files won't truly be useful unless we give our future wife a script to govern her behavior and a dialogue file so we can communicate and interact with her.

Part Two: Bringing Miria to life

Overview

We have now set Miria to gain experience levels and advance her skills, but she remains a bland and frankly annoying character--as the folks at Black Isle Studios intended when they made Fallout 2. While this may be slightly amusing to a first-time player of the game, after a while the only possible result is that the player will avoid Miria (and her brother Davin) like the plague, since neither is fun to interact with. Therefore the second part of the traditional Miria mod is to give her a new script (the heart of any crpg character) and a new dialogue file (the soul of any crpg character).

The traditional Miria mods do a fairly good job in this regard. Miria is provided with a script that allows her to operate as a "regular" party member who can be asked to wait while the player does a solo mission, etc, as well as a large body of entertaining dialogue providing commentary on locations around the wasteland as well as some basic interactivity (she may blush when you move the "look" cursor over her, and so forth). I tend to approach Fallout 2 as primarily a role-playing game, however; since a role-playing game is only as good as the npcs that populate its landscape, I wanted more for someone who is my character's wife. As noted at the beginning of this article, I've added a whole new layer to interacting with Miria that we'll explore in the remainder of this tutorial.

After I formed some initial ideas about how I wanted Miria to work, I naturally started studying her script from the RP-compatible Miria mod (mcmiria.int) to see how I could adapt it to my purposes. As I went through the script line-by-line, however, it quickly became apparent to me that there several bugs in the code, as well as several things that are not done as efficiently as they could be. Therefore I took a detour by closely studying killap's Miria script from the Restoration Project, and comparing it to the scripts of other RP characters who may join the Chosen One in his or her travels. I decided the way killap's scripts work is much better (and less buggy), and decided to start fresh and rewrite Miria's script based on how "normal" party members function. Although naturally I copied and pasted a lot of code from killap's scripts, I incorporated the functionality of the traditional Miria mod as well as my own enhancements into her as I worked. The result is a bug-free script for Miria (I've tested it extensively and haven't found any noticeable problems) that also serves as a good guide for writing new scripts for new ally npcs in general.

The traditional Miria mod has a fairly good set of dialogue lines for Miria, but as I wrote new dialogue for my additional enhancements I also found myself rewriting many of Miria's lines not only from the Miria mod but from the original vanilla game as well. Hopefully the dialogue shown for Miria will entertain the player, as well as serving as an example of the kinds of dialogue one should consider writing for any new npc who will get a lot of "screen time."

Therefore it should be clear that much of what follows is heavily based on and directly uses a lot of material that was written not by me, but by those who have worked on the traditional Miria mod over the years (Stone-D, Grandson of Sam, and others--hey folks, if you want credit don't forget to put your name or handle in your readme file!) as well as killap, whose RP Miria script I used as the "base" for my own version. Although I made many changes to Miria because they fit the way I like to play the game better, that shouldn't be taken as a knock against the others who have helped shape Miria in the various incarnations of her mod, and I'd like to thank all of those folks. Without their work, I likely would never have been moved to further enhance Miria in the first place.

Our plan in the rest of this article, then will be to first give Miria a new script, and then give her a dialogue file containing a mix of new material, traditional Miria mod material, and original vanilla FO2 material. Although Miria's large script and lengthy dialogue files are shown in their entirety below so you'll be able to copy/paste the text to help you build your own Miria mod, I'll also be explaining some of the changes I made so you'll be able to more easily create your own new npcs in the future.

The Script: Mcmiria.int

If you normally use Jargo's Fallout Script Editor (FSE) to decompile or edit Fallout 2 scripts you'll notice immediately that the code below looks even more complicated than usual. I always work with the old-school Noid's Script Compiler, which formats its code slightly differently than FSE. Scripts in this format also don't use header files, so what may be just a phrase in a script studied in FSE may take a dozen lines or more in Noid's format.

There are some advantages to using the older compiler, however--chief among them is the fact that as far as I know there are no script header source files available for killap's Restoration Project, and FSE requires those to function. Although it would be possible for one to update all the original Fallout 2 header files to include killap's work (a few guesses would be required here and there), that's a lot of very time-consuming work. When working with killap's scripts using Noid's compiler one also must sometimes make (educated) guesses as well about the function of new local variables (but it's usually not too difficult) and one has the advantage that one doesn't have to guess about more complex matters like the content of killap's macros. In any case, my understanding is that FSE can compile scripts written in Noid's format so even if you don't have a copy of the older compiler you should still be able to compile the code below.

If none of these things make any sense to you, don't worry. All that's really required to get this mod working in your own game is that you copy/paste the script text sections below into a plain-text editor and understand how to compile an "ssl" script source file into an "int" FO2 game script. Pasting into a plain-text editor is important, though, as if you paste text from a web-page into a fancy text editor it will retain all sorts of invisible formatting symbols that will cause your script compiler to choke; a plain-text editor (Windows Notepad works fine) removes all these symbols. If everything still seems a mystery, hopefully you'll learn quite a bit as you read the rest of this article.

Global variables are so-called because they may be modified by any script in the game, such as map scripts, object scripts, or critter (actor) scripts. Fallout 2 stores the name, initial state, and id number of all its global variables in a file called vault13.gam, found in the Fallout2\data\Data game directory. Since I plan on doing more work on this mod in the future, I've planned ahead by incorporating the use of five new global variables into this Miria script. Therefore our first step will be to open vault13.gam in a plain-text editor and add these new global variables. Should killap modify the RP in the future by adding more global variables, we would have to move our variables for Miria further down the list as well as change her script to take the resulting new id numbers into account. Currently, though, the last global variable listed in the RP's vault13.gam is number 790; therefore we want scroll down to the end of the file and right after line 790 (GVAR_RP_UNSED_10 :=0) add the following five lines:

 GVAR_MIRIA_ASK1TIME                     :=0;    //      (791)
GVAR_MIRIA_SEXTIME                     :=0;    //      (794)
GVAR_MIRIA_WANTS                     :=0;    //      (795)


then save and close the file.

The script for this mod generally functions in the following way, based on the status of these global variables:

(A) Miria expects things from her spouse (that would be you, Chosen One). She expects her spouse to show concern about how she's feeling at least once for every two months of in-game time that passes; we store the most recent time that has occurred in GVAR_MIRIA_ASK1TIME. Miria expects her spouse to tell her she's loved and appreciated at least once for every two months of in-game time that passes; we store the most recent time that has occurred in GVAR_MIRIA_ASK2TIME. Miria expects her spouse to tell her she's attractive and desirable at least once for every two months of in-game time that passes; we store the most recent time that has occurred in GVAR_MIRIA_ASK3TIME. Her last primary desire is that her spouse fulfill his or her marital obligations by having sex with her at least once for every two months of in-game time that passes; we store the most recent time that has occurred in GVAR_MIRIA_SEXTIME. It may seem unusual or even initially unreasonable that she would expect each of these things from her spouse only once in every two months. However, the passage of "time" is highly distorted during gameplay; I think if these requirements were demanded more frequently they would become onerous, which is in direct violation of the Number One Law of Game Design: If it's not fun to play, forget about it. I think you'll see what I mean about the time issue when you try the mod for yourself. Of course nothing prevents you from fulfilling any or all of the requirements as often as you like if you want to do them more often, and beyond that you're free to change the mod in any way you like in order to make it entertaining to you.

(B) Miria has an opinion about whether or not she has a good marriage to the player-character. Depending upon how well or how poorly the player-character takes care of Miria's four basic desires (A), her opinion-level will rise or fall. If her opinion-level rises high enough, she will feel secure that her marriage is going to last and begin to share her dreams for the couple's future (C). Should the player take drastic action to disrupt Miria's vision of her desired future (for example, she wanted to move to Vault City but the player-character wiped out the town) she'll adapt by offering a more generic plan that the player won't be able to disrupt. In role-playing terms we might say she's a supportive wife who is committed to her marriage, while in game design terms the reason for this accomodation is to allow Miria to continue to be a fun companion who the player will want to keep around.

(C) As the player travels around the wasteland with Miria, she may find that the place she's currently visiting appeals to her so much that she'd like to settle down there someday (after the Chosen One has finished saving the world, of course). This location is randomly chosen from 7 options each time the player enters Modoc for the first time in a new game, adding variablility and replayability to the mod; Miria's "choice" is stored in GVAR_MIRIA_WANTS. However, Miria will only share these plans (which the player can use to shape his or her approach to solving the major quests in the game) if she feels secure that her marriage will last and she is consistently happy with the player-character.

(D) Miria's opinion-level (B) is also modified if her spouse has certain undesirable traits, such as being a drug-addict, being a slaver, having a very poor general reputation, or being a New Reno gang-member. From a design standpoint this isn't intended to penalize a player whose style of play includes such choices, but is instead intended to enhance the player's suspension of disbelief in regard to Miria's character. After all, what wife wouldn't be worried if her spouse had one or more of those characteristics? Nonetheless these things don't influence Miria's opinion-level as much as how well the player-character treats her (A); it's certainly possible to be a jerk to the world but committed to the happiness of loved ones.

In technical terms, the way Miria's wifely AI works is as follows:

• Her opinion-level of her marriage--(B) and (D)--is stored as a score that can range from zero to thirty. Miria's opinion score starts at 10 when she first marries the player-character, and after every two months of in-game time the score is updated in the following way:
• +1 point if the pc recently talked to Miria about how she's doing
• +1 point if the pc recently told Miria how pretty she is
• +1 point if the pc recently had sex with Miria
• +1 point if the pc recently told Miria she's the apple of his/her eyes
• +1 bonus point if all four of the above are up-to-date
• -1 penalty point if none of the above are up-to-date
• -1 point if the pc is a New Reno gangster
• -1 point if the pc is a drug addict
• -1 point if the pc is a slaver
• -1 point if the pc has a bad general reputation (-500 or worse)
• Miria will only share her plans for the future (C) if her opinion score is twenty or more; this means the player-character must consistently pay attention to her (i.e. raise her opinion-level) over many in-game months.

In addition to extra global variables, this mod uses additional local variables for Miria's script. Unlike global variables that can be accessed by any script in the game, local variables are strictly for the use of the an individual script. The game has to allocate memory to store local variables, and therefore needs to know how many are used by each script; this information is stored in the file Fallout2\data\Scripts\scripts.lst. To make sure our new local variables will be used properly, open up scripts.lst and find the entry for mcmiria.int. Change the entry to:

 mcMiria.int	; Miria in Modoc		# local_vars=20


then save and close the file. For some odd reason only the makers of Fallout 2 know, the number of local variables (local_vars) allocated in scripts.lst must always be one more than is actually used in the script. In our new Miria script we'll be using 19 local variables (compared to 14 in the standard RP 2.0 mcmiria.int), therefore we set the number in scripts.lst to 20.

In technical terms, the functions (B) and (D) of Miria's AI discussed above are tracked using local variables 17 and 18 in the new script we're making.

When using the "Noid's compiler" format we're using in this article, local variables in a script are referred to only by their number, such as local_var(7). Figuring out what these local variables do can often be time-consuming, as one must study the entire script and make inferences based upon their usage. A few tips that can make understanding the particular function of local variables easier are:

A) Almost all npc scripts in the game use local variables 0, 1, 2, and 3 for the same purpose, because they include the script header file modreact.h (if you have the Fallout2 Mapper installed, you'll find this file in the Black Isle\Fallout 2 Mapper\scripts\Headers folder for wherever you installed the mapper). The function of these local variables can be deduced from their name, and the number each is assigned is in parentheses:

1. define LVAR_reaction (0) // Holds reaction number value.
2. define LVAR_reaction_level (1) // Holds reaction level: BAD, NEUTRAL, GOOD.
3. define LVAR_got_reaction (2) // Makes sure to modify reaction only once.
4. define LVAR_base_reaction (3)

B) If you have the Fallout2 Mapper installed, looking at the original uncompiled script (*.ssl) for an npc will usually give you some hints as to what most of the other local variables do (based on their somewhat cryptic names). In Miria's case, looking at mcmiria.ssl from the mapper scripts we can see the other local variables she's originally set to use are:

1. define LVAR_Hostile (4)
2. define LVAR_Here_Before (5)
3. define LVAR_Insulted (6)
4. define LVAR_Mode (7)
5. define LVAR_TEAM (8)
6. define LVAR_WAITING (9)
7. define LVAR_FOLLOW_DISTANCE (10)
8. define LVAR_Home_Tile (13)
9. define LVAR_Gave_Weapon (14)

As I mentioned earlier, the number of local variables allocated for a particular script in the file scripts.lst is always one more than the actual number used. Since scripts.lst in killap's RP has 15 local variables allocated for Miria, we can deduce from this that killap didn't add any new local variables to her script while making his mod.

C) If you're using FSE, trying to compile your own header files, or just need some help figuring out how the new local variables I've added for Miria work, I've cryptically named them as follows:

1. define LVAR_DID2100 (15)
2. define LVAR_DID2600 (16)
3. define LVAR_TALLY (17)
4. define LVAR_TALLY_TIMER (18)
5. define LVAR_HAVESEX (19)

which should allow you to follow their function in the script.

Next we move on to the script itself. Open a plain text editor and copy the sections of code below into a text file, in the order they are presented. Note that the code sections are broken up here and there by some commentary to help explain how the script works--don't copy the comments, of course. You'll likely notice that the sections of code are indented in two different ways: some parts with spaces, some parts with tabs. The script compiler doesn't care either way as the only purpose of indenting is to make the code easier to read for people; in general though the parts indented with tabs are parts I changed or wrote myself, while the parts indented with spaces are parts copied without modification from killap's RP 2.0 mcmiria.int script.

At the beginning of any script, we must declare all the special variables and procedures that will be used so the game will be able to decipher what's written. However, we don't need to include global variables, local variables, or map variables since the game already knows about those (they're declared in other files, for example vault13.gam). In the category of special variables declared in the first part of a script we mainly find "temporary" variables, which only exist for a moment at a time while a particular procedure is running. These temporary variables are similar to local variables in that they are unique to this particular script, but unlike true local variables they're forgotten by the game as soon as they have fulfilled their purpose.

 variable ProtoOfItemGiven := 0;
variable ValueOfRollCheck := 1;
variable Scenery_Creation := 0;
variable Scenery_Creation_Hex := 0;
variable Scenery_Creation_Count := 0;
variable Temp_Scenery_Creation_Hex := 0;
variable Scenery_Creation_Ptr := 0;
variable How_Many_Party_Members_Are_Injured := 0;
variable How_Many_Party_Members_Armed := 0;
variable PartyHealingItem := 0;

 procedure checkPartyMembersNearDoor;

 variable global_temp := 0;
variable dest_tile := 0;
variable step_tile := 0;
variable in_dialog := 0;
variable forced_node := 0;
variable restock_amt := 0;
variable restock_obj := 0;
variable restock_trash := 0;
variable removed_qty := 0;
variable Static_Reaction := 0;
variable Evil_Critter := 0;
variable Slavery_Tolerant := 2;
variable Karma_Perception := 0;
variable reaction_bonus_town_rep := 0;
variable reaction_bonus_karma := 0;
variable karma_tmp := 0;

 procedure start;
procedure critter_p_proc;
procedure pickup_p_proc;
procedure talk_p_proc;
procedure destroy_p_proc;
procedure look_at_p_proc;
procedure description_p_proc;
procedure use_skill_on_p_proc;
procedure damage_p_proc;
procedure map_enter_p_proc;
procedure map_update_p_proc;
procedure timed_event_p_proc;
procedure combat_p_proc;
procedure push_p_proc;
procedure Node000;
procedure Node002;
procedure Node010;
procedure Node011;
procedure Node012;
procedure Node013;
procedure Node014;
procedure Node015;
procedure Node016;
procedure Node017;
procedure Node018;
procedure Node019;
procedure Node020;
procedure Node021;
procedure Node022;
procedure Node023;
procedure Node024;
procedure Node025;
procedure Node026;
procedure Node027;
procedure Node100;
procedure Node1001;
procedure Node1002;
procedure Node1003;
procedure Node1004;
procedure Node1005;
procedure Node1006;
procedure Node1007;
procedure Node1008;
procedure Node1009;
procedure Node1010;
procedure Node1100;
procedure Node999;
procedure Node998;
procedure Node996;
procedure Node995;

 variable biff := 0;
variable gun := 0;
variable did_node_11 := 0;
variable did_node_12 := 0;
variable did_node_14 := 0;
variable Perform_Critter_Float := 0;

 import variable modoc_jo_obj;

 procedure Node2000;
procedure Node2100;
procedure Node2200;
procedure Node2300;
procedure Node2400;
procedure Node2500;
procedure Node2501;
procedure Node2502;
procedure Node2503;
procedure Node2504;
procedure Node2600;

 procedure use_obj_on_p_proc;
procedure location_floats;


In the past I've had my doubts about whether the next section, found in virtually every script in the game, actually does anything useful at all or even works. It's supposed to keep automated doors from closing while a member of the pc's party is walking nearby, and I've noticed that some modders update it when they design new npcs while others don't. In the RP 2.0, however, killap added some new automated doors (most noticeably at the gate to Vault City), and the functioning of this code can clearly be seen in action.

procedure checkPartyMembersNearDoor
begin
if (op_party_member_obj(16777278) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777278)) <= 5) then
return(1);
end
if (op_party_member_obj(16777376) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777376)) <= 5) then
return(1);
end
if (op_party_member_obj(16777377) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777377)) <= 5) then
return(1);
end
if (op_party_member_obj(16777305) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777305)) <= 5) then
return(1);
end
if (op_party_member_obj(16777313) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777313)) <= 5) then
return(1);
end
if (op_party_member_obj(16777323) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777323)) <= 5) then
return(1);
end
if (op_party_member_obj(16777352) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777352)) <= 5) then
return(1);
end
if (op_party_member_obj(16777378) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777378)) <= 5) then
return(1);
end
if (op_party_member_obj(16777368) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777368)) <= 5) then
return(1);
end
if (op_party_member_obj(16777379) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777379)) <= 5) then
return(1);
end
if (op_party_member_obj(16777380) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777380)) <= 5) then
return(1);
end
if (op_party_member_obj(16777295) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777295)) <= 5) then
return(1);
end
if (op_party_member_obj(16777381) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777381)) <= 5) then
return(1);
end
if (op_party_member_obj(16777407) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777407)) <= 5) then
return(1);
end
if (op_party_member_obj(16777411) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777411)) <= 5) then
return(1);
end
if (op_party_member_obj(16777412) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777412)) <= 5) then
return(1);
end
if (op_party_member_obj(16777413) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777413)) <= 5) then
return(1);
end
if (op_party_member_obj(16777481) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777481)) <= 5) then
return(1);
end
if (op_party_member_obj(16777558) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777558)) <= 5) then
return(1);
end
if (op_party_member_obj(16777600) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777600)) <= 5) then
return(1);
end
if (op_party_member_obj(16777718) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777718)) <= 5) then
return(1);
end
if (op_party_member_obj(16777719) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777719)) <= 5) then
return(1);
end
if (op_party_member_obj(16777720) != 0) then
begin
if (op_tile_distance_objs(op_self_obj(), op_party_member_obj(16777720)) <= 5) then
return(1);
end
return(0);
end


The next procedure must be found in every script (to initialize it). It shouldn't contain any other functions inside it.

 procedure start
begin
end


The next procedure checks on the object of the script (in this case, Miria) every few moments to see if something needs to be updated; things that are processed here typically include checks to see if the npc has become angry with the player-character, checks to see if the npc should utter some random floating text, and in Miria's case whether or not to begin the "wedding cutscene" with the player-character in Modoc.

procedure critter_p_proc
begin
variable LVar2 := 0;
if ((op_cur_map_index() == 54) and (op_map_var(2) == op_party_member_obj(16777380))) then
begin
LVar2 := op_get_critter_stat(op_self_obj(), 0);
if (LVar2 == op_get_critter_stat(op_self_obj(), 0)) then
op_use_obj_on_obj(op_create_object(482, 0, 0, -1), op_self_obj());
if ((op_get_critter_stat(op_self_obj(), 0) == (LVar2 + 1)) or (op_get_critter_stat(op_self_obj(), 0) == 10)) then
begin
op_set_map_var(2, 0);
LVar2 := 0;
end
end
if (Perform_Critter_Float == 1) then
begin
Perform_Critter_Float := 0;
call location_floats();
end
if (op_party_member_obj(16777380) != 0) then
begin
if ((op_global_var(52) <= -1000) == 0) then
begin
if (((op_local_var(9) != 0) == 0) and ((op_global_var(398) != 0) == 0)) then
begin
if (op_local_var(10) == 0) then
op_set_local_var(10, 6);
if (op_tile_distance_objs(op_self_obj(), op_dude_obj()) > (3 * op_local_var(10) / 2)) then
begin
if (op_anim_busy(op_self_obj()) == 0) then
begin
dest_tile := op_tile_num_in_direction(op_tile_num_in_direction(op_tile_num(op_dude_obj()), op_rotation_to_tile(op_tile_num(op_dude_obj()), op_tile_num(op_self_obj())), op_local_var(10)), op_random(0, 5), op_random(0, 2));
if (op_tile_distance_objs(op_self_obj(), op_dude_obj()) > (3 * op_local_var(10) / 2 * 2)) then
op_animate_move_obj_to_tile(op_self_obj(), dest_tile, 1);
else
op_animate_move_obj_to_tile(op_self_obj(), dest_tile, 0);
end
else if (op_tile_distance(op_tile_num(op_self_obj()), op_tile_num(op_dude_obj())) < op_tile_distance(op_tile_num(op_self_obj()), dest_tile)) then
op_reg_anim_func(2, op_self_obj());
end
end
end
else
begin
if (op_party_member_obj(op_obj_pid(op_self_obj())) != 0) then
begin
op_debug_msg("abandon party: " + op_obj_name(op_self_obj()));
op_party_remove(op_self_obj());
end
if (op_obj_pid(op_self_obj()) == 16777380) then
begin
op_debug_msg("start: set_dude_was_married");
if (op_global_var(6) == 1) then
begin
op_debug_msg("   GVAR_PLAYER_WAS_MARRIED before == " + op_global_var(449));
op_set_global_var(449, op_global_var(6));
op_debug_msg("   GVAR_PLAYER_WAS_MARRIED after == " + op_global_var(449));
op_set_global_var(6, 0);
end
op_debug_msg("finished: set_dude_was_married");
end
if ((op_local_var(8) != -1) and (op_has_trait(1, op_self_obj(), 6) == 0)) then
begin
op_set_local_var(8, -1);
end
op_debug_msg("" + op_obj_name(op_self_obj()) + " has abandoned the party");
end
end
else if (((op_global_var(291) - (op_global_var(291) % 100)) == 200) or ((op_global_var(291) - (op_global_var(291) % 100)) == 300)) then
begin
if ((op_global_var(291) % 100) == 5) then
begin
op_reg_anim_func(2, op_self_obj());
op_move_to(op_self_obj(), (21504 * ((op_global_var(291) - (op_global_var(291) % 100)) == 200)) + (22705 * ((op_global_var(291) - (op_global_var(291) % 100)) == 300)), op_elevation(op_dude_obj()));
op_anim(op_self_obj(), 1000, op_rotation_to_tile(op_tile_num(op_self_obj()), op_tile_num(modoc_jo_obj)));
end
else if ((op_global_var(291) - (op_global_var(291) % 100)) == 200) then
begin
if ((op_global_var(291) % 100) == 27) then
begin
if ((op_party_member_obj(16777380) != 0) == 0) then
begin
if ((op_critter_state(op_self_obj()) bwand 1) == 0) then
begin
if (op_local_var(10) == 0) then
op_set_local_var(10, 3);
op_set_local_var(9, 0);
if (op_has_trait(1, op_self_obj(), 6) != 0) then
op_set_local_var(8, op_has_trait(1, op_self_obj(), 6));
end
op_debug_msg("join party: " + op_obj_name(op_self_obj()));
if (((op_global_var(6) != 0) == 0) and ((op_global_var(449) != 0) == 0)) then
begin
if (106 == 99) then
op_set_global_var(6, 2);
else if (106 == 106) then
op_set_global_var(6, 1);
end
op_debug_msg("set_dude_married");
restock_obj := op_create_object(40, 0, 0, -1);
restock_obj := op_create_object(49, 0, 0, -1);
end
end
else if (op_game_time() >= op_global_var(290)) then
begin
if ((op_global_var(291) % 100) == 2) then
begin
op_float_msg(op_self_obj(), op_msg_string(106, 400 + (20 * ((op_global_var(297) bwand 131072) != 0))), 8 + ((7 - 8) * op_has_trait(0, op_dude_obj(), 22)));
op_float_msg(op_dude_obj(), op_msg_string(106, 401), 8);
op_set_global_var(290, op_game_time() + (3 * 10));
op_set_global_var(291, op_global_var(291) - (op_global_var(291) % 100) + 3);
op_debug_msg("\n SET_STAGE_EVENT == " + op_global_var(291) + " in script " + op_obj_name(op_self_obj()));
end
else if ((op_global_var(291) % 100) == 17) then
begin
op_float_msg(op_dude_obj(), op_msg_string(106, 410), 8);
op_set_global_var(290, op_game_time() + (3 * 10));
op_set_global_var(291, op_global_var(291) - (op_global_var(291) % 100) + 18);
op_debug_msg("\n SET_STAGE_EVENT == " + op_global_var(291) + " in script " + op_obj_name(op_self_obj()));
end
else if ((op_global_var(291) % 100) == 19) then
begin
op_float_msg(op_dude_obj(), op_msg_string(106, 411), 8);
op_set_global_var(290, op_game_time() + (3 * 10));
op_set_global_var(291, op_global_var(291) - (op_global_var(291) % 100) + 20);
op_debug_msg("\n SET_STAGE_EVENT == " + op_global_var(291) + " in script " + op_obj_name(op_self_obj()));
end
else if ((op_global_var(291) % 100) == 21) then
begin
op_float_msg(op_self_obj(), op_msg_string(106, 402), 8 + ((9 - 8) * op_has_trait(0, op_dude_obj(), 22)));
op_set_global_var(290, op_game_time() + (3 * 10));
op_set_global_var(291, op_global_var(291) - (op_global_var(291) % 100) + 22);
op_debug_msg("\n SET_STAGE_EVENT == " + op_global_var(291) + " in script " + op_obj_name(op_self_obj()));
end
else if ((op_global_var(291) % 100) == 23) then
begin
op_float_msg(op_dude_obj(), op_msg_string(106, 412), 8);
op_set_global_var(290, op_game_time() + (3 * 10));
op_set_global_var(291, op_global_var(291) - (op_global_var(291) % 100) + 24);
op_debug_msg("\n SET_STAGE_EVENT == " + op_global_var(291) + " in script " + op_obj_name(op_self_obj()));
end
else if ((op_global_var(291) % 100) == 25) then
begin
op_float_msg(op_dude_obj(), op_msg_string(106, 413), 8);
op_set_global_var(290, op_game_time() + (3 * 10));
op_set_global_var(291, op_global_var(291) - (op_global_var(291) % 100) + 26);
op_debug_msg("\n SET_STAGE_EVENT == " + op_global_var(291) + " in script " + op_obj_name(op_self_obj()));
end
end
end
end
else if ((op_global_var(291) - (op_global_var(291) % 100)) == 100) then
begin
if (op_obj_can_see_obj(op_self_obj(), op_dude_obj())) then
begin
if ((op_global_var(291) % 100) == 1) then
begin
op_float_msg(op_self_obj(), op_msg_string(106, 250 + (10 * (op_get_critter_stat(op_dude_obj(), 34) == 1)) + (20 * ((op_global_var(297) bwand 131072) != 0))), 8 + ((7 - 8) * op_has_trait(0, op_dude_obj(), 22)));
op_set_global_var(290, op_game_time() + (3 * 10));
op_set_global_var(291, op_global_var(291) - (op_global_var(291) % 100) + 2);
op_debug_msg("\n SET_STAGE_EVENT == " + op_global_var(291) + " in script " + op_obj_name(op_self_obj()));
end
end
end
else
begin
if (op_obj_can_see_obj(op_self_obj(), op_dude_obj())) then
begin
if ((op_local_var(4) != 0) or (op_global_var(52) <= -1000)) then
begin
if (op_critter_is_fleeing(op_self_obj())) then
begin
if (op_anim_busy(op_self_obj()) == 0) then
begin
if ((op_tile_distance_objs(op_self_obj(), op_dude_obj()) < 8) or op_obj_can_see_obj(op_self_obj(), op_dude_obj())) then
begin
if (op_anim_busy(op_self_obj()) == 0) then
begin
global_temp := op_rotation_to_tile(op_tile_num(op_dude_obj()), op_tile_num(op_self_obj()));
op_animate_move_obj_to_tile(op_self_obj(), op_tile_num_in_direction(op_tile_num(op_self_obj()), global_temp, op_random(3, 10)), 1);
global_temp := (global_temp + 1) % 6;
while ((op_anim_busy(op_self_obj()) == 0) and (global_temp != op_rotation_to_tile(op_tile_num(op_dude_obj()), op_tile_num(op_self_obj())))) do
begin
op_debug_msg("flee loop: rot == " + global_temp);
op_animate_move_obj_to_tile(op_self_obj(), op_tile_num_in_direction(op_tile_num(op_self_obj()), global_temp, op_random(3, 10)), 1);
global_temp := (global_temp + 1) % 6;
end
end
end
end
end
else
op_attack(op_dude_obj(), 0, 1, 0, 0, 30000, 0, 0);
end
end
if (op_cur_map_index() == 18) then
begin
if (op_tile_num(op_self_obj()) != op_local_var(13)) then
begin
if ((op_tile_num(op_self_obj()) != op_local_var(13)) and (op_local_var(13) != 0)) then
begin
if ((dest_tile == op_local_var(13)) and (step_tile < 0)) then
begin
step_tile := step_tile + 1;
op_debug_msg("step_tile: " + step_tile);
end
else if (op_anim_busy(op_self_obj()) == 0) then
begin
dest_tile := op_local_var(13);
step_tile := op_local_var(13);
op_animate_move_obj_to_tile(op_self_obj(), step_tile, 0);
while ((op_anim_busy(op_self_obj()) == 0) and (op_tile_distance(op_tile_num(op_self_obj()), op_local_var(13)) >= op_tile_distance(step_tile, op_local_var(13)))) do
begin
op_debug_msg("rot: " + op_rotation_to_tile(step_tile, op_tile_num(op_self_obj())));
step_tile := op_tile_num_in_direction(step_tile, op_rotation_to_tile(step_tile, op_tile_num(op_self_obj())), 5 % op_tile_distance(step_tile, op_tile_num(op_self_obj())));
op_debug_msg("step_var: " + step_tile);
op_animate_move_obj_to_tile(op_self_obj(), step_tile, 0);
end
if (op_anim_busy(op_self_obj()) == 0) then
begin
if (op_metarule3(106, op_tile_num_in_direction(op_tile_num(op_self_obj()), op_has_trait(1, op_self_obj(), 10), 1), op_elevation(op_self_obj()), 0) != 0) then
begin
if (op_anim_busy(op_self_obj()) == 0) then
begin
global_temp := op_rotation_to_tile(op_tile_num_in_direction(op_tile_num(op_self_obj()), op_rotation_to_tile(op_tile_num_in_direction(op_tile_num(op_self_obj()), op_has_trait(1, op_self_obj(), 10), 1), op_tile_num(op_self_obj())), 1), op_tile_num(op_self_obj()));
op_animate_move_obj_to_tile(op_self_obj(), op_tile_num_in_direction(op_tile_num(op_self_obj()), global_temp, op_random(2, 5)), 0);
global_temp := (global_temp + 1) % 6;
while ((op_anim_busy(op_self_obj()) == 0) and (global_temp != op_rotation_to_tile(op_tile_num_in_direction(op_tile_num(op_self_obj()), op_rotation_to_tile(op_tile_num_in_direction(op_tile_num(op_self_obj()), op_has_trait(1, op_self_obj(), 10), 1), op_tile_num(op_self_obj())), 1), op_tile_num(op_self_obj())))) do
begin
op_debug_msg("flee loop: rot == " + global_temp);
op_animate_move_obj_to_tile(op_self_obj(), op_tile_num_in_direction(op_tile_num(op_self_obj()), global_temp, op_random(2, 5)), 0);
global_temp := (global_temp + 1) % 6;
end
end
end
else
step_tile := -10;
end
end
else if (op_tile_distance(op_tile_num(op_self_obj()), op_local_var(13)) < op_tile_distance(dest_tile, op_local_var(13))) then
op_reg_anim_func(2, op_self_obj());
end
end
end
end
end

The next section governs what happens when the player-character tries to "pick up" something the npc is holding (i.e. steal or pickpocket from the npc). In Miria's case, if she's not married to the pc this turns her hostile.

procedure pickup_p_proc
begin
if (op_source_obj() == op_dude_obj()) then
begin
if (((op_party_member_obj(16777380) != 0) == 0) or (op_global_var(6) != 1)) then
call Node998();
end
end

The next procedure governs the mechanics of what happens when the player-character tries to talk to Miria. The actual lines of dialogue that will be displayed, however, are organized later in the script in the "Node" procedures. This procedure also contains the mechanics of changing Miria's appearance based on the armor she's currently wearing, since her appearance needs to be updated after we have talked to her and told her to change her armor.

procedure talk_p_proc
begin
variable LVar1 := 0;
LVar1 := op_critter_inven_obj(op_self_obj(), 0);
op_set_local_var(19, 0);
if ((op_global_var(52) <= -1000) == 0) then
begin
if (((op_global_var(291) - (op_global_var(291) % 100)) == 200) or ((op_global_var(291) - (op_global_var(291) % 100)) == 300)) then
begin
if ((op_global_var(291) % 100) == 3) then
op_float_msg(op_self_obj(), op_msg_string(106, 450 + (20 * ((op_global_var(297) bwand 131072) != 0))), 8 + ((7 - 8) * op_has_trait(0, op_dude_obj(), 22)));
end
else if ((op_global_var(291) - (op_global_var(291) % 100)) == 100) then
op_float_msg(op_self_obj(), op_msg_string(106, 251), 8 + ((7 - 8) * op_has_trait(0, op_dude_obj(), 22)));
else
begin
op_script_overrides();
if (op_local_var(6) > 0) then
op_float_msg(op_self_obj(), op_msg_string(106, 150 + (op_get_critter_stat(op_dude_obj(), 34) == 0)), 8);
else if ((op_get_critter_stat(op_self_obj(), 34) == 0) and (op_global_var(6) == 1) or ((op_get_critter_stat(op_self_obj(), 34) == 1) and (op_global_var(6) == 2)) and (op_global_var(6) != 0) or (op_global_var(449) != 0)) then
begin
if ((op_global_var(297) bwand 131072) != 0) then
op_float_msg(op_self_obj(), op_msg_string(106, 500), 8);
else
op_float_msg(op_self_obj(), op_msg_string(106, 152 + (op_get_critter_stat(op_dude_obj(), 34) == 1)), 8);
end
else
begin
did_node_14 := 0;
op_start_gdialog(106, op_self_obj(), 4, -1, -1);
maybe_start_dialog();
if ((op_party_member_obj(16777380) != 0) or (op_local_var(9) != 0)) then
call Node100();
else
call Node000();
maybe_close_dialog();
maybe_op_end_gdialog();
end
op_set_local_var(5, op_local_var(5) + 1);
end
end
else
begin
if (op_party_member_obj(op_obj_pid(op_self_obj())) != 0) then
begin
op_debug_msg("abandon party: " + op_obj_name(op_self_obj()));
op_party_remove(op_self_obj());
end
if (op_obj_pid(op_self_obj()) == 16777380) then
begin
op_debug_msg("start: set_dude_was_married");
if (op_global_var(6) == 1) then
begin
op_debug_msg("   GVAR_PLAYER_WAS_MARRIED before == " + op_global_var(449));
op_set_global_var(449, op_global_var(6));
op_debug_msg("   GVAR_PLAYER_WAS_MARRIED after == " + op_global_var(449));
op_set_global_var(6, 0);
end
op_debug_msg("finished: set_dude_was_married");
end
if ((op_local_var(8) != -1) and (op_has_trait(1, op_self_obj(), 6) == 0)) then
begin
op_set_local_var(8, -1);
end
op_debug_msg("" + op_obj_name(op_self_obj()) + " has abandoned the party");
call Node998();
if (op_critter_is_fleeing(op_self_obj())) then
begin
if (op_anim_busy(op_self_obj()) == 0) then
begin
if ((op_tile_distance_objs(op_self_obj(), op_dude_obj()) < 8) or op_obj_can_see_obj(op_self_obj(), op_dude_obj())) then
begin
if (op_anim_busy(op_self_obj()) == 0) then
begin
global_temp := op_rotation_to_tile(op_tile_num(op_dude_obj()), op_tile_num(op_self_obj()));
op_animate_move_obj_to_tile(op_self_obj(), op_tile_num_in_direction(op_tile_num(op_self_obj()), global_temp, op_random(3, 10)), 1);
global_temp := (global_temp + 1) % 6;
while ((op_anim_busy(op_self_obj()) == 0) and (global_temp != op_rotation_to_tile(op_tile_num(op_dude_obj()), op_tile_num(op_self_obj())))) do
begin
op_debug_msg("flee loop: rot == " + global_temp);
op_animate_move_obj_to_tile(op_self_obj(), op_tile_num_in_direction(op_tile_num(op_self_obj()), global_temp, op_random(3, 10)), 1);
global_temp := (global_temp + 1) % 6;
end
end
end
end
end
else
op_attack(op_dude_obj(), 0, 1, 0, 0, 30000, 0, 0);
end
if (op_critter_inven_obj(op_self_obj(), 0) != LVar1) then
begin
if (op_critter_inven_obj(op_self_obj(), 0) == 0) then
begin
op_metarule3(107, op_self_obj(), 16777252, 0);
op_float_msg(op_self_obj(), op_msg_string(106, op_random(6000, 6001)), 8);
end
else if ((op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 1) or (op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 379)) then
begin
op_metarule3(107, op_self_obj(), 16777221, 0);
op_float_msg(op_self_obj(), op_msg_string(106, op_random(6005, 6006)), 8);
end
else if ((op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 232) or (op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 3)) then
begin
op_metarule3(107, op_self_obj(), 16777217, 0);
op_float_msg(op_self_obj(), op_msg_string(106, op_random(6025, 6026)), 8);
end
else if ((op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 349) or (op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 348)) then
begin
op_metarule3(107, op_self_obj(), 16777287, 0);
op_float_msg(op_self_obj(), op_msg_string(106, op_random(6030, 6031)), 8);
end
else if ((op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 240) or (op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 380) or (op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 2)) then
begin
op_metarule3(107, op_self_obj(), 16777223, 0);
op_float_msg(op_self_obj(), op_msg_string(106, op_random(6015, 6016)), 8);
end
else if ((op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 74) or (op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 265)) then
begin
op_metarule3(107, op_self_obj(), 16777222, 0);
op_float_msg(op_self_obj(), op_msg_string(106, op_random(6010, 6011)), 8);
end
else if ((op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 239) or (op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 17) or (op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 381)) then
begin
op_metarule3(107, op_self_obj(), 16777219, 0);
op_float_msg(op_self_obj(), op_msg_string(106, op_random(6020, 6021)), 8);
end
else if ((op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 524) or (op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 113)) then
begin
op_metarule3(107, op_self_obj(), 16777218, 0);
op_float_msg(op_self_obj(), op_msg_string(106, op_random(6035, 6036)), 8);
end
else if (op_obj_pid(op_critter_inven_obj(op_self_obj(), 0)) == 554) then
begin
op_metarule3(107, op_self_obj(), 16777320, 0);
op_float_msg(op_self_obj(), op_msg_string(106, op_random(6040, 6041)), 8);
end
restock_obj := op_critter_inven_obj(op_self_obj(), 1);
op_debug_msg("armour pid == " + op_obj_pid(restock_obj));
op_rm_obj_from_inven(op_self_obj(), restock_obj);
end
if (op_local_var(19) != 0) then
begin
call Node2502();
op_set_local_var(19, 0);
end
end

The next procedure governs what happens if the player-character kills Miria (perish the thought!) and takes care of things like updating the player's kill count, karma reputation, town reputations, and so forth.

procedure destroy_p_proc
begin
op_debug_msg("start: set_dude_was_married");
if ((op_global_var(6) != 0) and ((op_global_var(449) != 0) == 0)) then
begin
op_debug_msg("   GVAR_PLAYER_WAS_MARRIED before == " + op_global_var(449));
op_set_global_var(449, op_global_var(6));
op_debug_msg("   GVAR_PLAYER_WAS_MARRIED after == " + op_global_var(449));
op_set_global_var(6, 0);
end
op_debug_msg("finished: set_dude_was_married");
if (op_source_obj() == op_dude_obj()) then
begin
op_set_global_var(5, op_global_var(5) + 1);
if (((op_global_var(4) + op_global_var(5)) >= 25) and ((op_global_var(4) > (3 * op_global_var(5))) or (op_global_var(2) == 1)) and (op_global_var(1) == 0)) then
begin
op_set_global_var(2, 1);
op_set_global_var(3, 0);
end
if (op_metarule(51, op_self_obj()) == 2) then
begin
if (op_source_obj() == op_dude_obj()) then
begin
op_set_global_var(2, 0);
op_set_global_var(1, op_global_var(1) + 1);
op_set_global_var(0, op_global_var(0) + -15);
op_debug_msg("Player gains " + -15 + " Karma Points.");
op_set_global_var(37, 0);
op_set_global_var(38, 0);
op_set_global_var(39, 0);
op_set_global_var(40, 0);
op_set_global_var(41, 0);
op_set_global_var(42, 0);
op_set_global_var(43, 0);
op_set_global_var(44, 0);
op_set_global_var(45, 0);
if (op_global_var(0) >= 1000) then
op_set_global_var(37, 1);
else if (op_global_var(0) >= 750) then
op_set_global_var(38, 1);
else if (op_global_var(0) >= 500) then
op_set_global_var(39, 1);
else if (op_global_var(0) >= 250) then
op_set_global_var(40, 1);
else if (op_global_var(0) > -250) then
op_set_global_var(41, 1);
else if (op_global_var(0) > -500) then
op_set_global_var(42, 1);
else if (op_global_var(0) > -750) then
op_set_global_var(43, 1);
else if (op_global_var(0) > -1000) then
op_set_global_var(44, 1);
else
op_set_global_var(45, 1);
op_set_global_var(52, op_global_var(52) + -8);
op_debug_msg("Added " + -8 + " to Town Rep");
end
end
if (((op_global_var(4) + op_global_var(5)) >= 25) and ((op_global_var(5) > (2 * op_global_var(4))) or (op_global_var(3) == 1))) then
begin
op_set_global_var(3, 1);
op_set_global_var(2, 0);
end
op_set_global_var(0, op_global_var(0) + -10);
op_debug_msg("Player gains " + -10 + " Karma Points.");
op_set_global_var(37, 0);
op_set_global_var(38, 0);
op_set_global_var(39, 0);
op_set_global_var(40, 0);
op_set_global_var(41, 0);
op_set_global_var(42, 0);
op_set_global_var(43, 0);
op_set_global_var(44, 0);
op_set_global_var(45, 0);
if (op_global_var(0) >= 1000) then
op_set_global_var(37, 1);
else if (op_global_var(0) >= 750) then
op_set_global_var(38, 1);
else if (op_global_var(0) >= 500) then
op_set_global_var(39, 1);
else if (op_global_var(0) >= 250) then
op_set_global_var(40, 1);
else if (op_global_var(0) > -250) then
op_set_global_var(41, 1);
else if (op_global_var(0) > -500) then
op_set_global_var(42, 1);
else if (op_global_var(0) > -750) then
op_set_global_var(43, 1);
else if (op_global_var(0) > -1000) then
op_set_global_var(44, 1);
else
op_set_global_var(45, 1);
op_set_global_var(52, op_global_var(52) + -5);
op_debug_msg("Added " + -5 + " to Town Rep");
end
end

The next procedure determines the text displayed in the game's message box when the player looks at Miria using the cursor on a game map.

procedure look_at_p_proc
begin
op_script_overrides();
if (op_local_var(5) > 0) then
begin
if ((op_global_var(6) != 1) and (op_global_var(449) != 1)) then
op_display_msg(op_msg_string(106, 101));
else if (op_global_var(6) == 1) then
op_display_msg(op_msg_string(106, 103));
else if ((op_global_var(6) != 1) and (op_global_var(449) == 1)) then
op_display_msg(op_msg_string(106, 104));
end
else
op_display_msg(op_msg_string(106, 100));
end

The next procedure determines the text displayed in the game's message box when the player "closely examines" Miria using the cursor on a game map.

procedure description_p_proc
begin
op_script_overrides();
if ((op_global_var(6) != 1) and (op_global_var(449) == 1)) then
begin
op_display_msg(op_msg_string(106, op_random(9100, 9101)));
end
else if (op_global_var(6) == 1) then
begin
op_display_msg(op_msg_string(106, op_random(105, 109)));
if ((op_random(1, 100) >= 25) and (op_global_var(6) == 1)) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5200, 5206)), 8);
end
else
begin
op_display_msg(op_msg_string(106, 102));
end
end

The next procedure determines what happens if the player-character uses a skilldex skill (science, lockpick, etc) on the object controlled by the script. In Miria's case this procedure is empty since it wouldn't make any sense to use (for example) "repair" on her, and using the doctor or first aid skill is handled by the game engine rather than the script (although if we wanted using the first aid skill on Miria to do something different than normal, we could certainly add something here using a "script overrides" command).

procedure use_skill_on_p_proc
begin
end

The next procedure determines what happens if the player-character causes damage (namely, by attacking) the npc. I originally wanted to have an option where an evil pc could be an "abusive spouse" to Miria, but the game engine prevents party members from turning hostile against the pc (otherwise, if you accidently hit them in combat they'd turn on you). In any case, as it is now this procedure only governs results of attacking Miria if we haven't yet married her; among other things this causes the player-character's town reputation in Modoc to plummet.

procedure damage_p_proc
begin
if (op_source_obj() == op_dude_obj()) then
begin
if (((op_global_var(291) - (op_global_var(291) % 100)) == 100) or (((op_global_var(291) - (op_global_var(291) % 100)) == 200) or ((op_global_var(291) - (op_global_var(291) % 100)) == 300))) then
op_set_global_var(291, 0);
if (op_party_member_obj(op_obj_pid(op_self_obj())) != 0) then
begin
op_debug_msg("abandon party: " + op_obj_name(op_self_obj()));
op_party_remove(op_self_obj());
end
if (op_obj_pid(op_self_obj()) == 16777380) then
begin
op_debug_msg("start: set_dude_was_married");
if ((op_global_var(6) != 0) and ((op_global_var(449) != 0) == 0)) then
begin
op_debug_msg("   GVAR_PLAYER_WAS_MARRIED before == " + op_global_var(449));
op_set_global_var(449, op_global_var(6));
op_debug_msg("   GVAR_PLAYER_WAS_MARRIED after == " + op_global_var(449));
op_set_global_var(6, 0);
end
op_debug_msg("finished: set_dude_was_married");
end
if ((op_local_var(8) != -1) and (op_has_trait(1, op_self_obj(), 6) == 0)) then
begin
op_set_local_var(8, -1);
end
op_debug_msg("" + op_obj_name(op_self_obj()) + " has abandoned the party");
call Node998();
if ((op_cur_map_index() == 18) or (op_cur_map_index() == 19)) then
begin
if ((op_global_var(52) <= -1000) == 0) then
op_set_global_var(52, -1000);
end
end
end

The next procedure is run each time the npc moves to a different game map. In Miria's case, we set a timer here so she'll make her commentary on a specific town or area if she has one. Other things taken care of in this procedure are setting the npc's team and AI packet, moving them to a different elevation if the map they're on has changed since the last time the player visited, and so forth. If we wanted an npc to move around using a pre-determined patrol route, this would be a good place to start that process.

procedure map_enter_p_proc
begin
if ((op_cur_map_index() == 19) or (op_cur_map_index() == 37) or (op_cur_map_index() == 38)) then
begin
if ((op_elevation(op_self_obj()) != op_elevation(op_dude_obj())) and (op_local_var(9) != 0)) then
op_move_to(op_self_obj(), op_tile_num(op_self_obj()), op_elevation(op_dude_obj()));
end
if (op_global_var(6) == 1) then
begin
if (op_party_member_obj(16777380) != 0) then
begin
Perform_Critter_Float := 1;
op_rm_timer_event(op_self_obj());
end
else
Perform_Critter_Float := 0;
end
if ((op_party_member_obj(16777380) != 0) == 0) then
begin
if (op_cur_map_index() == 18) then
begin
if (op_metarule(14, 0)) then
op_set_local_var(13, op_tile_num(op_self_obj()));
op_critter_attempt_placement(op_self_obj(), op_local_var(13), op_elevation(op_dude_obj()));
end
end
end

The next procedure runs every few minutes when Miria is running around a town or random encounter map with the player. It contains things that need to be updated frequently, but not continuously (those sorts of things are instead in critter_p_proc above). Most of the lines in this section control whether Miria thinks she should try to heal herself, assuming she has the supplies (first aid kit, stimpacks, etc) to do so.

procedure map_update_p_proc
begin
if ((op_global_var(6) == 1) and (op_global_var(449) != 1)) then
begin
if (op_local_var(18) < op_game_time()) then
begin
if (op_game_time() < op_global_var(791)) then
op_set_local_var(17, (op_local_var(17) + 1));
if (op_game_time() < op_global_var(792)) then
op_set_local_var(17, (op_local_var(17) + 1));
if (op_game_time() < op_global_var(793)) then
op_set_local_var(17, (op_local_var(17) + 1));
if (op_game_time() < op_global_var(794)) then
op_set_local_var(17, (op_local_var(17) + 1));
if ((op_game_time() < op_global_var(791)) and (op_game_time() < op_global_var(792)) and (op_game_time() < op_global_var(793)) and (op_game_time() < op_global_var(794))) then
op_set_local_var(17, (op_local_var(17) + 1));
if ((op_game_time() > op_global_var(791)) and (op_game_time() > op_global_var(792)) and (op_game_time() > op_global_var(793)) and (op_game_time() > op_global_var(794))) then
op_set_local_var(17, (op_local_var(17) - 1));
if ((op_global_var(22) > 0) or (op_global_var(23) > 0) or (op_global_var(24) > 0) or (op_global_var(25) > 0) or (op_global_var(296) != 0) or (op_global_var(26) > 0) or (op_global_var(295) > 0)) then
op_set_local_var(17, (op_local_var(17) - 1));
if (op_global_var(230) > 0) then
op_set_local_var(17, (op_local_var(17) - 1));
if (op_global_var(11) > 0) then
op_set_local_var(17, (op_local_var(17) - 1));
if (op_global_var(0) < -500) then
op_set_local_var(17, (op_local_var(17) - 1));
if (op_local_var(17) < 0) then
op_set_local_var(17, 0);
if (op_local_var(17) > 30) then
op_set_local_var(17, 30);
op_set_local_var(18, (op_game_time() + (2 * (30 * (24 * (60 * (60 * 10)))))));
op_debug_msg("updated Miria planning timer");
end
end
if (maybe_in_battle() == 0) then
begin
if (op_anim_busy(op_self_obj()) == 0) then
begin
if (op_party_member_obj(op_obj_pid(op_self_obj())) != 0) then
begin
if (op_metarule3(109, op_self_obj(), 0, 0) == 1) then
begin
if ((100 * op_get_critter_stat(op_self_obj(), 35) / op_get_critter_stat(op_self_obj(), 7)) <= 60) then
begin
global_temp := 1;
if (op_obj_is_carrying_obj(op_self_obj(), 144)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
PartyHealingItem := op_obj_carrying_pid_obj(op_self_obj(), 144);
op_use_obj_on_obj(PartyHealingItem, op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used super stimpak.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 40)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 40), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used stimpak.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 273)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 273), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used healing powder.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 91)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 91), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used doctor's bag kit.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 47)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 47), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used First Aid kit.");
end
end
end
else if (op_metarule3(109, op_self_obj(), 0, 0) == 2) then
begin
if ((100 * op_get_critter_stat(op_self_obj(), 35) / op_get_critter_stat(op_self_obj(), 7)) <= 30) then
begin
global_temp := 1;
if (op_obj_is_carrying_obj(op_self_obj(), 144)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
PartyHealingItem := op_obj_carrying_pid_obj(op_self_obj(), 144);
op_use_obj_on_obj(PartyHealingItem, op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used super stimpak.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 40)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 40), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used stimpak.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 273)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 273), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used healing powder.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 91)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 91), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used doctor's bag kit.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 47)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 47), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used First Aid kit.");
end
end
end
else if (op_metarule3(109, op_self_obj(), 0, 0) == 3) then
begin
if ((100 * op_get_critter_stat(op_self_obj(), 35) / op_get_critter_stat(op_self_obj(), 7)) <= 50) then
begin
global_temp := 1;
if (op_obj_is_carrying_obj(op_self_obj(), 144)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
PartyHealingItem := op_obj_carrying_pid_obj(op_self_obj(), 144);
op_use_obj_on_obj(PartyHealingItem, op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used super stimpak.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 40)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 40), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used stimpak.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 273)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 273), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used healing powder.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 91)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 91), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used doctor's bag kit.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 47)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 47), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used First Aid kit.");
end
end
end
else if (op_metarule3(109, op_self_obj(), 0, 0) == 4) then
begin
if ((100 * op_get_critter_stat(op_self_obj(), 35) / op_get_critter_stat(op_self_obj(), 7)) <= 50) then
begin
global_temp := 1;
if (op_obj_is_carrying_obj(op_self_obj(), 144)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
PartyHealingItem := op_obj_carrying_pid_obj(op_self_obj(), 144);
op_use_obj_on_obj(PartyHealingItem, op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used super stimpak.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 40)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 40), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used stimpak.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 273)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 273), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used healing powder.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 91)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then

end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 91), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used doctor's bag kit.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 47)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 47), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used First Aid kit.");
end
end
end
end
end
end
end

In the next procedure, we control what happens when all the various timers set elsewhere in the script are due to fire. In Miria's case, things like her float text if she's injured (which is governed by a timer) are carried out. In all the traditional Miria mods, Miria was assigned some custom text if she was poisoned or irradiated. Unfortunately the game engine prevents pcs from being poisoned or irradiated, so that part of the traditional mod never worked and I had originally removed it. In the RP 2.0 killap has stated he found a way to allow npcs to be poisoned or irradiated--so I added the section back in. I haven't seen it work yet myself, but if killap says it's fixed then it probably is.

procedure timed_event_p_proc
begin
if (op_fixed_param() == 1) then
begin
if (not maybe_in_battle() and op_has_trait(1, op_self_obj(), 666)) then
begin
if (op_party_member_obj(16777380) != 0) then
begin
if (op_critter_state(op_party_member_obj(16777380)) bwand (4 bwor 8 bwor 16 bwor 32)) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5004, 5005)), 8);
else if (op_get_critter_stat(op_self_obj(), 37)) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5000, 5001)), 8);
else if (op_get_poison(op_self_obj())) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5002, 5003)), 8);
else if (op_get_critter_stat(op_self_obj(), 35) <= (op_get_critter_stat(op_self_obj(), 7) * 3 / 4)) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5006, 5007)), 8);
else
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 1) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5500, 5521)), 8);
else
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5507, 5528)), 8);
end
end
end
op_rm_timer_event(op_self_obj());
end
else if (op_fixed_param() == 666) then
begin
op_float_msg(op_self_obj(), " ", 8);
op_float_msg(op_dude_obj(), " ", 8);
op_float_msg(op_self_obj(), 0, 0);
op_float_msg(op_dude_obj(), 0, 0);
end
end

The next section governs what happens if the player starts a fight with Miria or attacks her (which isn't necessarily the same thing as causing damage, which was governed in a previous procedure). Since the engine prevents npcs from turning hostile if they are in the player-character's party, in Miria's case this only governs what happens if she's not currently married to the pc.

procedure combat_p_proc
begin
if (op_global_var(52) <= -1000) then
begin
if (op_party_member_obj(op_obj_pid(op_self_obj())) != 0) then
begin
op_debug_msg("abandon party: " + op_obj_name(op_self_obj()));
op_party_remove(op_self_obj());
end
if (op_obj_pid(op_self_obj()) == 16777380) then
begin
op_debug_msg("start: set_dude_was_married");
if (op_global_var(6) == 1) then
begin
op_set_global_var(449, op_global_var(6));
op_set_global_var(6, 0);
end
op_debug_msg("finished: set_dude_was_married");
end
if ((op_local_var(8) != -1) and (op_has_trait(1, op_self_obj(), 6) == 0)) then
begin
op_set_local_var(8, -1);
end
op_debug_msg("" + op_obj_name(op_self_obj()) + " has abandoned the party");
end
if ((op_party_member_obj(16777380) != 0) == 0) then
begin
if (op_has_trait(1, op_self_obj(), 6) != 28) then
if (op_fixed_param() == 4) then
begin
if (((op_item_subtype(op_critter_inven_obj(op_self_obj(), 1)) == 3) or (op_item_subtype(op_critter_inven_obj(op_self_obj(), 2)) == 3)) == 0) then
begin
if (op_obj_is_carrying_obj(op_self_obj(), 4) > 0) then
op_wield_obj_critter(op_self_obj(), op_obj_carrying_pid_obj(op_self_obj(), 4));
end
end
end
end

The next procedure governs what happens if the player tries to push an npc out of the way (if the npc is blocking a door, for example). If this procedure is empty, then the npc won't move when pushed and the player will have to wait for them to move out of the way on their own.

procedure push_p_proc
begin
if (op_party_member_obj(16777380) != 0) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5100, 5103)), 8);
else
op_script_overrides();
end

The next section of the script, the numbered procedures, are mainly used to organize conversation trees and dialogues with the npc. The very first lines of conversation the player ever has with Miria, for example, are contained in the first node below, Node000. I also use Node000 to initialize the value of one of my new local variables, setting it to 10 the first time the player talks to Miria. This is the local variable that stores the "score" determining whether or not Miria is happy overall with her marriage to the player-character. If you didn't already know, the format for displaying most of the dialogue lines on the screen during the game is:

op_giq_option(minimum intelligence needed to get this line as an option, script number of the npc, line of dialogue to display from the npc's .msg text file, where to go in the script if this line is said, and the reaction modifier if the pc uses this line).

procedure Node000
begin
if (op_local_var(17) != 10) then
begin
op_set_local_var(17, 10);
end
op_gsay_reply(106, 154 + (op_local_var(5) > 0));
op_set_local_var(5, op_local_var(5) + 1);
op_giq_option(4, 106, 156, @Node018, 50);
op_giq_option(4, 106, 157, @Node013, 50);
op_giq_option(4, 106, 158, @Node014, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
op_giq_option(-3, 106, 159, @Node026, 50);
end

procedure Node002
begin
op_giq_option(4, 106, 156, @Node018, 50);
op_giq_option(4, 106, 158, @Node014, 50);
op_giq_option(4, 106, 157, @Node013, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node010
begin
did_node_11 := 0;
did_node_12 := 0;
op_giq_option(4, 106, 165, @Node011, 50);
op_giq_option(4, 106, 166, @Node012, 50);
op_giq_option(4, 106, 167, @Node014, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node011
begin
did_node_11 := 1;
op_set_global_var(117, 1);
if (did_node_12 == 0) then
op_giq_option(4, 106, 166, @Node012, 50);
op_giq_option(4, 106, 184, @Node014, 50);
op_giq_option(4, 106, 170, @Node002, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node012
begin
did_node_12 := 1;
if (did_node_11 == 0) then
op_giq_option(4, 106, 165, @Node011, 50);
op_giq_option(4, 106, 184, @Node014, 50);
op_giq_option(4, 106, 170, @Node002, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node013
begin
op_giq_option(4, 106, 170, @Node002, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node014
begin
did_node_14 := 1;
if ((op_global_var(105) >= 4) and (op_global_var(105) < 7) or ((op_global_var(106) >= 4) and (op_global_var(106) < 7))) then
op_giq_option(4, 106, 178, @Node010, 50);
op_giq_option(4, 106, 179, @Node015, 50);
op_giq_option(4, 106, 180, @Node016, 50);
op_giq_option(4, 106, 181, @Node017, 50);
op_giq_option(4, 106, 182, @Node002, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node015
begin
op_giq_option(4, 106, 184, @Node014, 50);
op_giq_option(4, 106, 182, @Node002, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node016
begin
op_giq_option(4, 106, 184, @Node014, 50);
op_giq_option(4, 106, 182, @Node002, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node017
begin
op_giq_option(4, 106, 184, @Node014, 50);
op_giq_option(4, 106, 182, @Node002, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node018
begin
if ((op_get_critter_stat(op_dude_obj(), 3) + op_success(op_do_check(op_dude_obj(), 3, 0)) + (op_global_var(52) > 0)) >= 9) then
op_giq_option(4, 106, 193, @Node019, 50);
op_giq_option(4, 106, 194, @Node020, 50);
op_giq_option(4, 106, 170, @Node002, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node019
begin
op_giq_option(4, 106, 197, @Node021, 50);
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
op_giq_option(4, 106, op_msg_string(106, 198) + op_obj_name(op_dude_obj()) + op_msg_string(106, 199), @Node022, 50);
op_giq_option(4, 106, 200, @Node024, 50);
op_giq_option(4, 106, 170, @Node002, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node020
begin
op_giq_option(4, 106, 203, @Node996, 50);
op_giq_option(4, 106, 204, @Node999, 50);
end

procedure Node021
begin
op_set_local_var(6, 2);
op_giq_option(4, 106, op_msg_string(14, 350), @Node999, 50);
end

procedure Node022
begin
op_giq_option(4, 106, 170, @Node023, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node023
begin
op_giq_option(4, 106, op_msg_string(14, 350), @Node999, 50);
end

procedure Node024
begin
op_giq_option(4, 106, 210, @Node025, 50);
op_giq_option(4, 106, 211, @Node022, 50);
op_giq_option(4, 106, 212, @Node020, 50);
op_giq_option(4, 106, 213, @Node021, 50);
op_giq_option(4, 106, op_msg_string(14, op_random(375, 376)), @Node999, 50);
end

procedure Node025
begin
op_giq_option(4, 106, 215, @Node995, 50);
end

procedure Node026
begin
op_giq_option(-3, 106, 217, @Node027, 50);
op_giq_option(-3, 106, 218, @Node999, 50);
end

procedure Node027
begin
op_giq_option(-3, 106, op_msg_string(14, 350), @Node999, 50);
end

While the above nodes mostly govern conversations with Miria if we haven't yet married her, the next nodes mostly control conversations with Miria after she's in the party and govern routine things like changing her follow distance, asking her about her weapons and armor, etc. Node100 below is the "party node," or the very first lines of dialogue we'll initially see each time we talk to Miria after we've married her. If we want to have a line of conversation always available with an npc while they're in our party, we would probably want to put the initial "hook" in Node100.

procedure Node100
begin
if ((op_local_var(9) != 0) == 0) then
begin
if (op_local_var(10) == 0) then
op_set_local_var(10, 3);
op_giq_option(4, 106, 10000, @Node2000, 50);
if (op_msg_string(14, 10001) != 0) then
begin
if (op_get_critter_stat(op_self_obj(), 35) < op_get_critter_stat(op_self_obj(), 7)) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9211, @Node1001, 50);
end
else
begin
op_giq_option(4, 106, 9210, @Node1001, 50);
end
end
end
if (op_msg_string(106, 1020) != 0) then
op_giq_option(4, 106, 1020, @Node1007, 50);
if (op_msg_string(14, 10009) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9221, @Node1008, 50);
end
else
begin
op_giq_option(4, 106, 9220, @Node1008, 50);
end
end
if (op_msg_string(14, 10002) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9231, @Node1002, 50);
end
else
begin
op_giq_option(4, 106, 9230, @Node1002, 50);
end
end
end
else if (op_msg_string(14, 10100) != 0) then
op_giq_option(4, 106, op_random(9200, 9201), @Node1100, 50);
if (op_msg_string(14, 10007) != 0) then
begin
if (op_global_var(0) > -500) then
begin
op_giq_option(4, 106, op_random(9240, 9241), @Node999, 50);
end
else
begin
op_giq_option(4, 106, op_random(9241, 9242), @Node999, 50);
end
end
if (op_msg_string(14, op_random(300, 303)) != 0) then
op_giq_option(-3, 106, op_msg_string(14, op_random(300, 303)), @Node999, 50);
op_debug_msg("USED PARTY MEMBER OPTIONS");
end

If we ask Miria to heal herself, it's taken care of in Node1001. If we were to add new medicines to the game, we'd want to modify this node in order for Miria to make use of them on her own.

procedure Node1001
begin
if (op_obj_is_carrying_obj(op_self_obj(), 144)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
PartyHealingItem := op_obj_carrying_pid_obj(op_self_obj(), 144);
op_use_obj_on_obj(PartyHealingItem, op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used super stimpak.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 40)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 40), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used stimpak.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 273)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 273), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used healing powder.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 91)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 91), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used doctor's bag kit.");
end
else if (op_obj_is_carrying_obj(op_self_obj(), 47)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if (0 > 0) then
end
op_use_obj_on_obj(op_obj_carrying_pid_obj(op_self_obj(), 47), op_self_obj());
op_debug_msg(op_obj_name(op_self_obj()) + " used First Aid kit.");
end
else if (op_has_skill(op_self_obj(), 7) > op_has_skill(op_self_obj(), 6)) then
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if ((60 * (60 * 10)) > 0) then
end
if (op_success(op_roll_vs_skill(op_self_obj(), 7, 0))) then
begin
op_critter_heal(op_self_obj(), op_random(10, 25));
op_debug_msg(op_obj_name(op_self_obj()) + " healed some using doctor skill.");
end
end
else
begin
if ((global_temp == 0) and (maybe_in_battle() == 0)) then
begin
if ((15 * (60 * 10)) > 0) then
end
if (op_success(op_roll_vs_skill(op_self_obj(), 6, 0))) then
begin
op_critter_heal(op_self_obj(), op_random(5, 15));
op_debug_msg(op_obj_name(op_self_obj()) + " healed some using first aid skill.");
end
end
global_temp := 0;
if (op_get_critter_stat(op_self_obj(), 35) == op_get_critter_stat(op_self_obj(), 7)) then
else if ((op_get_critter_stat(op_self_obj(), 35) * 100 / op_get_critter_stat(op_self_obj(), 7)) >= 90) then
else if ((op_get_critter_stat(op_self_obj(), 35) * 100 / op_get_critter_stat(op_self_obj(), 7)) >= 70) then
else
if ((op_local_var(9) != 0) == 0) then
begin
if (op_local_var(10) == 0) then
op_set_local_var(10, 3);
op_giq_option(4, 106, 10000, @Node2000, 50);
if (op_msg_string(14, 10001) != 0) then
begin
if (op_get_critter_stat(op_self_obj(), 35) < op_get_critter_stat(op_self_obj(), 7)) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9211, @Node1001, 50);
end
else
begin
op_giq_option(4, 106, 9210, @Node1001, 50);
end
end
end
if (op_msg_string(106, 1020) != 0) then
op_giq_option(4, 106, 1020, @Node1007, 50);
if (op_msg_string(14, 10009) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9221, @Node1008, 50);
end
else
begin
op_giq_option(4, 106, 9220, @Node1008, 50);
end
end
if (op_msg_string(14, 10002) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9231, @Node1002, 50);
end
else
begin
op_giq_option(4, 106, 9230, @Node1002, 50);
end
end
end
else if (op_msg_string(14, 10100) != 0) then
op_giq_option(4, 106, op_random(9200, 9201), @Node1100, 50);
if (op_msg_string(14, 10007) != 0) then
begin
if (op_global_var(0) > -500) then
begin
op_giq_option(4, 106, op_random(9240, 9241), @Node999, 50);
end
else
begin
op_giq_option(4, 106, op_random(9241, 9242), @Node999, 50);
end
end
if (op_msg_string(14, op_random(300, 303)) != 0) then
op_giq_option(-3, 106, op_msg_string(14, op_random(300, 303)), @Node999, 50);
op_debug_msg("USED PARTY MEMBER OPTIONS");
end

Node1002 deals with what happens when we ask Miria to wait somewhere, resulting in her removal from the player-character's party of teammates.

procedure Node1002
begin
op_set_local_var(9, op_game_time());
op_party_remove(op_self_obj());
op_rm_timer_event(op_self_obj());
if ((op_local_var(9) != 0) == 0) then
begin
if (op_local_var(10) == 0) then
op_set_local_var(10, 3);
if (op_msg_string(14, 10001) != 0) then
begin
if (op_get_critter_stat(op_self_obj(), 35) < op_get_critter_stat(op_self_obj(), 7)) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9211, @Node1001, 50);
end
else
begin
op_giq_option(4, 106, 9210, @Node1001, 50);
end
end
end
if (op_msg_string(106, 1020) != 0) then
op_giq_option(4, 106, 1020, @Node1007, 50);
if (op_msg_string(14, 10009) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9221, @Node1008, 50);
end
else
begin
op_giq_option(4, 106, 9220, @Node1008, 50);
end
end
if (op_msg_string(14, 10002) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9231, @Node1002, 50);
end
else
begin
op_giq_option(4, 106, 9230, @Node1002, 50);
end
end
end
else if (op_msg_string(14, 10100) != 0) then
op_giq_option(4, 106, op_random(9200, 9201), @Node1100, 50);
if (op_msg_string(14, 10007) != 0) then
begin
if (op_global_var(0) > -500) then
begin
op_giq_option(4, 106, op_random(9240, 9241), @Node999, 50);
end
else
begin
op_giq_option(4, 106, op_random(9241, 9242), @Node999, 50);
end
end
if (op_msg_string(14, op_random(300, 303)) != 0) then
op_giq_option(-3, 106, op_msg_string(14, op_random(300, 303)), @Node999, 50);
op_debug_msg("USED PARTY MEMBER OPTIONS");
end

Node1003 deals with asking Miria to put away whatever weapon she is currently using.

procedure Node1003
begin
op_metarule(43, op_self_obj());
if ((op_local_var(9) != 0) == 0) then
begin
if (op_local_var(10) == 0) then
op_set_local_var(10, 3);
op_giq_option(4, 106, 10000, @Node2000, 50);
if (op_msg_string(14, 10001) != 0) then
begin
if (op_get_critter_stat(op_self_obj(), 35) < op_get_critter_stat(op_self_obj(), 7)) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9211, @Node1001, 50);
end
else
begin
op_giq_option(4, 106, 9210, @Node1001, 50);
end
end
end
if (op_msg_string(106, 1020) != 0) then
op_giq_option(4, 106, 1020, @Node1007, 50);
if (op_msg_string(14, 10009) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9221, @Node1008, 50);
end
else
begin
op_giq_option(4, 106, 9220, @Node1008, 50);
end
end
if (op_msg_string(14, 10002) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9231, @Node1002, 50);
end
else
begin
op_giq_option(4, 106, 9230, @Node1002, 50);
end
end
end
else if (op_msg_string(14, 10100) != 0) then
op_giq_option(4, 106, op_random(9200, 9201), @Node1100, 50);
if (op_msg_string(14, 10007) != 0) then
begin
if (op_global_var(0) > -500) then
begin
op_giq_option(4, 106, op_random(9240, 9241), @Node999, 50);
end
else
begin
op_giq_option(4, 106, op_random(9241, 9242), @Node999, 50);
end
end
if (op_msg_string(14, op_random(300, 303)) != 0) then
op_giq_option(-3, 106, op_msg_string(14, op_random(300, 303)), @Node999, 50);
op_debug_msg("USED PARTY MEMBER OPTIONS");
end

The next several nodes deal with setting Miria's "follow distance," or how closely she stands next to the player-character on the game map. In the original version of Fallout 2 Miria kept a close distance to the player at all times regardless of what the player asked her to do. I've modified this so that the player can ask Miria to keep her distance, but she'll try from time to time to get close again so she can be with her beloved.

procedure Node1004
begin
op_set_local_var(10, 3);
if ((op_local_var(9) != 0) == 0) then
begin
if (op_local_var(10) == 0) then
op_set_local_var(10, 3);
op_giq_option(4, 106, 10000, @Node2000, 50);
if (op_msg_string(14, 10001) != 0) then
begin
if (op_get_critter_stat(op_self_obj(), 35) < op_get_critter_stat(op_self_obj(), 7)) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9211, @Node1001, 50);
end
else
begin
op_giq_option(4, 106, 9210, @Node1001, 50);
end
end
end
if (op_msg_string(106, 1020) != 0) then
op_giq_option(4, 106, 1020, @Node1007, 50);
if (op_msg_string(14, 10009) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9221, @Node1008, 50);
end
else
begin
op_giq_option(4, 106, 9220, @Node1008, 50);
end
end
if (op_msg_string(14, 10002) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9231, @Node1002, 50);
end
else
begin
op_giq_option(4, 106, 9230, @Node1002, 50);
end
end
end
else if (op_msg_string(14, 10100) != 0) then
op_giq_option(4, 106, op_random(9200, 9201), @Node1100, 50);
if (op_msg_string(14, 10007) != 0) then
begin
if (op_global_var(0) > -500) then
begin
op_giq_option(4, 106, op_random(9240, 9241), @Node999, 50);
end
else
begin
op_giq_option(4, 106, op_random(9241, 9242), @Node999, 50);
end
end
if (op_msg_string(14, op_random(300, 303)) != 0) then
op_giq_option(-3, 106, op_msg_string(14, op_random(300, 303)), @Node999, 50);
op_debug_msg("USED PARTY MEMBER OPTIONS");
end

procedure Node1005
begin
if ((op_local_var(9) != 0) == 0) then
begin
if (op_local_var(10) == 0) then
op_set_local_var(10, 6);
op_giq_option(4, 106, 10000, @Node2000, 50);
if (op_msg_string(14, 10001) != 0) then
begin
if (op_get_critter_stat(op_self_obj(), 35) < op_get_critter_stat(op_self_obj(), 7)) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9211, @Node1001, 50);
end
else
begin
op_giq_option(4, 106, 9210, @Node1001, 50);
end
end
end
if (op_msg_string(106, 1020) != 0) then
op_giq_option(4, 106, 1020, @Node1007, 50);
if (op_msg_string(14, 10009) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9221, @Node1008, 50);
end
else
begin
op_giq_option(4, 106, 9220, @Node1008, 50);
end
end
if (op_msg_string(14, 10002) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9231, @Node1002, 50);
end
else
begin
op_giq_option(4, 106, 9230, @Node1002, 50);
end
end
end
else if (op_msg_string(14, 10100) != 0) then
op_giq_option(4, 106, op_random(9200, 9201), @Node1100, 50);
if (op_msg_string(14, 10007) != 0) then
begin
if (op_global_var(0) > -500) then
begin
op_giq_option(4, 106, op_random(9240, 9241), @Node999, 50);
end
else
begin
op_giq_option(4, 106, op_random(9241, 9242), @Node999, 50);
end
end
if (op_msg_string(14, op_random(300, 303)) != 0) then
op_giq_option(-3, 106, op_msg_string(14, op_random(300, 303)), @Node999, 50);
op_debug_msg("USED PARTY MEMBER OPTIONS");
end

procedure Node1006
begin
if ((op_local_var(9) != 0) == 0) then
begin
if (op_local_var(10) == 0) then
op_set_local_var(10, 9);
op_giq_option(4, 106, 10000, @Node2000, 50);
if (op_msg_string(14, 10001) != 0) then
begin
if (op_get_critter_stat(op_self_obj(), 35) < op_get_critter_stat(op_self_obj(), 7)) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9211, @Node1001, 50);
end
else
begin
op_giq_option(4, 106, 9210, @Node1001, 50);
end
end
end
if (op_msg_string(106, 1020) != 0) then
op_giq_option(4, 106, 1020, @Node1007, 50);
if (op_msg_string(14, 10009) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9221, @Node1008, 50);
end
else
begin
op_giq_option(4, 106, 9220, @Node1008, 50);
end
end
if (op_msg_string(14, 10002) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9231, @Node1002, 50);
end
else
begin
op_giq_option(4, 106, 9230, @Node1002, 50);
end
end
end
else if (op_msg_string(14, 10100) != 0) then
op_giq_option(4, 106, op_random(9200, 9201), @Node1100, 50);
if (op_msg_string(14, 10007) != 0) then
begin
if (op_global_var(0) > -500) then
begin
op_giq_option(4, 106, op_random(9240, 9241), @Node999, 50);
end
else
begin
op_giq_option(4, 106, op_random(9241, 9242), @Node999, 50);
end
end
if (op_msg_string(14, op_random(300, 303)) != 0) then
op_giq_option(-3, 106, op_msg_string(14, op_random(300, 303)), @Node999, 50);
op_debug_msg("USED PARTY MEMBER OPTIONS");
end

procedure Node1007
begin
if (op_msg_string(14, 10004) != 0) then
begin
if (op_local_var(10) != 3) then
op_giq_option(4, 106, op_msg_string(14, 10004), @Node1004, 50);
end
if (op_msg_string(106, 1005) != 0) then
begin
if (op_local_var(10) != 6) then
op_giq_option(4, 106, 1005, @Node1005, 50);
end
if (op_msg_string(106, 1006) != 0) then
begin
if (op_local_var(10) != 9) then
op_giq_option(4, 106, 1006, @Node1006, 50);
end
if (op_msg_string(14, 10010) != 0) then
op_giq_option(4, 106, op_msg_string(14, 10010), @Node100, 50);
end

The next few nodes deal with asking Miria about her equipment, asking her to take off her armor, and so forth.

procedure Node1008
begin
if (op_msg_string(14, 10013) != 0) then
op_giq_option(4, 106, op_msg_string(14, 10013), @Node1010, 50);
if (op_msg_string(14, 10003) != 0) then
begin
if ((op_item_subtype(op_critter_inven_obj(op_self_obj(), 1)) == 3) or (op_item_subtype(op_critter_inven_obj(op_self_obj(), 2)) == 3)) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9251, @Node1003, 50);
end
else
begin
op_giq_option(4, 106, 9250, @Node1003, 50);
end
end
end
if (op_msg_string(14, 10012) != 0) then
begin
if (op_item_subtype(op_critter_inven_obj(op_self_obj(), 0)) == 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9261, @Node1009, 50);
end
else
begin
op_giq_option(4, 106, 9260, @Node1009, 50);
end
end
end
if (op_msg_string(14, 10011) != 0) then
op_giq_option(4, 106, op_msg_string(14, 10011), @Node100, 50);
op_debug_msg("USED PARTY GEAR OPTIONS");
end

procedure Node1009
begin
if (op_item_subtype(op_critter_inven_obj(op_self_obj(), 0)) == 0) then
begin
restock_obj := op_critter_inven_obj(op_self_obj(), 0);
op_debug_msg("armour pid == " + op_obj_pid(restock_obj));
op_rm_obj_from_inven(op_self_obj(), restock_obj);
end
if ((op_local_var(9) != 0) == 0) then
begin
if (op_local_var(10) == 0) then
op_set_local_var(10, 3);
op_giq_option(4, 106, 10000, @Node2000, 50);
if (op_msg_string(14, 10001) != 0) then
begin
if (op_get_critter_stat(op_self_obj(), 35) < op_get_critter_stat(op_self_obj(), 7)) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9211, @Node1001, 50);
end
else
begin
op_giq_option(4, 106, 9210, @Node1001, 50);
end
end
end
if (op_msg_string(106, 1020) != 0) then
op_giq_option(4, 106, 1020, @Node1007, 50);
if (op_msg_string(14, 10009) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9221, @Node1008, 50);
end
else
begin
op_giq_option(4, 106, 9220, @Node1008, 50);
end
end
if (op_msg_string(14, 10002) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9231, @Node1002, 50);
end
else
begin
op_giq_option(4, 106, 9230, @Node1002, 50);
end
end
end
else if (op_msg_string(14, 10100) != 0) then
op_giq_option(4, 106, op_random(9200, 9201), @Node1100, 50);
if (op_msg_string(14, 10007) != 0) then
begin
if (op_global_var(0) > -500) then
begin
op_giq_option(4, 106, op_random(9240, 9241), @Node999, 50);
end
else
begin
op_giq_option(4, 106, op_random(9241, 9242), @Node999, 50);
end
end
if (op_msg_string(14, op_random(300, 303)) != 0) then
op_giq_option(-3, 106, op_msg_string(14, op_random(300, 303)), @Node999, 50);
op_debug_msg("USED PARTY MEMBER OPTIONS");
end

procedure Node1010
begin
if ((op_local_var(9) != 0) == 0) then
begin
if (op_local_var(10) == 0) then
op_set_local_var(10, 3);
op_giq_option(4, 106, 10000, @Node2000, 50);
if (op_msg_string(14, 10001) != 0) then
begin
if (op_get_critter_stat(op_self_obj(), 35) < op_get_critter_stat(op_self_obj(), 7)) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9211, @Node1001, 50);
end
else
begin
op_giq_option(4, 106, 9210, @Node1001, 50);
end
end
end
if (op_msg_string(106, 1020) != 0) then
op_giq_option(4, 106, 1020, @Node1007, 50);
if (op_msg_string(14, 10009) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9221, @Node1008, 50);
end
else
begin
op_giq_option(4, 106, 9220, @Node1008, 50);
end
end
if (op_msg_string(14, 10002) != 0) then
begin
if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 9231, @Node1002, 50);
end
else
begin
op_giq_option(4, 106, 9230, @Node1002, 50);
end
end
end
else if (op_msg_string(14, 10100) != 0) then
op_giq_option(4, 106, op_random(9200, 9201), @Node1100, 50);
if (op_msg_string(14, 10007) != 0) then
begin
if (op_global_var(0) > -500) then
begin
op_giq_option(4, 106, op_random(9240, 9241), @Node999, 50);
end
else
begin
op_giq_option(4, 106, op_random(9241, 9242), @Node999, 50);
end
end
if (op_msg_string(14, op_random(300, 303)) != 0) then
op_giq_option(-3, 106, op_msg_string(14, op_random(300, 303)), @Node999, 50);
op_debug_msg("USED PARTY MEMBER OPTIONS");
end

Node1100 controls what happens when the player-character asks Miria to rejoin the team after she has been left waiting somewhere. In other npc followers there are checks in this node to see if the pc already has too many teammates in the current party, or if the pc has done something (such as becoming a slaver) that the npc doesn't care for, resulting in a refusal to rejoin. In Miria's case, however, she doesn't take such things into consideration due to the bonds of matrimony and will always rejoin the player's team.

procedure Node1100
begin
variable Chowtime := 0;
if ((op_global_var(6) != 1) and (op_global_var(449) == 1)) then
begin
if (op_party_member_obj(op_obj_pid(op_self_obj())) != 0) then
begin
op_debug_msg("abandon party: " + op_obj_name(op_self_obj()));
op_party_remove(op_self_obj());
end
if ((op_local_var(8) != -1) and (op_has_trait(1, op_self_obj(), 6) == 0)) then
begin
op_set_local_var(8, -1);
end
op_debug_msg("" + op_obj_name(op_self_obj()) + " has abandoned the party");
op_giq_option(1, 106, 9130, @Node999, 50);
op_giq_option(1, 106, 9140, @Node999, 50);
end
else
begin
op_set_local_var(9, 0);
if ((op_critter_state(op_self_obj()) bwand 1) == 0) then
begin
if (op_local_var(10) == 0) then
op_set_local_var(10, 3);
if (op_has_trait(1, op_self_obj(), 6) != 0) then
op_set_local_var(8, op_has_trait(1, op_self_obj(), 6));
op_rm_timer_event(op_self_obj());
end
op_debug_msg("join party: " + op_obj_name(op_self_obj()));
if (Chowtime == 0) then
begin
if ((op_game_time_hour() >= 400) and (op_game_time_hour() <= 900)) then
Chowtime := 9161;
else if ((op_game_time_hour() > 900) and (op_game_time_hour() <= 1300)) then
Chowtime := 9162;
else if ((op_game_time_hour() > 1300) and (op_game_time_hour() <= 2200)) then
Chowtime := 9163;
else if ((op_game_time_hour() > 2200) and (op_game_time_hour() < 400)) then
Chowtime := 9164;
end
if ((op_global_var(1) >= 5) or (op_global_var(0) < -500)) then
begin
op_giq_option(1, 106, op_random(9170, 9180), @Node999, 50);
op_giq_option(1, 106, op_msg_string(106, 9160) + op_msg_string(106, (Chowtime)), @Node999, 50);
end
else
begin
op_giq_option(1, 106, 9150, @Node999, 50);
op_giq_option(1, 106, op_msg_string(106, 9160) + op_msg_string(106, (Chowtime)), @Node999, 50);
end
end
end

The next group of nodes govern a variety of miscellaneous things. Every npc script has an empty procedure called Node999, which is used to end any particular line of conversation and let the game know it's ok to close the dialogue screen.

procedure Node999
begin
end

Whenever the script needs to turn Miria hostile to the player, it does so by running Node998.

procedure Node998
begin
op_set_local_var(4, 2);
end

Node996 governs what happens if the player tries to escape the events of the "wedding scene" with Miria and her father in Modoc.

procedure Node996
begin
if ((op_global_var(297) bwand 131072) != 0) then
begin
biff := op_create_object(16777409, 28512, op_elevation(op_self_obj()), 101);
gun := op_create_object(385, 0, 0, -1);
op_add_mult_objs_to_inven(biff, op_create_object(95, 0, 0, -1), 4);
op_wield_obj_critter(biff, gun);
end
maybe_lock_input();
op_set_global_var(291, 0);
op_set_global_var(291, 100 + (op_global_var(291) % 100));
op_debug_msg("\n SET_STAGE_EVENT == " + op_global_var(291) + " in script " + op_obj_name(op_self_obj()));
op_set_global_var(291, op_global_var(291) - (op_global_var(291) % 100) + 1);
op_debug_msg("\n SET_STAGE_EVENT == " + op_global_var(291) + " in script " + op_obj_name(op_self_obj()));
op_set_global_var(0, op_global_var(0) + -50);
op_debug_msg("Player gains " + -50 + " Karma Points.");
op_set_global_var(37, 0);
op_set_global_var(38, 0);
op_set_global_var(39, 0);
op_set_global_var(40, 0);
op_set_global_var(41, 0);
op_set_global_var(42, 0);
op_set_global_var(43, 0);
op_set_global_var(44, 0);
op_set_global_var(45, 0);
if (op_global_var(0) >= 1000) then
op_set_global_var(37, 1);
else if (op_global_var(0) >= 750) then
op_set_global_var(38, 1);
else if (op_global_var(0) >= 500) then
op_set_global_var(39, 1);
else if (op_global_var(0) >= 250) then
op_set_global_var(40, 1);
else if (op_global_var(0) > -250) then
op_set_global_var(41, 1);
else if (op_global_var(0) > -500) then
op_set_global_var(42, 1);
else if (op_global_var(0) > -750) then
op_set_global_var(43, 1);
else if (op_global_var(0) > -1000) then
op_set_global_var(44, 1);
else
op_set_global_var(45, 1);
op_critter_attempt_placement(op_dude_obj(), 27501, op_elevation(op_dude_obj()));
if (op_item_subtype(op_critter_inven_obj(op_dude_obj(), 0)) == 0) then
begin
restock_obj := op_critter_inven_obj(op_dude_obj(), 0);
op_debug_msg("armour pid == " + op_obj_pid(restock_obj));
op_rm_obj_from_inven(op_dude_obj(), restock_obj);
end
op_set_local_var(7, 1);
end

Node995 is where the actual "wedding" cutscene in Modoc is performed.

procedure Node995
begin
if ((op_global_var(297) bwand 131072) != 0) then
begin
biff := op_create_object(16777409, 28512, op_elevation(op_self_obj()), 101);
gun := op_create_object(385, 0, 0, -1);
op_add_mult_objs_to_inven(biff, op_create_object(95, 0, 0, -1), 4);
op_wield_obj_critter(biff, gun);
end
op_game_time_advance(op_get_critter_stat(op_dude_obj(), 2) * op_random(4, 8) * (60 * 10));
op_set_global_var(194, op_global_var(194) + (((((op_get_critter_stat(op_dude_obj(), 3) * 50) + (op_get_critter_stat(op_dude_obj(), 2) * 25) + (op_get_critter_stat(op_dude_obj(), 5) * 13) + (op_get_critter_stat(op_dude_obj(), 0) * 12)) / 100) + (op_has_trait(0, op_dude_obj(), 94) * 2) + op_has_trait(2, op_dude_obj(), 13) + (((op_global_var(194) >= 100) or (op_global_var(232) > 0)) * 2 * (op_dude_obj() == op_dude_obj()))) * 1));
if (op_global_var(358) >= 9) then
op_set_global_var(589, 1);
if (((((op_get_critter_stat(op_dude_obj(), 3) * 50) + (op_get_critter_stat(op_dude_obj(), 2) * 25) + (op_get_critter_stat(op_dude_obj(), 5) * 13) + (op_get_critter_stat(op_dude_obj(), 0) * 12)) / 100) + (op_has_trait(0, op_dude_obj(), 94) * 2) + op_has_trait(2, op_dude_obj(), 13) + (((op_global_var(194) >= 100) or (op_global_var(232) > 0)) * 2 * (op_dude_obj() == op_dude_obj()))) >= 9) then
op_set_global_var(588, 1);
if (op_global_var(590) == 1) then
op_set_global_var(590, 0);
op_set_global_var(358, op_global_var(358) + 1);
op_set_global_var(398, 1);
maybe_lock_input();
op_reg_anim_func(2, op_dude_obj());
if (((op_game_time_hour() > 600) and (op_game_time_hour() < 1800)) == 0) then
op_game_time_advance((24 * (60 * (60 * 10)) * (op_game_time_hour() > 1200)) + (((1200 / 100) - (op_game_time_hour() / 100)) * (60 * (60 * 10))) + (((1200 % 100) - (op_game_time_hour() % 100)) * (60 * 10)));
op_set_global_var(291, 0);
if (106 == 106) then
begin
op_set_global_var(291, 200 + (op_global_var(291) % 100));
op_debug_msg("\n SET_STAGE_EVENT == " + op_global_var(291) + " in script " + op_obj_name(op_self_obj()));
op_critter_attempt_placement(op_dude_obj(), 27703, op_elevation(op_dude_obj()));
end
else
begin
op_set_global_var(291, 300 + (op_global_var(291) % 100));
op_debug_msg("\n SET_STAGE_EVENT == " + op_global_var(291) + " in script " + op_obj_name(op_self_obj()));
op_critter_attempt_placement(op_dude_obj(), 27697, op_elevation(op_dude_obj()));
end
if (op_tile_distance(op_tile_num(op_self_obj()), op_local_var(13)) > 1) then
op_critter_attempt_placement(op_self_obj(), op_local_var(13), 0);
op_critter_attempt_placement(op_dude_obj(), (27501 * ((op_global_var(291) - (op_global_var(291) % 100)) == 200)) + (27295 * ((op_global_var(291) - (op_global_var(291) % 100)) == 300)), op_elevation(op_dude_obj()));
if (op_item_subtype(op_critter_inven_obj(op_dude_obj(), 0)) == 0) then
begin
restock_obj := op_critter_inven_obj(op_dude_obj(), 0);
op_debug_msg("armour pid == " + op_obj_pid(restock_obj));
op_rm_obj_from_inven(op_dude_obj(), restock_obj);
end
op_set_global_var(291, op_global_var(291) - (op_global_var(291) % 100) + 1);
op_debug_msg("\n SET_STAGE_EVENT == " + op_global_var(291) + " in script " + op_obj_name(op_self_obj()));
end

While most of the above parts of the script are found in one form or another in the original Miria scripts, the next few are the new ones I wrote to govern the details of the "marriage simulation" to Miria. The first node is the "base" where all the various conversations with Miria about married life always start.

procedure Node2000
begin
op_giq_option(4, 106, 10010, @Node2100, 50);
op_giq_option(4, 106, op_random(10030, 10033), @Node2200, 50);
op_giq_option(4, 106, op_random(10048, 10051), @Node2300, 50);
op_giq_option(4, 106, 10070, @Node2400, 50);
op_giq_option(4, 106, 11200, @Node2600, 50);
op_giq_option(4, 106, 10006, @Node999, 50);
end

In Node2100, we ask Miria how her life is going in general and how she's feeling about herself.

procedure Node2100
begin
if (op_local_var(15) < 2) then
begin
op_set_local_var(15, (op_local_var(15) + 1));
op_set_global_var(791, (op_game_time() + (2 * (30 * (24 * (60 * (60 * 10)))))));
op_giq_option(4, 106, 10027, @Node100, 50);
op_giq_option(4, 106, 10029, @Node999, 50);
end
else
begin
if (op_global_var(791) >= op_game_time()) then
begin
op_set_global_var(791, (op_game_time() + (2 * (30 * (24 * (60 * (60 * 10)))))));
op_giq_option(4, 106, op_random(10022, 10023), @Node100, 50);
op_giq_option(4, 106, op_random(10024, 10025), @Node999, 50);
end
else
begin
op_set_global_var(791, (op_game_time() + (2 * (30 * (24 * (60 * (60 * 10)))))));
op_giq_option(4, 106, op_random(10026, 10027), @Node100, 50);
op_giq_option(4, 106, op_random(10028, 10029), @Node999, 50);
end
end
end

In Node2200, the player-character can score some points with Miria by expressing some verbal affection for her.

procedure Node2200
begin
op_set_global_var(792, (op_game_time() + (2 * (30 * (24 * (60 * (60 * 10)))))));
op_giq_option(4, 106, op_random(10039, 10040), @Node2500, 50);
op_giq_option(4, 106, 10041, @Node100, 50);
op_giq_option(4, 106, op_random(10042, 10043), @Node999, 50);
end

In Node2300, the player-character can score some points with Miria by telling her how pretty she is.

procedure Node2300
begin
op_set_global_var(793, (op_game_time() + (2 * (30 * (24 * (60 * (60 * 10)))))));
if (op_get_critter_stat(op_dude_obj(), 34) == 1) then
begin
op_giq_option(4, 106, op_random(10057, 10065), @Node2501, 50);
end
op_giq_option(4, 106, op_random(10066, 10067), @Node2500, 50);
op_giq_option(4, 106, 10068, @Node100, 50);
op_giq_option(4, 106, 10069, @Node999, 50);
end

Node2400 allows the player to get a general idea of whether Miria is happy overall with her marriage.

procedure Node2400
begin
if ((op_game_time() < op_global_var(791)) and (op_game_time() < op_global_var(792)) and (op_game_time() < op_global_var(793)) and (op_game_time() < op_global_var(794))) then
begin
if ((op_global_var(22) > 0) or (op_global_var(23) > 0) or (op_global_var(24) > 0) or (op_global_var(25) > 0) or (op_global_var(296) != 0)) then
begin
op_giq_option(4, 106, 10091, @Node100, 50);
op_giq_option(4, 106, 10089, @Node999, 50);
end
else if (op_global_var(295) > 0) then
begin
op_giq_option(4, 106, 10088, @Node100, 50);
op_giq_option(4, 106, 10089, @Node999, 50);
end
else if (op_global_var(26) > 0) then
begin
op_giq_option(4, 106, 10091, @Node100, 50);
op_giq_option(4, 106, 10089, @Node999, 50);
end
else if (op_global_var(230) > 0) then
begin
op_giq_option(4, 106, 10094, @Node100, 50);
op_giq_option(4, 106, 10095, @Node999, 50);
end
else if (op_global_var(11) != 0) then
begin
op_giq_option(4, 106, 11388, @Node100, 50);
op_giq_option(4, 106, 10093, @Node999, 50);
end
else if (op_global_var(0) <= -500) then
begin
op_giq_option(4, 106, 11370, @Node100, 50);
op_giq_option(4, 106, 11375, @Node999, 50);
end
else
begin
op_giq_option(4, 106, op_random(10085, 10086), @Node100, 50);
op_giq_option(4, 106, 10087, @Node999, 50);
end
end
else
begin
if ((op_global_var(22) > 0) or (op_global_var(23) > 0) or (op_global_var(24) > 0) or (op_global_var(25) > 0) or (op_global_var(296) > 0)) then
begin
op_giq_option(4, 106, 10091, @Node100, 50);
op_giq_option(4, 106, 10092, @Node999, 50);
end
else if (op_global_var(295) > 0) then
begin
op_giq_option(4, 106, 10098, @Node100, 50);
op_giq_option(4, 106, 10099, @Node999, 50);
end
else if (op_global_var(26) > 0) then
begin
op_giq_option(4, 106, 10091, @Node100, 50);
op_giq_option(4, 106, 10092, @Node999, 50);
end
else if (op_global_var(230) > 0) then
begin
op_giq_option(4, 106, 10094, @Node100, 50);
op_giq_option(4, 106, 10095, @Node999, 50);
end
else if (op_global_var(11) != 0) then
begin
op_giq_option(4, 106, 11052, @Node100, 50);
op_giq_option(4, 106, 11053, @Node999, 50);
end
else if (op_global_var(0) < -500) then
begin
op_giq_option(4, 106, 11054, @Node100, 50);
op_giq_option(4, 106, 11386, @Node999, 50);
end
else
begin
op_giq_option(4, 106, op_random(10088, 10089), @Node100, 50);
op_giq_option(4, 106, 10090, @Node999, 50);
end
end
end

Nodes2500, 2501, 2502, 2503, and 2504 all deal with carrying out the details of the player having sex with Miria. I've designed this process to differ from how sex with other npcs works in a few ways; for example spending some intimate time with one's wife doesn't contribute to the "Gigolo" reputation one can receive from sleeping around in the game. On occassion the player may approach Miria for sex, but be told she's having her monthly feminine issues. There is also a special form of "sex" that can be chosen as an option if the player-character is female, where she and Miria can gab about things like makeup and skin care (which they both enjoy as much as sex).

procedure Node2500
begin
if (20 >= (op_random(1, 100))) then
begin
if (50 >= (op_random(1,100))) then
begin
if ((op_get_critter_stat(op_dude_obj(), 34) == 1)) then
begin
op_giq_option(4, 106, 11035, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11036, @Node999, 50);
end
end
else
begin
op_giq_option(4, 106, 11037, @Node2504, 50);
op_giq_option(4, 106, 11038, @Node999, 50);
end
end
else
begin
call Node2503();
end
end

procedure Node2501
begin
op_set_global_var(794, (op_game_time() + (2 * (30 * (24 * (60 * (60 * 10)))))));
op_set_local_var(19,1);
call Node999();
end

procedure Node2502
begin
if (op_local_var(19) == 1) then
begin
op_display_msg(op_msg_string(106, 11000));
end
else
begin
if ((op_has_trait(0, op_dude_obj(), 94) == 1) or (op_global_var(232) > 0) or (op_global_var(588) > 0) or (op_global_var(194) >= 100)) then
begin
if (op_local_var(19) == 2) then
op_display_msg(op_msg_string(106, op_random(11003, 11012)));
else
op_display_msg(op_msg_string(106, 11008));
end
else
begin
if (op_local_var(19) == 2) then
op_display_msg(op_msg_string(106, op_random(11001, 11005)));
else
op_display_msg(op_msg_string(106, 11002));
end
end
op_float_msg(op_self_obj(), op_msg_string(106, op_random(11020, 11025)), 4);
end

procedure Node2503
begin
op_set_global_var(794, (op_game_time() + (2 * (30 * (24 * (60 * (60 * 10)))))));
op_set_local_var(19, 2);
op_game_time_advance(op_get_critter_stat(op_dude_obj(), 2) * op_random(4, 8) * (60 * 10));
op_set_global_var(194, op_global_var(194) + (((((op_get_critter_stat(op_dude_obj(), 3) * 50) + (op_get_critter_stat(op_dude_obj(), 2) * 25) + (op_get_critter_stat(op_dude_obj(), 5) * 13) + (op_get_critter_stat(op_dude_obj(), 0) * 12)) / 100) + (op_has_trait(0, op_dude_obj(), 94) * 2) + op_has_trait(2, op_dude_obj(), 13) + (((op_global_var(194) >= 100) or (op_global_var(232) > 0)) * 2 * (op_dude_obj() == op_dude_obj()))) * 1));
if (((((op_get_critter_stat(op_dude_obj(), 3) * 50) + (op_get_critter_stat(op_dude_obj(), 2) * 25) + (op_get_critter_stat(op_dude_obj(), 5) * 13) + (op_get_critter_stat(op_dude_obj(), 0) * 12)) / 100) + (op_has_trait(0, op_dude_obj(), 94) * 2) + op_has_trait(2, op_dude_obj(), 13) + (((op_global_var(194) >= 100) or (op_global_var(232) > 0)) * 2 * (op_dude_obj() == op_dude_obj()))) >= 9) then
op_set_global_var(588, 1);
if (op_global_var(590) == 1) then
op_set_global_var(590, 0);
call Node999();
end

procedure Node2504
begin
op_set_local_var(19,3);
op_game_time_advance(op_get_critter_stat(op_dude_obj(), 2) * op_random(4, 8) * (60 * 10));
if (op_get_critter_stat(op_dude_obj(), 34) == 1) then
begin
op_set_global_var(194, op_global_var(194) + (((((op_get_critter_stat(op_dude_obj(), 3) * 50) + (op_get_critter_stat(op_dude_obj(), 2) * 25) + (op_get_critter_stat(op_dude_obj(), 5) * 13) + (op_get_critter_stat(op_dude_obj(), 0) * 12)) / 100) + (op_has_trait(0, op_dude_obj(), 94) * 2) + op_has_trait(2, op_dude_obj(), 13) + (((op_global_var(194) >= 100) or (op_global_var(232) > 0)) * 2 * (op_dude_obj() == op_dude_obj()))) * 1));
if (op_global_var(590) == 1) then
op_set_global_var(590, 0);
end
call Node999();
end

Node2600 is where we track the overall "marriage score" between the player-character and Miria, and where conversations about her dreams for the future are handled.

procedure Node2600
begin
if (op_local_var(16) < 2) then
begin
op_set_local_var(16, (op_local_var(16) + 1));
op_giq_option(4, 106, 10022, @Node100, 50);
op_giq_option(4, 106, 10024, @Node999, 50);
end
else
begin
if (op_global_var(795) == 0) then
op_set_global_var(795, (op_random(1,8)));
else
begin
if (op_local_var(17) < 20) then
begin
if (op_global_var(0) > -500) then
begin
op_giq_option(4, 106, op_random(11370, 11372), @Node100, 50);
op_giq_option(4, 106, op_random(11375, 11377), @Node999, 50);
end
else
begin
op_giq_option(4, 106, op_random(11380, 11382), @Node100, 50);
op_giq_option(4, 106, op_random(11385, 11387), @Node999, 50);
end
end
else
begin
if (op_global_var(795) == 1) then
begin
if (op_global_var(52) <= -30) then
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
else
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11357, @Node100, 50);
op_giq_option(4, 106, 11358, @Node999, 50);
end
end
end
else if (op_global_var(795) == 2) then
begin
if (op_global_var(47) <= -30) then
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
else
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
end
else if (op_global_var(795) == 3) then
begin
if ((op_global_var(55) <= -30) or (op_metarule(17, 7) != 2)) then
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
else
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
end
else if (op_global_var(795) == 4) then
begin
if ((op_global_var(57) <= -30) or (op_metarule(17, 10) != 2)) then
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
else
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
end
else if (op_global_var(795) == 5) then
begin
if (op_metarule(17, 11) != 2) then
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
else
begin
if ((op_global_var(59) <= -30) or (op_global_var(422) != 1)) then
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_gsay_reply(106, op_msg_string(106, 11224) + op_msg_string(106, 11226));
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
else
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_gsay_reply(106, op_msg_string(106, 11224) + op_msg_string(106, 11225));
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
end
end
else if (op_global_var(795) == 6) then
begin
if ((op_global_var(56) <= -30) or (op_metarule(17, 13) != 2)) then
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
else
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11357, @Node100, 50);
op_giq_option(4, 106, 11358, @Node999, 50);
end
end
end
else if (op_global_var(795) == 7) then
begin
if ((op_global_var(59) <= -30) or (op_metarule(17, 4) != 2) or (op_global_var(137) != 0)) then
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
else
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 0) then
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
end
else
begin
if (op_get_critter_stat(op_dude_obj(), 34) == 1) then
begin
if ((op_global_var(49) <= -30) or (op_metarule(17, 1) != 0) or (op_global_var(728) != 3) or (op_global_var(14) != 0)) then
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
else
begin
op_giq_option(4, 106, 11355, @Node100, 50);
op_giq_option(4, 106, 11356, @Node999, 50);
end
end
else
begin
op_giq_option(4, 106, 11335, @Node100, 50);
op_giq_option(4, 106, 11336, @Node999, 50);
end
end
end
end
end
end

The remainder of the script deals with some remaining miscellaneous details of Miria's behavior. The next node, for example, determines what happens if the player-character uses something, like a beer or a stimpack, on Miria (causing her to give a special float text). If we wanted Miria to have a special reaction when some new or special item is used on her we'd add some new lines here.

procedure use_obj_on_p_proc
begin
if ((op_obj_pid(op_obj_being_used_with()) == 39) or (op_obj_pid(op_obj_being_used_with()) == 38)) then
begin
op_script_overrides();
op_display_msg("That does nothing.");
end
else if ((op_global_var(6) == 1) and (op_global_var(449) != 1)) then
begin
if ((op_obj_pid(op_obj_being_used_with()) == 40) or (op_obj_pid(op_obj_being_used_with()) == 144)) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5010, 5012)), 8);
else if (op_obj_pid(op_obj_being_used_with()) == 273) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5020, 5023)), 8);
else if ((op_obj_pid(op_obj_being_used_with()) == 124) or (op_obj_pid(op_obj_being_used_with()) == 125) or (op_obj_pid(op_obj_being_used_with()) == 469) or (op_obj_pid(op_obj_being_used_with()) == 311) or (op_obj_pid(op_obj_being_used_with()) == 310)) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5030, 5032)), 8);
end
end

The final procedure of the script governs the special comments Miria (gives depending on the particular location) when she and the player-character arrive on a new map. While this is a feature of all the traditional Miria mods, I've added some new lines for areas that didn't feature a comment before.

procedure location_floats
begin
if (75 >= op_random(1, 100)) then
begin
if ((op_cur_map_index() == 146) or (op_cur_map_index() == 145) or (op_cur_map_index() == 144) or (op_cur_map_index() == 144) or (op_cur_map_index() == 143) or (op_cur_map_index() == 142) or (op_cur_map_index() == 141) or (op_cur_map_index() == 125) or (op_cur_map_index() == 68)) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5720, 5724)), 12);
else if ((op_cur_map_index() == 74) or (op_cur_map_index() == 75)  or (op_cur_map_index() == 121) or (op_cur_map_index() == 122) or (op_cur_map_index() == 123) or (op_cur_map_index() == 124)) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5715, 5719)), 12);
else if ((op_cur_map_index() == 117) or (op_cur_map_index() == 116) or (op_cur_map_index() == 115) or (op_cur_map_index() == 114) or (op_cur_map_index() == 113) or (op_cur_map_index() == 84) or (op_cur_map_index() == 83) or (op_cur_map_index() == 82) or (op_cur_map_index() == 81) or (op_cur_map_index() == 2) or (op_cur_map_index() == 1) or (op_cur_map_index() == 0)) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5710, 5714)), 12);
else if ((op_cur_map_index() == 76) or (op_cur_map_index() == 77) or (op_cur_map_index() == 85) or (op_cur_map_index() == 86) or (op_cur_map_index() == 87) or (op_cur_map_index() == 88) or (op_cur_map_index() == 89) or (op_cur_map_index() == 90) or (op_cur_map_index() == 91) or (op_cur_map_index() == 110) or (op_cur_map_index() == 111) or (op_cur_map_index() == 112)) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5705, 5709)), 12);
else if ((op_cur_map_index() == 120) or (op_cur_map_index() == 119) or (op_cur_map_index() == 118) or (op_cur_map_index() == 73) or (op_cur_map_index() == 72) or (op_cur_map_index() == 71) or (op_cur_map_index() == 70) or (op_cur_map_index() == 69)) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5700, 5704)), 12);
else if (op_cur_map_index() == 130) then
op_float_msg(op_self_obj(), op_msg_string(106, 5680), 12);
else if (op_cur_map_index() == 132) then
op_float_msg(op_self_obj(), op_msg_string(106, 5679), 12);
else if (op_cur_map_index() == 133) then
op_float_msg(op_self_obj(), op_msg_string(106, 5678), 12);
else if (op_cur_map_index() == 134) then
op_float_msg(op_self_obj(), op_msg_string(106, 5677), 12);
else if (op_cur_map_index() == 131) then
op_float_msg(op_self_obj(), op_msg_string(106, 5676), 12);
else if (op_cur_map_index() == 129) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5674, 5675)), 12);
else if (op_cur_map_index() == 128) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5672, 5673)), 12);
else if (op_cur_map_index() == 148) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5670, 5671)), 12);
else if (op_cur_map_index() == 140) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5668, 5669)), 12);
else if (op_cur_map_index() == 139) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5666, 5667)), 12);
else if (op_cur_map_index() == 138) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5664, 5665)), 12);
else if (op_cur_map_index() == 137) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5662, 5663)), 12);
else if (op_cur_map_index() == 136) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5660, 5661)), 12);
else if (op_cur_map_index() == 135) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5658, 5659)), 12);
else if (op_cur_map_index() == 109) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5656, 5657)), 12);
else if (op_cur_map_index() == 79) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5654, 5655)), 12);
else if (op_cur_map_index() == 78) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5652, 5653)), 12);
else if (op_cur_map_index() == 64) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5650, 5651)), 12);
else if (op_cur_map_index() == 62) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5648, 5649)), 12);
else if (op_cur_map_index() == 59) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5646, 5647)), 12);
else if (op_cur_map_index() == 57) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5644, 5645)), 12);
else if (op_cur_map_index() == 56) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5642, 5643)), 12);
else if (op_cur_map_index() == 55) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5640, 5641)), 12);
else if (op_cur_map_index() == 54) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5638, 5639)), 12);
else if (op_cur_map_index() == 51) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5636, 5637)), 12);
else if (op_cur_map_index() == 46) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5634, 5635)), 12);
else if (op_cur_map_index() == 43) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5632, 5633)), 12);
else if (op_cur_map_index() == 42) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5630, 5631)), 12);
else if (op_cur_map_index() == 40) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5628, 5629)), 12);
else if (op_cur_map_index() == 36) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5626, 5627)), 12);
else if (op_cur_map_index() == 34) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5624, 5625)), 12);
else if (op_cur_map_index() == 31) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5622, 5623)), 12);
else if (op_cur_map_index() == 32) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5681, 5682)), 12);
else if (op_cur_map_index() == 27) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5620, 5621)), 12);
else if (op_cur_map_index() == 24) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5618, 5619)), 12);
else if (op_cur_map_index() == 22) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5616, 5617)), 12);
else if (op_cur_map_index() == 19) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5614, 5615)), 12);
else if (op_cur_map_index() == 18) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5612, 5613)), 12);
else if (op_cur_map_index() == 30) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5610, 5611)), 12);
else if (op_cur_map_index() == 16) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5608, 5609)), 12);
else if (op_cur_map_index() == 17) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5606, 5607)), 12);
else if (op_cur_map_index() == 15) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5604, 5605)), 12);
else if (op_cur_map_index() == 9) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5602, 5603)), 12);
else if (op_cur_map_index() == 6) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5600, 5601)), 12);
else if (op_cur_map_index() == 107) then
op_float_msg(op_self_obj(), op_msg_string(106, 5683), 12);
else if (op_cur_map_index() == 96) then
op_float_msg(op_self_obj(), op_msg_string(106, 5684), 12);
else if (op_cur_map_index() == 48) then
op_float_msg(op_self_obj(), op_msg_string(106, 5685), 12);
else if (op_cur_map_index() == 26) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5686, 5687)), 12);
else if (op_cur_map_index() == 23) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5688, 5689)), 12);
else if (op_cur_map_index() == 127) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5690, 5691)), 12);
else if (op_cur_map_index() == 10) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5692, 5693)), 12);
else if (op_cur_map_index() == 5) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5694, 5695)), 12);
else if (op_cur_map_index() == 4) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5696, 5697)), 12);
else if (op_cur_map_index() == 157) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5698, 5699)), 12);
else if (op_cur_map_index() == 158) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5800, 5801)), 12);
else if (op_cur_map_index() == 156) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5802, 5803)), 12);
else if (op_cur_map_index() == 155) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5804, 5805)), 12);
else if (op_cur_map_index() == 152) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5806, 5807)), 12);
else if (op_cur_map_index() == 151) then
op_float_msg(op_self_obj(), op_msg_string(106, op_random(5808, 5809)), 12);
end
end

That's it! Now that you've copied each of the sections of code above into a text file, save the file with the name mcmiria.ssl and compile it with your script compiler (which will give you a new file called mcmiria.int). Then simply replace the existing mcmiria.int in your Fallout2\data\Scripts folder with the new one you just made (after you've made a backup of the original, of course, in case you ever want to switch back). A few things to keep in mind are:

--If the script failed to compile, then most likely you either didn't copy/paste ALL the code above, or you pasted it into a fancy text editor instead of a plain text editor and some formatting symbols remain, or you tried to compile it with FSE without first converting the syntax over from "Noid's" format. I've compiled, decompiled, and recompiled the script many times using Noid's compiler, however, and there are no errors that should ever prevent it from compiling.

--When you make a new script, you can't just drop it into an existing game that you load from a saved game. Most likely you'll need to start a brand new game for your new script to be assigned instead of the original, although a) if the script is for a unique character and b) you've never visited the map containing that character and c) the script doesn't require making any changes to vault13.gam, then you may be able to have the new script assigned during an existing game the when you enter a map for the first time. However, since our Miria script requires changes to vault13.gam there's no way around it, you'll have to start fresh from the character creation screen and the the Temple of Trials.

The Dialogue

Miria's script determines that certain lines of dialogue will be shown at certain times without specifying the particular text that will be shown in the game. That job is left to her dialogue file, which (like all other dialogue files in the game) is a plain-text file containing numbered lines of text organized between lots of braces { }.

The dialogue lines below come from a number of sources: the original Black Isle dialogue lines, traditional Miria mod lines, killap's spelling bugfix lines and grammer rewrites, as well a fair number I either wrote or rewrote myself. Once again I remind the reader that most of the fun of making a mod is making it your own mod (as I have done for myself with the traditional Miria mod). Therefore if you want to rewrite anything below into something that you like better, go for it! That's the whole point of this article.

If there's one aspect of the mod presented in this article that may yet need some work in terms of flawless functionality, it's here. Since the way the mod works is that the player-character is expected to repeatedly have what are in the end very similar conversations, I've written multiple lines that are presented randomly to the player in the dialogue screen in order to keep things fresh and prevent seeing the same old text over and over again. One interesting aspect of this approach, however, is that it's difficult to test random behavior. Occassionally random combinations of text may come together in the player's response lines to Miria with the result that one or more or the lines of text are a bit too long, crowding some of the lines below them off the bottom of the response area where the player can't see them. I've tested the mod a lot and already fixed most of these problems, but you may occassionally still see the issue. Don't worry, though, you should never get "stuck" in any dialogue with Miria as I designed the conversations with her to always lead back to a central nexus node (either Node100 or Node2500). If the option you want to use has been crowded off to the bottom of the screen and isn't displayed, just pick something else and come back--the text will be rerandomized and the line you want will probably be there.

In any case open an new, empty text file in a plain text-editor (the same concerns about extraneous formatting symbols we had when constructing Miria's script remain in effect for her dialogue file) and copy paste all the numbered lines of below. Make sure you get all the { } braces, as if a dialogue file is missing even one single brace it will crash your game when called upon to do its job. At the time of posting this article, not a single brace was missing so it should work just fine for you (as I've been using it in my own games for some time now).

{100}{}{Oh my! A very shapely and seductive looking woman.}
{101}{}{Miria.}
{102}{}{You’re not sure, but the measurements 36-24-36 come to mind.}
{106}{}{She's twirling her hair around her fingers.}
{107}{}{She's looking at her manicure.}
{108}{}{She looks like she's daydreaming.}
{109}{}{There's no denying it, she's a beauty.}

{150}{}{Bitch!}
{151}{}{How dare you show your face around here!}

{152}{}{That’s just sick!}
{153}{}{I hope you two are happy together.}

# Node 0
{154}{}{Why, hello there, stranger. I’m Miria.}
{155}{}{I am so pleased you came back. Anything I can do... for you?}
{156}{}{What do you do around here?}
{157}{}{What can you tell me about the slaughterhouse?}
{158}{}{Heard any good rumors?}
{159}{}{Hubba! Hubba!}

# Node 2
{160}{}{Sure. It's so boring around here, and I hardly ever have anyone to really talk to.}

# Node 10
{164}{}{Rumor has it that Farrel stole the watch.}
{165}{}{Why would Farrel steal the watch?}
{166}{}{Isn’t Farrel Cornelius’ best friend?}
{167}{}{Tell me some more rumors.}

# Node 11
{168}{}{Because poor people tend to steal to make ends meet. Farrel definitely falls in the poor
category, and that would explain the new tools he bought soon after Cornelius’s watch disappeared.}
{170}{}{Can I ask you a few more questions?}

# Node 12
{171}{}{Yes, they were thick as thieves, those two. Which is why I think Farrel stole the watch. Who
else but Farrel would have the access and the opportunity to steal Cornelius’s watch?}

# Node 13
{174}{}{There's not much to tell. My family runs the slaughterhouse, and people from all around bring their brahmin in for culling. After the animals are processed we treat and cure the meat, and it's sold to traders who then distribute it to merchants in various towns. [She sighs] All very boring, if you ask me.}

# Node 14
{176}{}{Have you come to the right place! This town is so boring, sometimes it seems like there’s nothing else to do but gossip. So the other day I'm... [she enthusiastically talks for quite awhile before you’re able to get a word in edgewise.]}
{177}{}{What else do you want to know?}
{178}{}{What do you know about the Cornelius’ missing watch?}
{180}{}{What’s this about a mutated brahmin?}

# Node 15
{183}{}{Rose, the lady that runs Rose's Bed and Breakfast? Now, you didn’t hear it from me, but have you ever wondered why her ‘coop’ is so well protected? She says it’s to protect her chickens from predators, but if you look closely it looks as if she’s trying to keep something in rather than out. Plus, whoever heard of chickens laying twelve pound eggs?}
{184}{}{Tell me more rumors.}

# Node 16
{186}{}{It’s really strange, but I hear some ranchers say that every once in a while a brahmin will give birth to a calf with only one head. Talk about weird!}

# Node 17
{189}{}{Davin's a good guy. I'm definitely not going to dish any dirt on my own brother to you, though. Family is really important to me, and I soooo can't wait to have a family of my own one day.}

# Node 18
{192}{}{Who, me? Oh, I do odd jobs here and there. Surely nothing worth talking about. [She flutters her eyes at you and smiles]}
{193}{}{I really would like to know more about you.}
{194}{}{You're right, enough talk. Let's get it on! You know you want it!}

# Node 19
{196}{}{I’m really touched. Nobody ever tries to get to know me better. All they want is sex, sex, sex!
I get so tired of having wild sex all the time. I’m so glad you’re not like the others.}
{197}{}{Forget about it, Miss Ho-bag. And to think I thought you were special for a moment.}
{198}{}{You know, I’m just a normal guy like everyone else. Why, my friends say, "}
{199}{}{ you’re just so cool because you’re normal just like everyone else." Yep, normal that’s me.}
{200}{}{Well, I’ve never known anyone as fascinating as you.}

# Node 20
{202}{}{Want what? Just what are you implying?}
{203}{}{I think you know what I’m talking about, girl. Come here, I've got something for you. [You smile and start to undress.]}
{204}{}{I didn’t mean to imply anything. I'm sorry if I upset you.}

# Node 21
{205}{}{How dare you call me a slut! Let me tell you, I am very picky about the people I sleep with.
Why, I only slept with 3 or 4 people this month! This conversation is over!}

# Node 22
{206}{}{How disappointing. You are just like everyone else, aren’t you?}

# Node 23
{208}{}{No. I don’t think so. I’m tired of this conversation. Good bye.}

# Node 24
{209}{}{[She blushes] Stop it, you’re embarrassing me. Aren't you are just the sweetest thing? Why don’t come over here and sit on the bed with me.}
{210}{}{I think this going too far. Can’t we just talk a little?}
{211}{}{I thought you’d never ask. I just feel so comfortable around you, I'm not usually like that with most people.}
{212}{}{All right! You know what I want, baby!}
{213}{}{You are a slut, aren’t you!}

# Node 25
{214}{}{I can’t take this anymore! You’re perfect. [She rips off her clothes, your clothes, and starts probing the the back of your throat with her tongue as she runs her hands over your naked body.]}
{215}{}{[You're overwhelmed by the feeling that your life will never be the same again.]}

# Node 26
{216}{}{That better not mean what I think that means.}
{217}{}{Aoooga!}
{218}{}{Urg?}

# Node 27
{219}{}{Yup! That’s what I thought. It’s funny how Neanderthal and civilized speech all sound the same on some subjects. [You don’t even see it coming. But you’re fairly sure that bright red hand print on your face will go away eventually.]}

# rape script dialog
{251}{}{Get away!}

{270}{}{Help! Get him away!}
{280}{}{Help! Get her away!}

# wedding script dialog
{401}{}{Uh oh!}
{402}{}{I surely do!}

{410}{}{Uhh...}
{412}{}{I sure the hell…}
{413}{}{Um… I... do.}

{420}{}{Uncle Biff!}

{450}{}{Uhhh, I think daddy's the one you should be talking too.}

{470}{}{Uhhh, I think Uncle Biff's the one you should be talking too.}

{500}{}{Great, I guess this means I have to run this dump now.}

{1000}{}{What's up, babe?}
{1001}{}{What is it, sweetheart?}
{1004}{}{Hey there, sweetie.}
{1005}{}{No, no, no... not that kind of distance! I just need you hang back a little when we're walking around.}
{1006}{}{Relax, honey. I just need a little more space when we're walking around.}
{1007}{}{I'll try harder, baby. It's just that it's hard to get "us" time out here in this wasteland.}
{1008}{}{My stuff is your stuff, dear.}
{1009}{}{Of course, sweetie. Do we have to stop with *just* my armor?}
{1010}{}{Sometimes Daddy made me help in the slaughterhouse, so I know a little about sharp stuff like knives. And growing up on a farm, I've shot rifle and a pistol before, but I'm not really a very good shot, and they're *so* noisy. And then there's that gunpowder smell, I mean...}
{1020}{}{We need to talk about the distance between us.}
{1100}{}{I'm all healed up and ready to go, honey.}
{1200}{}{I all better, except for a few bruises. Nothing to worry about too much about.}
{1300}{}{Well, I mostly feel better -- but I'll need some more time to patch things up when we get some time to rest.}
{1400}{}{Baby, I tried to heal myself as much as I could, but I'm still hurt pretty bad. Do something, honey!}
{1500}{}{Baby, no. We're in this thing together, and I wanna come with you.}
{1600}{}{If you think it's a good idea, then sure. I'll put it away, honey.}
{1700}{}{Aww, does somebody wanna cuddle?}
{1800}{}{But sweetheart, then we won't be able to hold hands! [She sighs] Whatever.}
{1900}{}{Yeah. I'll just follow ten steps behind you, "master." What's next, a damn robe and a veil? Oh and by the way, next time you want some sex... have fun playing with yourself, because I'm planning a headache that day.}

{5000}{}{That's weird... my nails are all rubbery... oh my God, one just fell off!}
{5001}{}{Honey, look at me! Something's wrong wrong with my skin! Help me, baby!}
{5002}{}{I feel sick... Stay back, I think I'm gonna... [She vomits]}
{5003}{}{Ohhh my God. I feel sooo sick.}
{5004}{}{Arggh, I think I broke something! Help me, honey!}
{5005}{}{Nnnnnnnnnnnggggghhh... ithurtsithurtsohgodithurtsithurts...}
{5006}{}{Baby, help me... it hurts so much!}
{5007}{}{Oh my God, I'm gonna bleed to death! Do something, honey!}

{5010}{}{Ahhh... that feels SO good. You're so good to me, honey.}
{5011}{}{Woah, head rush! Thanks though, babe.}
{5012}{}{Are you sure these are safe, dear?}

{5020}{}{I feel kinda numb, babe. But it's a good numb.}
{5021}{}{Woah, that feels kinda nice.}
{5022}{}{So your tribe uses these to get stoned?}
{5023}{}{This one time I saw my grandad and buddies burn a whole pile of these in the shed... it was so weird, they started a fire and closed all the windows and doors... I freaked out, of course, and then I told mom, and she freaked out, and...}

{5030}{}{Sweet! Partytime!}
{5031}{}{Mmm, that was good, babe.}
{5032}{}{Trying to get me drunk, huh? Yeah, I know all your little tricks, but I love you anyway.}

{5100}{}{Go here, go there, I can't take it anymore!}
{5101}{}{Quit poking me! Well, I mean, not in public anyway.}
{5102}{}{Feelin' frisky, huh?}
{5103}{}{Can't keep your hands off me, eh?}

{5200}{}{[She blows you a kiss]}
{5201}{}{This outfit makes me look fat, doesn't it? I knew it.}
{5202}{}{[She flashes you a flirty smile]}
{5203}{}{What? Is there something stuck on my ass?}
{5204}{}{*BLUSH*  Stop it sweetie, you're embarrassing me.}
{5205}{}{What, do I have a rash or something?}
{5206}{}{You can never give me too much attention, sweetie.}

{5500}{}{When are we gonna settle down, hon? I want babies. I know, but maybe we can adopt some.}
{5501}{}{Oh please, honey.  Your boobs are SO much nicer than my boobs.  Well, let's ask that guy over there and see what he thinks.}
{5502}{}{I think I'm getting my period, hon. Do we have any more pads?}
{5503}{}{I wonder how dad's coping? Actually, I don't care.  I can't believe he called me a rugmuncher in front of the mayor.}
{5504}{}{Will you do my nails later, sweetheart?  You paint those little hearts on so much better than I can.}
{5505}{}{I like the way you did your hair today, babe.  You look fucking hot.}
{5506}{}{Do you have any hand lotion, babe?}
{5507}{}{We need a vacaction. When are you going to take me somewhere romantic?}
{5508}{}{I have to go pee, honey.}
{5509}{}{But do we *always* have to be on the go? I mean we never even had a honeymoon!}
{5510}{}{No, honey. I love YOU more.}
{5511}{}{Why are we always moving around? I mean, can't we just find a nice farm somewhere and play house for a while?}
{5512}{}{I don't *care* what some girl in your tribe did, I'm *not* getting my clit pierced.}
{5513}{}{Can't we just forget all this stuff and go cuddle somewhere?}
{5514}{}{I love the way that outfit brings out the color in your eyes, sweetie}
{5515}{}{Damn it, you were *so* checking out that girl's ass.  I can't believe you sometimes!}
{5516}{}{Baby *I know* your tribal customs and all, but I'm not gonna walk around topless so every lowlife in the wasteland can stare at my boobs.}
{5517}{}{I shaved my legs for this?}
{5518}{}{I don't know if you've noticed or not, but I regularly get this psychological urge to stand in doorways.
It's not annoying you baby, is it?}
{5519}{}{What was that, dear? Sorry, I was just thinking about how things are back home in Modoc.}
{5520}{}{OWW! DAMN! I just broke a nail.}
{5521}{}{Do you think I look okay in this outfit?}
{5522}{}{When are we gonna settle down, honey?}
{5523}{}{Oh honey, remind me to get some more maxipads next time we find a store.}
{5524}{}{Do you think there's a jewelry store anywhere around here?}
{5525}{}{You look so handsome today, sweetie.}
{5526}{}{Sweetheart, will you rub my neck later? I'm getting stiff.}
{5527}{}{I still can't get over the nerve of that bitch back there. Who did she think she was, checking out my husband's butt like that?}
{5528}{}{Baby, I need some new clothes. This outfit just isn't working for me.}

{5600}{}{Honey, this place is filthy. Can't you ever take me anywhere nice?}
{5601}{}{That's just great. Slavers and jetheads. You sure know how to show a girl good time.}
{5602}{}{And I thought Modoc was the middle of nowhere!}
{5603}{}{A nice hot bath? That sounds soooo good right now.}
{5604}{}{Well, it sure doesn't look very impressive from out here.}
{5605}{}{So wait, they just sit inside those walls while all these poor people suffer out here right under their noses?}
{5606}{}{Wow, I think this is the cleanest place I've ever seen.}
{5607}{}{And I thought *I* was obsessed with cleanliness!}
{5608}{}{Aww, how cute. All their little outfits match, honey.}
{5609}{}{Are they all related? They look like they're all related to me.}
{5610}{}{Can somebody turn up the heat? It's freezing in here.}
{5611}{}{Woah, look how shiny that floor is! I've gotta find out how they do that.}
{5612}{}{Who said you can never go home again?}
{5613}{}{It's just like I remembered. Unfortunately.}
{5614}{}{I want some brahmin-fries, honey. Buy me some brahmin fries? Pleeeaaassee?}
{5615}{}{This place will never change.}
{5616}{}{I think Davin and his friends used to play down here when they were kids. Gross.}
{5617}{}{Like, ewww!}
{5618}{}{Poor Karl. I would've been scared off too.}
{5619}{}{Oh my god! Wait, they're not real... damn, I feel silly.}
{5620}{}{Okay, this place is freaking me out. Can we leave, like now?}
{5621}{}{Honey, can I wait outside?}
{5622}{}{Where are all the girl ghouls? What kind of sexist town is this, anyway?}
{5623}{}{But their parts are, like, falling off! And they smell so bad! Gross!}
{5624}{}{We shouldn't be down here...}
{5625}{}{For some reason I think they'd look better in red and white jumpsuits. What do you think, honey?}
{5626}{}{Somebody should hose this place down.}
{5627}{}{Is *EVERYTHING* busted here?}
{5628}{}{So this is Vault 13? I was expecting it to be... bigger.}
{5629}{}{So wait, baby, why are we here again?}
{5630}{}{These people must be rich! I've never seen so many big buildings!}
{5631}{}{Oh my gawd, those blue suits are *awful*!}
{5632}{}{So you're related to that giant statue guy? Cool!}
{5633}{}{This place is such a drag, honey. Let's go somewhere fun.}
{5634}{}{Talk about a tale of two cities...}
{5635}{}{I think some of these people are up to no good, sweetie. Don't worry, I'll keep my eyes open.}
{5636}{}{This is just... eerie. I mean, all abandoned tents, just sitting out here in the middle of nowhere...}
{5637}{}{Make sure you search *EVERYWHERE*, okay? I mean God forbid you should miss out on one freaking stimpack...}
{5638}{}{Woah. Look at all these people!}
{5639}{}{You'd better keep a close eye on me, sweetie. I don't like all these big crowds of people.}
{5640}{}{Look at all those whores. I'm not letting you out of my sight, honey.}
{5641}{}{This place is crazy! There's all these, like, businesses and stuff.}
{5642}{}{It's pretty hard to tell around here, but I think this is the bad side of town.}
{5643}{}{If these people would clean this place up, they could have a nice town here.}
{5644}{}{Someone should start a soup kitchen in one of those abandoned buildings.}
{5645}{}{Someone should start a rehab clinic in one of those abandoned buildings.}
{5646}{}{Okay this place is freaking me out. Let's get outta here.}
{5647}{}{I don't want to stay here one minute longer than necessary. Do you hear me?!}
{5648}{}{Oh, that slime is just too nasty.}
{5649}{}{So they mined gold here? Like for jewelry and stuff?}
{5650}{}{These people have more brahmin than daddy!}
{5651}{}{They have gold here, baby! Maybe they have a jewelry store!}
{5652}{}{This place feels... on edge. Know what I mean? No? Oh well.}
{5653}{}{Wait... I thought we didn't like mutants? I'm confused, darling.}
{5654}{}{Maybe we could get one of these houses cheap, honey. You know, so we could settle down and start a family.}
{5655}{}{I don't know, I don't think we should be hanging around that mine.}
{5657}{}{We should get out of here right now.}
{5658}{}{So this whole giant place floats across the water? Yeah, right.}
{5659}{}{I'm just a redneck in a rock and roll bar...}
{5660}{}{Something's fishy here... hah! Fishy, get it? Hey, you're the one who married me.}
{5661}{}{Oh gross, that guy has fish guts on his clothes...}
{5662}{}{Wow! I love these buildings! Look at the design work!}
{5663}{}{Wait, aren't these the people that blew up the world?}
{5664}{}{Fly? In the air? Yeah, right.}
{5665}{}{I think they're gonna need a bigger runway.}
{5666}{}{Sweet, someone got this map back in the game!}
{5667}{}{I don't know, those seats don't look very comfortable.}
{5668}{}{How come they all have that brain-dead look on their face?}
{5669}{}{We should start a cult, too, sweetie. People would like, give us stuff. And the new recruits could give me pedicures. Just kidding. Except for the pedicure part.}
{5670}{}{I never knew there were this many computers in the whole world...}
{5671}{}{I've never seen so many smart people in all my life.}
{5672}{}{Let's not hang around here, okay?}
{5673}{}{I sure don't want to do time here.}
{5674}{}{Honey... I'm scared.}
{5675}{}{Do we really have to do this?}
{5676}{}{This is crazy! Let's get out of here!}
{5677}{}{Whoever thought this thing up is one twisted SOB.}
{5678}{}{Uhh... honey, what are we doing here?}
{5679}{}{I can feel the sleeze oozing out of the walls around here.}
{5680}{}{You can do it, sweetheart! I believe in you!}
{5681}{}{Can I get some rad-x, baby?}
{5682}{}{Let's not hang around here. I don't want to turn into one of those things.}
{5683}{}{Aww, look at that cute little puppy. Can we keep him?}
{5684}{}{This just doesn't make any sense.}
{5685}{}{So that thing came from the sky? Really?}
{5686}{}{Aww, honey, when are we going to have some kids?}
{5687}{}{Look at all these poor kids. Can we adopt them?}
{5688}{}{Heh, I lost my virginity down here. Don't ask, it's a long story.}
{5689}{}{When I was little, daddy told me an angel came every night to collect all the coins down here.}
{5690}{}{Oh honey, I'm so sorry...}
{5691}{}{I... I don't know what to say, sweetheart.}
{5692}{}{These trappers are a rough bunch, babe. Keep me close.}
{5693}{}{I think more than a few of these guys need to visit that bath place. They smell baaaddd.}
{5694}{}{I'm so nervous about meeting your family. I wish I had time to get a manicure and curl my hair first.}
{5696}{}{I sure hope they all like me.}
{5697}{}{So, this is where you grew up? I feel like I understand so much more about you now, honey.}
{5698}{}{I think we're the first people to see this place in years.}
{5699}{}{They sure built 'em big before the apocalypse.}

{5700}{}{I hate caves. Let's not go in there, okay?}
{5701}{}{Oh look. Cavetastic! Yay!}
{5702}{}{Hey, another empty cave!}
{5703}{}{Let's skip the cave tour this time, okay babe?}
{5704}{}{It's dark in there, sweetie. Will you hold my hand?}

{5705}{}{Woah! Look at all that water!}
{5706}{}{Mmmm! The air smells so clean here!}
{5707}{}{DID YOU SEE THAT?! Something *HUGE* just jumped out of the water!}
{5708}{}{Who's up for some skinnydipping?}
{5709}{}{Well I'd love to go swimming, if *someone* would buy me a new swimsuit.}

{5710}{}{I hope we find an oasis soon.  We could both use a bath.}
{5711}{}{I'm thirsty.}
{5712}{}{Look! There's house over there! Over there, silly! Are you bli... eh, where'd it go?}
{5713}{}{I got some sand in my panties, honey.}
{5714}{}{Eww, you're all sweaty. Double eww, I'm all sweaty too!}

{5715}{}{My feet hurt, sweetie.  How about giving me a massage?}
{5716}{}{Can we go downhill now? Just for a little while?}
{5717}{}{What is it with you and mountains, anyway?}
{5718}{}{Ooh, this romantic view really puts me in the mood sweetie.}
{5719}{}{Why are we even here? Nobody in their right mind would live out here.}

{5720}{}{I bet this place was so nice once. I can't believe those fools blew it all up.}
{5721}{}{Yeeooww! What are all those shadows? I'm scared!}
{5722}{}{Do you think we could fix up one of those houses, sweetie? You know, and just live in one place for a while?}
{5723}{}{This place makes me sad. I think I'll go cry.}
{5724}{}{Just think of all the families who used to live here. Until they blew themselves up. What were they thinking?}

{5800}{}{This place gives me the willies.}
{5801}{}{And to think a place like this could just be... forgotten.}
{5802}{}{Sometimes I wish we could settle down to a simple life like this.}
{5803}{}{I'd like to go for a swim, but I'm not sure if I should strip down in front of all these, savag... er, I mean, strangers. Sorry, honey.}
{5804}{}{Ah, barefoot and fancy-free. I might be able to get into this kind of lifestyle.}
{5806}{}{A vow of chastity? You're kidding, right?}
{5807}{}{So, are we in Fiat Homo or Fiat Lux?}
{5808}{}{This looks like a nice place to rest for a while.}
{5809}{}{Maybe I should wait outside. Daddy always told me we're Lutherans.}

{6000}{}{When are you gonna buy me a new outfit, babe?}
{6001}{}{It feels so good to be out of that sweaty armor for once.}

{6005}{}{I bet Balthas could fix this up into something really nice.}
{6006}{}{Can't you get something better for me to wear than a stinky old brahmin hide?}

{6010}{}{Hey, does this outfit turn you on? It turns me on...}
{6011}{}{Oh yeah. I look pretty hot in this, dontcha think?}

{6015}{}{Hmmm, does this mean I'm your knight in shining armor, sweetie?}
{6016}{}{But it's rusty, sweetie! And it needs a good polish! I'm just saying, I don't like it.}

{6020}{}{Do you think this is a flattering color for me, dear?}
{6021}{}{Check out how this outfit hugs my... oh, you already noticed eh?}

{6025}{}{I know you want me to be safe, darling, but it's sooo hot in here!}
{6026}{}{Woah! Time to kick somebody's ass!}

{6030}{}{Mmfjf mflfffmmmphh? Hmmpphhhmmmmph!}
{6031}{}{Yay! I always wanted to be as big as a fridge!}

{6035}{}{Oh, this is niiiicce... And I *love* this color! Thanks, honey!}
{6036}{}{Nice one, hon! It's a little frumpy, but... can anyone say easy access?}

{6040}{}{This thing better be working.}
{6041}{}{How long do I have to wear all this crap?}

{8000}{}{Okay, baby... but don't be long, okay?}
{8001}{}{Oh, suuuure. That's just GREAT... I guess I'll just sit and file my nails then, ok?}
{8002}{}{I guess so, but you better behave while you're gone! I'll know it if you don't!}
{8003}{}{All right, darling. Here, have a kiss for good luck. *smooch*}
{8004}{}{All right. I trust you. Just be safe and come back in one piece, okay sweetheart?}

{8005}{}{Oh I missed you so much, sweetie! While you were gone I... [Miria enthusiastically fills you in on the tiniest details of how she spent every... single... minute... during your absence. Twice.}
{8006}{}{[She sniffs your clothes and checks your collar]. You're damn lucky I can't smell some other woman's perfume on you. If you're done screwing around, can we leave?}
{8007}{}{[She gives you a tight hug]. Hey babe, I missed you.}
{8008}{}{You look beat, honey. Let's go somewhere and I'll give you a nice massage.}
{8009}{}{Oh baby, I was so worried about you, out there facing God knows what dangers... Please, I can't bear to be apart from you any more!}

{8010}{}{Baby... I don't know, you scare me sometimes... Okay, okay! Please don't start yelling at me again!}
{8011}{}{[For the briefest of moments there's a look of fear in her eyes] Yes dear, of course.}

{9000}{}{I'm sorry, baby. *sob* I'll try harder.}
{9001}{}{Stop, baby, please! I'll do whatever you want!}
{9003}{}{[bursts into tears]}
{9004}{}{Asshole! I've had it with you!}
{9005}{}{You can't treat me this way!}
{9006}{}{Enough! I don't have to take your bullshit!}

{9100}{}{She's giving you the evil eye.}
{9101}{}{She looks a bit shabby and has a crazed look in her eyes. She seems very angry.}

{9120}{}{Get away from me. It's over.}
{9130}{}{I'm so sorry, honey. I hope you can forgive me someday.}
{9140}{}{I just stopped by to tell you I found somebody new. She's younger than you, better-looking than you, and she's a lot better in the sack too. I'm outta here.}

{9150}{}{I really missed you, too, Miria.}
{9160}{}{I'm hungry. Let's get moving so you can get }
{9161}{}{breakfast started.}
{9162}{}{supper started.}
{9163}{}{dinner started.}
{9170}{}{Don't sass me, woman. Let's go.}
{9180}{}{[Grab her arm] Get your ass over here, woman.}

{9190}{}{Like I'm going ANYWHERE with you after what you did in Modoc. Get away from me.}

{9200}{}{Let's get going, babe.}
{9201}{}{Are you ready to go, Miria?}

{9210}{}{I'm worried about you. Will you try to patch up your wounds?}

{9220}{}{Let's take a look at your equipment.}
{9221}{}{What are you doing? Get over and let me look at your gear.}

{9230}{}{I've got to take care of some things, and it's not safe for you to come along. Will you wait for me here, babe?}
{9231}{}{Sit your ass down right here, woman. Wait for me until I get back.}

{9240}{}{[Kiss her]. Ok, that's all I needed right now.}
{9241}{}{I guess that's all we needed to talk about right now.}
{9242}{}{That's all I wanted to talk to you about right now.}

{9250}{}{Put that weapon away, honey.}
{9251}{}{Put away that weapon! Can't you do anything right?}

{9260}{}{Why don't you slip out of that armor you're wearing?}
{9261}{}{Get that armor off, woman.}

{10001}{}{Really? Sure thing, honey. What's on your mind?}
{10002}{}{I've been wanting to talk to you, too. What's on your mind?}
{10003}{}{Of course, sweetheart. What did you want to talk about?}
{10004}{}{I always have time to talk to my sweetie. What's up?}
{10005}{}{Um... sure. What is it you wanted to talk about?}
{10006}{}{Actually, I changed my mind. We'll talk later.}

{10010}{}{How are things? I mean the big picture. Are you doing okay?}
{10011}{}{I don't know. I mean, my life has changed so much since I met you. Sometimes it's hard to understand all that's happened to me.}
{10012}{}{I guess. Life is hard out here in this wasteland, and sometimes I miss my family. But I'm happy we're together, and I don't have any regrets.}
{10013}{}{Sometimes I miss the simple life and being on the farm back in Modoc, but I wouldn't trade being with you and the excitement of adventuring across the wastelands for anything.}
{10014}{}{It seems like it was just yesterday that I was a little girl, playing with my dolly at the farmhouse. I've had a lot adjust to since we got married, but I think I'm doing okay with it. And being with you makes it all a lot easier, honey.}
{10015}{}{When I was growing up, I never imagined I'd have a life like we have. Now that we're out here doing it, though, I have to say I wouldn't trade the way we live for anything.}
{10016}{}{I'm guess I'm good, babe. You inspire me to be something more than I ever thought I could be, and I really like the unexpected way my life is turning out since I met you.}
{10017}{}{Sometimes I feel lonely out here in this wasteland. I mean, you're always busy saving every clueless fool who crosses our path, and I understand you have to be who you are. But once in a while I wish I had some friends of my own to talk to about things, since I hardly ever get a chance to really talk to you.}
{10018}{}{I don't know. I've been thinking a lot lately about my family and friends back in Modoc. I never thought I'd say this but I guess I sort of miss them, even if they do smell like brahmin dung all the time. At least with all those people around, there was always somebody around for me to talk to.}
{10019}{}{I guess maybe I'm a little jealous sometimes, sweetheart. I mean, we run all over the wastelands meeting interesting new people... and they all want to talk to you, or want your help, or want to be around you. I'm proud of you, but sometimes I feel like a wallflower.}
{10020}{}{Sometimes I feel like I don't really fit in. I mean we're always fighting for our lives, exploring spooky old vaults, and even meddling in politics. I'm just a simple farmgirl, and nothing I experienced growing up really prepared me to deal with any of those things.}
{10021}{}{I don't know, honey. Sometimes I just wish you and I could go somewhere and be alone, and just have a normal life. Our only friends are your friends, we're always doing what you want, and going where you want to go. I know it's selfish, but I hope we can just settle down someday and leave all this excitement behind.}
{10022}{}{I'm happy if you're happy, Miria. Let's talk about something else.}
{10023}{}{I know it's hard for you, Miria, but I'm glad you're adjusting well to my crazy life. Let's talk about something else.}
{10024}{}{Good. We'll talk more later, Miria.}
{10025}{}{I'm glad to hear that. We have to get moving now, but we'll talk more later.}
{10026}{}{This is all my fault, and I'll try harder, Miria. Let's talk about something else.}
{10027}{}{I know it's hard sometimes, but you have to believe I'm doing what's best for us both. Let's talk about something else.}
{10028}{}{I'm trying, honey, but all this is new to me too. We'll talk more about this later.}
{10029}{}{I understand. I feel the same things sometimes. We have to go now, but we'll talk more later.}

{10030}{}{I love you, Miria. Sometimes I feel bad that I don't tell you that more often.}
{10031}{}{I just wanted to tell you I love you, that's all. [Kiss her]}
{10032}{}{I love you, honey. You'll always be the only girl for me.}
{10033}{}{[Hold Miria's hand]. Sometimes I wonder if you know how crazy I am about you, honey. I'm so lucky to have a wife like you.}
{10034}{}{Aww, that's sweet. I love you too, honey.}
{10035}{}{[She gets misty-eyed for a moment]. Thank you, sweetie. How do always know just when I need to hear that from you?}
{10036}{}{I'm so lucky to have you. And just for the record, I love YOU more.}
{10037}{}{[She leans in and kisses you] I love you, too.}
{10038}{}{[Miria smiles and softly touches your cheek]}
{10039}{}{Now you've got me all hot and bothered. Wanna go somewhere and fool around?}
{10040}{}{You're the best wife ever. Let's find somewhere quiet, I want to make love to you.}
{10041}{}{Let's talk about something else, Miria.}
{10042}{}{I hate to say this, but we have to go now, Miria.}
{10043}{}{We'll talk more later, Miria. Let's get going.}

{10048}{}{You look really good today, babe. You really are the most beautiful woman in this whole wasteland.}
{10049}{}{Did you do something different with your hair today? You look so beautiful, honey.}
{10050}{}{You look ravishing in that outfit, darling. I didn't think it was possible, but you really do get better looking every day.}
{10051}{}{You're so pretty, Miria. And every woman we meet is SO jealous of you. Is it ever a hassle, being so beautiful?}
{10052}{}{Thank you, sweetie. You always know just the right thing to say to me.}
{10053}{}{Aww. I try so hard to be sexy for you, I'm glad it's working. [She giggles]}
{10054}{}{That's sweet. I'm glad I can still inspire some passion in you.}
{10055}{}{I love it when you sweet-talk me, babe. Thanks, I needed to hear that.}
{10056}{}{You're so good to me. Thank you, honey.}

{10057}{}{I'm so jealous of your nails, babe. How do you keep you cuticles in such good shape?}
{10058}{}{My hair is always so dull and lifeless in this humidity. How do you keep yours so shiny and vibrant?}
{10059}{}{We're both out here running around the same wasteland, but my skin is like sandpaper while yours is always as soft as silk. What's your secret?}
{10060}{}{My feet are all cracked and dry from running around in sand and toxic goo all day, but yours are always so smooth and healthy-looking. Do you put some kind of lotion or something on them?}
{10061}{}{We can be out here stomping around the desert for days, fighting for our lives in 110 degree heat, but you always smell so good. Is it some kind of herbal perfume you use?}
{10062}{}{I was looking at one of those Cat's Paw magazines and saw that before the Apocalypse many of our female ancestors scraped all the hair from their legs and under their arms. Should we try that? Should we just use a knife, or try some kind of adhesive to pull it off?}
{10063}{}{I'm so stressed, honey. On top of that, we're usually too busy staying alive to get enough sleep or eat a healthy diet. We're both riding the same brahmin out here, but I've got these nasty dark bags under my eyes and you don't. Do you have any ideas how I can get rid of them?}
{10064}{}{Woah, you look great! What plants do you use to prepare that powdered dye you rub on your cheeks to give them that hale, rosy-red glow?}
{10065}{}{Is that... did you put something on your eyelashes to make them look so dark and lush? How did you apply it so evenly, without any clumping?}

{10066}{}{No, really babe. You are SO fine. Let's go somewhere and make out.}
{10067}{}{You look so enchanting, I can barely concentrate. Let's go somewhere quiet... I've got to have you right now, honey.}
{10068}{}{Let's talk about something else, Miria.}
{10069}{}{I could go on about your beauty all day, Miria, but we have to get going now.}

{10070}{}{Are WE doing okay? Are you happy with our marriage?}
{10071}{}{I'm crazy about you, babe. I think everything's great between us.}
{10072}{}{I love you more than ever, honey. I'm so lucky to be your wife.}
{10073}{}{I've never been happier. You're the best, darling.}
{10074}{}{I don't know, I... suppose we're okay. It's just that you're always so busy, sometimes I get jealous and wish we could spend more time together.}
{10075}{}{Well, marriage is a mixed-bag, sweetheart. Sometimes I just feel so lonely, and wish you'd spend more time with me.}
{10076}{}{I... guess so. We're just always so busy and on the move all the time, and the only friends we have are your friends. I'm sorry, it's selfish, but sometimes I wish I could have you to myself for a while.}
{10077}{}{I love you and I'm happy, but I'm worried about you. You... well... you seem use a lot of drugs, honey. Sometimes you're not yourself. You just seem... a little crazy when you're on that stuff.}
{10078}{}{I wish we had more time together. It seems like you're always busy with something else, and then when we do get a break all you want to do is get wasted on drugs. I'm worried about you, dear.}
{10079}{}{Our marriage is everything I ever wanted, but I'm worried about you. I know those slavers are your friends, but... I mean, they're a really rough bunch, and I don't like the way I feel when we're around them. It just seems like a really dangerous way to make a few extra bucks.}
{10080}{}{Well, I dunno. I guess I sometimes wonder how I fit into your life, honey. You seem like you're always too busy to spend time with me, and then... well, I know you're just trying to provide for us, but I'm not really sure how I feel about your business. It's so brutal, buying and selling people... Oh, I'm just going to be quiet now. [She looks like she's about to cry]}
{10081}{}{Of course I'm happy, honey. It's just... I don't understand some of the decisions you make. Are you sure you know what you're doing, getting in with those gangsters?}
{10082}{}{I don't know, baby. It seems like you just don't have much time for me anymore... especially now that you've gotten us mixed up with those gangs.}
{10083}{}{I know you love me, dear, and I think our marriage is strong. It's just... I worry about you. You seem to stir up a lot of trouble wherever we go, and a lot of people really hate us. I feel safe when I'm with you, but sometimes when you're not around I get scared.}
{10084}{}{Please, baby, don't ask me silly questions like that. [She shivers and cringes, as if she expects you to start beating her] I'm trying so hard, baby. Please just don't get upset with me again.}
{10085}{}{I'm so happy to hear that, Miria. Let's talk about something else.}
{10086}{}{There's nothing more important to me than our marriage, Miria. Let's talk about something else.}
{10087}{}{It makes me feel so good to hear you say that, Miria. We'll talk more later.}

{10088}{}{I'll try harder to be there for you, Miria. Let's talk about something else.}
{10089}{}{I understand how you could feel that way. I'd like to think it all over, so let's go and we'll talk more later.}
{10090}{}{Yeah, well, marriage is a two-way street. Let's go, and you can think about that while we walk.}
{10091}{}{You just don't understand all the pressure I'm under, honey. Let's talk about something else.}
{10092}{}{Well, maybe if you took better care of me I could kick this habit. That's enough talk for now, let's go.}

{10093}{}{Don't worry, honey. I know what I'm doing. We'll talk more later.}
{10095}{}{I don't have time to explain this whole thing to you again, Miria. Let's go.}
{10096}{}{I love you and I'm happy, but I'm worried about you. You spend an awful lot of time playing with those silly Tragic cards, and you're not taking care of things like you should be.}
{10097}{}{I wish we had more time together. It seems like you're always busy with something else, and then when we do get a break all you want to do is play with those stupid Tragic cards. I'm worried about you, dear.}
{10098}{}{It's not just a game, Miria, it's a lifestyle. Anyway, let's talk about something else.}
{10099}{}{Well maybe if you tried harder, I'd pay more attention to you. I don't want to argue with you, so I'm going to go reorganize my card collection now.}

{11000}{}{You spend an hour swapping personal beauty tips with Miria. It's almost as good as sex, and the two of you feel very close afterwards.}
{11001}{}{You spend some time giving your wife oral sex. It's hard to tell whether the look on her face meant she was in agony or in ecstasy. She won't YOU tell which, of course, but you can be sure she's telling everyone ELSE she knows all about it.}
{11002}{}{Miria spends some time giving you oral sex. Although you appreciate that she's trying to do her best, in the end you use your hand to finish yourself off.}
{11003}{}{You spend some time alone with your wife, each of you happily fulfilling your marital obligations to each other.}
{11004}{}{You make passionate love to your wife.}
{11005}{}{Your wife makes passionate love to you.}
{11006}{}{Miria wants to be 'on top' this time, and she works you over thoroughly.}
{11007}{}{You spend some time giving your wife what you hope is pretty good oral sex. Judging by the way she moaned and screamed, she thought it was better than just 'pretty good.'}
{11008}{}{Miria spends some time giving you absolutely amazing oral sex.}
{11009}{}{You spend some time alone with your wife, having sex so sizzling it's probably illegal in some areas.}
{11010}{}{You spend some time alone with your wife engaging in sex that's almost embarrasingly hot for two married people.}
{11011}{}{You and your wife go at it like wild animals, and are both left sweaty and exhausted... but very satisfied.}
{11012}{}{You make love to your wife. It's really good, since the two of you are getting pretty experienced at knowing how to please each other.}

{11020}{}{Was it good for you too, babe?}
{11021}{}{Mmmm. That was great.}
{11022}{}{Mmmm. I needed that.}
{11023}{}{That was pretty good, sweetie.}
{11024}{}{I love being married.}
{11025}{}{You wore me out, honey. I need a nap.}

{11030}{}{I'm sorry, sweetie, but it's that time of the month for me right now. I'm feeling bloated, my boobs are sore, I have a bad headache, and I just don't think I'd be able to get into it right now even if I was feeling fresh. I'm sure you wouldn't want to be with me anyway while I'm like this.}
{11031}{}{It's that time of the month for me, honey, so we'll have to wait until later. I know how you get, though, so let's find somewhere private and I'll take care of you as best I can.}
{11035}{}{I'm not sure what I was thinking, babe. I've got my period right now, too, so I guess we'll both just save up some lust for later. Let's hit the road.}
{11036}{}{Oh yeah, I forgot about that. I guess I can hold off for a few days, so I'll talk to you later.}
{11037}{}{Thanks, honey. Let's go find that privacy...}
{11038}{}{Err, let's wait until we can both enjoy ourselves. Anyway, I'm not really in the mood anymore after hearing about your period, so I'll talk to you later.}

{11050}{}{I love you and I'm happy, but I'm worried about you. You... well... you drink an awful lot, honey. It's starting to affect your judgement, and it seems like you're not taking care of yourself. I'd be happier if you tried to spend more time sober.}
{11051}{}{I wish we had more time together. It seems like you're always busy with something else, and then when we do get a break all you want to do is get drunk. I'm worried about you, dear.}
{11052}{}{I see. You criticize my life, you're not happy... but you sure don't mind spending the money I bring in for us, right? Let's talk about something else before I lose my temper.}
{11053}{}{I can't deal with your bullshit right now, Miria. Let's go, before I decide to smack you.}
{11054}{}{What, I'm not good enough for you now? Let's talk about something else before I lose my temper.}

{11200}{}{We're in this thing together, Miria. What are your hopes for our future?}
{11210}{}{Let's just try to get through all the things that need to be done right now before we worry about the future.}
{11211}{}{I don't know. I'm starting to think maybe I'd like to go back to Modoc someday. I mean, of course, with you. Absolutely. [She might be frowning, but perhaps her expression just means she's got some food stuck between her teeth]}
{11212}{}{I want to settle down. I want a family. But as chaotic as our lives are, how can I hope to make plans with you about those things?}
{11213}{}{I've got my hands full right now just trying to keep your wounds bandaged and your clothes patched up. We'll worry about the future later.}
{11214}{}{Let's just try to get through today rather than worry about tomorrow.}
{11215}{}{I don't know. Why worry about that right now? We're young, we're in love, and nothing else matters to me. Can't we think about all that serious stuff later?}

{11220}{}{I miss Modoc, honey. All my family and friends are there, and I think it would be a fine place for us to set up a home and raise a tribe-full of children. We could get our own farm, and my family could teach you the cattle business so you can support us. Just think how peaceful it would be, dear. You could run the farm, and every fall you could satisfy your taste for adventure by driving the cattle to Redding or Vault City. Of course I'll be waaay too busy with all the babies we're going to have, but once they're older we could still travel from time to time. You know, maybe take a vacation and go somewhere romantic once in a while?}
{11221}{}{Do you ever miss your tribal life? I don't know, the idea of a simple life like that is sort of growing on me. I can see us in a modest teepee, with our babies playing all around. Plus, we wouldn't have to lug around all my outfits and shoes if my whole wardrobe consisted of a loincloth. [She flashes you a flirty smile] You could hunt and fish for our food, and I could start a garden to satisfy my green thumb. Who knows, maybe one of our kids could even grow up to be the next chief of the clan?}
{11222}{}{I never thought I'd say this, but the idea of living in a big town has sort of been growing on me.  We could get a nice big house in New Reno, with plenty of rooms for all the babies we're going to have. I'm sure you could find work doing something you like in a town that big, and I'd keep busy running our household. Just think, you could come home from work, and I'd have dinner waiting, and then when we put the kids to bed we could hire a babysitter and go out for a night on the town whenever we want.}
{11223}{}{I never thought I'd say this, but the idea of living in a big town has sort of been growing on me. We could get a nice big house in NCR, with plenty of rooms for all the babies we're going to have. I'm sure you could find work doing something you like in a town that big, and I could tend to our children and keep our household running smoothly. Just think, you could come home from work, and I'd have dinner waiting, and then when we put the kids to bed we could hire a babysitter and go out for a night on the town whenever we want.}
{11224}{}{What do you think about moving into Vault 13? I mean, it is your ancestral home and all, so you have as good a claim to be there as anybody else... Those big vault doors would make me feel safe, and if we need things it's not too far to run to NCR for all the modern amenities. Plus there's plenty of space in that big vault, and plenty of rooms for all the babies we're going to have to play and grow up in a safe environment.}
{11225}{}{  And since you've made friends with those deathclaws, so I'm sure they'd be happy to have us there.}
{11226}{}{  And now that all those nasty deathclaws are gone, the place is just sitting empty anyway.}
{11227}{}{I've been thinking lately that maybe we could make a home for ourselves in Redding. There's plenty of work there, so you can do anything you want.  If you need to satisfy your sense of adventure you can run with the caravans, or if you want something steady you can get into the mining business. Maybe you could even run for sheriff in the next election!  We'll get a nice big house on the outskirts of town, and of course I'll be busy raising all the babies we're going to have. I think we could really be happy there, sweetheart.}
{11228}{}{I think I'd like to live in Vault City, dear. It's safe there, and they have all the latest conveniences... I mean, there's just no higher quality of life anywhere else in this wasteland. We can settle down to a nice, quiet life inside the city walls, and I'm sure they'll find something more interesting for a person of your ability to do than working in the List Office. With all medical technology our children could grow up healthy, and they'll have a chance to go to the finest schools around. The more I think about it, the more I'm sure Vault City is the place for us.}
{11229}{}{I've been thinking lately... I never thought I'd say this, but after being out here in this wasteland with you I guess I'm sort of starting to like this lifestyle. And with your adventurous spirt, honey, I know it would just be too hard for you to ever really settle down in one place. We could be like gypsies, roaming the wilds, meeting new people and seeing new places all the time. Once all your business is settled on the coast, maybe we could head east and see what's over the mountains?}
{11330}{}{I guess you can take the girl out the country, honey, but you'll never take the country out of this girl. I'd like to see us find a nice patch of ground somewhere and build a homestead we can call our own. You can work the land, and I can raise all the babies we're going to have. I want lots of babies! We can do our part to tame this wasteland and make it a better place, and when we get old and grey all our kids and grandkids will help take care of us.}
{11335}{}{I want you to be happy, Miria, and I'm going to give your plan a lot of thought. Let's talk about something else, though.}
{11336}{}{I want to give your ideas some serious thought, Miria, so we'll talk more later. Let's hit the road.}
{11340}{}{I miss Modoc, babe, and I think it would be a fine place for us to make our home.  We could start our own brahmin farm... all my family and friends are there to help us get started.  Plus, it's a peaceful place where we can raise all the babies we're going to have.  Oh honey, I want babies so much!  We'll think of something... I mean if nothing else, lots of merchants pass through Modoc and I'm sure we can pick a smart, handsome guy from time to time to make you preggers.  That would be perfect, because then we'd probably never have to see him again after he left town. What? Well of course you're going to have all our babies, sweetie!  I mean I already know the cattle business, so I'll be busy with that and running our farm to support us while you keep our household and be our kids' mom. I think I want you to have six babies, three boys and three girls.  Just think how wonderful it will be, babe!}
{11341}{}{I want kids soooo much, honey, but let's face it... we could swim in a Vat all day and neither one of us is ever going to have the equipment to knock the other one up.  Maybe we could move to the Den? We could help run the orhphanage there! I mean, even though we can't have our own we'd be able to be around kids all the time, plus it's not too strenous a journey to Arroyo or Modoc for us to visit our families once in a while.}
{11342}{}{I kind of like the sound of the tribal lifestyle you had when you were younger, babe. Maybe we could settle down in Arroyo? But I'm worried... would they understand our relationship? I'm not sure they'd take a positive view of two women making it on our own, without some macho guy to protect us. I guess you know more about it than I do, though, so if you think we could make it work then I'm all for it. And after all, you are the 'Chosen One.' If anybody hassles us you can just tell them to mind their own business, or else kick their ass or something.}
{11343}{}{I never thought I'd say this being a farm girl and all, but I think maybe we should settle down in a bigger town. Maybe New Reno? We can be a little more anonymous in a place with a lot of people like that, and everyone probably won't be so quick to judge us for our lifestyle. You know, I mean.. us being two women with no man around, and all that. Plus we're going to have LOTS of babies, so in a big town we can probably find a decent guy with good genes to sire them who we won't have to run into every day after he's done his part.  I think we could make that work, honey.}
{11344}{}{I never thought I'd say this being a farm girl and all, but I think maybe we should settle down in a bigger town. Maybe NCR? We can be a little more anonymous in a place with a lot of people like that, and everyone probably won't be so quick to judge us for our lifestyle. You know, I mean.. us being two women with no man around, and all that. Plus we're going to have LOTS of babies, so in a big town we can probably find a decent guy with good genes to sire them who we won't have to run into every day after he's done his part.  I think we could make that work, honey.}
{11345}{}{What do you think about moving into your ancestral home, Vault 13? I have a good feeling about the community springing up around there. Since you made friends with all those deathclaws I'm sure they'd be happy to have us, and the people there seem pretty laid back... they probably won't hassle us at all about, you know, being two girls who are married to each other. Plus if we got bored, NCR is close by so you can take me out for a night on the town sometimes. I'd feel safe there, honey, and I think we could be really happy.}
{11346}{}{What do you think about moving into your ancestral home, Vault 13? I mean, now that all those deathclaws are gone the place is just sitting empty, and you've got as good a claim to it as anyone else. Plus I'd feel safe behind those big vault doors, and if we ever need anything NCR isn't too far away. And with all the ranching around there, I could get into the cattle business to support us. Maybe we could even use some of the space in the vault to start an orphanage! I think that would be great, honey. If we can't have kids of our own, we can still help make this wasteland a better place by providing a warm home to needy children with no parents of their own.}
{11347}{}{I've been thinking lately that maybe we could make a home for ourselves in Redding. I mean, I already know all about the cattle business, so we could start a ranch just outside of town and I could support us while you stay home and raise all the babies we're going to have! I can't wait to have a big family with lots of kids... I'm thinking like seven or eight precious little ones. Well, I mean, I'll be busy with the business, so of course you'll bear all our children. I don't know, maybe I might have one, but I mean... we can't both stay at home nursing babies all day! And with all those strapping young miners drifting in and out of town all the time, it'll be no problem for us to find a guy with decent genes to get you pregnant... like every two years or so... who won't stick around to bother us after he does his part. Don't worry, I've got it all worked out. It'll be wonderful, babe!}
{11348}{}{I want babies, honey, but let's face it... we just don't have what it takes to make that happen on our own. That's why I'm thinking we could move to Vault City. It's safe there, the quality of life inside the walls is the highest in the wasteland, and best of all... we won't need a man to father our children! We can sign up for the pregnancy cycles together and let science do the rest! Wouldn't that be too cool, if we each had a baby at the same time? Even more importantly, our kids will have a peaceful place to grow up and they'll get the best and most modern education available anywhere. All the pieces fit, babe. I think Vault City is the key to our future.}
{11349}{}{I've been thinking lately... I never thought I'd say this, but after being out here in this wasteland with you I guess I'm sort of starting to like this lifestyle. And with your adventurous spirt, honey, I know it would just be too hard for you to ever really settle down in one place. We could be like gypsies, roaming the wilds, meeting new people and seeing new places all the time. Once all your business is settled on the coast, maybe we could head east and see what's over the mountains?}
{11355}{}{Your happiness is more important to me than anything, babe, and I'll do my best to make your dreams come true. Let's talk about something else.}
{11356}{}{Miria, what would I ever do without you? It's a solid plan, and I'm sure that together we can make it happen. We'll work more on your idea later.}
{11357}{}{So, you're saying... you want me barefoot and pregnant for the next ten or fifteen years? Well... as long as you promise you'll still love me when my boobs are sagging down to around my ankles, it sounds like pure heaven to me. Let's talk about something else, though.}
{11358}{}{Hmm. So you'll be out and about all day bringing home the bacon while I'll be scrubbing floors, washing clothes, and changing out a few dozen soiled swaddling-cloths from sunrise on? Then you'll come home from work, I'll have dinner ready, and after I put the kids to bed you'll tell me all about your tough day while I change into a sexy outfit for you? We'll talk more about this later, Miria.}

{11370}{}{Things are pretty crazy right now, but I promise it will all get better soon. Let's talk about something else.}
{11371}{}{I feel the same way most of the time, Miria. Let's talk about something else.}
{11372}{}{I know what you mean sometimes.  Let's talk about something else.}

{11375}{}{Someday we'll look back at these hard times and laugh. We'll talk more later.}
{11376}{}{Sure, things are hectic right now. I'm going to take care of everything, though... you'll see. Let's go, and we'll talk more later.}
{11377}{}{Well, I'm sure if we work together we can get through this thing, Miria. We'll talk more later.}

{11380}{}{I don't need this bullshit from you right now, Miria. Let's talk about something else.}
{11381}{}{I'm trying, and maybe someday you'll appreciate that. Let's talk about something else.}
{11382}{}{Well, it's no picnic from where I'm standing either. Let's talk about something else.}

{11385}{}{You know, honey, sometimes being married to you sounded a lot better in the brochure. Let's go before I lose my patience with you.}
{11386}{}{Well, maybe if you'd help me more instead of whining all the time we could get ahead faster in this wasteland. I'll talk to you later.}
{11387}{}{No matter what I do it's never enough for you, is it? I don't even want to talk to you when you're like this.}

{11388}{}{Your happiness is important to me, Miria. Let's talk about something else.}

After you've pasted the dialogue lines into a text file, simply save it with the name mcmiria.msg and use the new file to replace the existing one (called mcmiria.msg) found in your Fallout2\data\Text\English\Dialogue folder (after making a backup of your original file, of course).

That's it! With all this new dialogue, I think you'll find that Miria is one of the most well-developed characters in the entire game.

Part 3: A Few Loose Ends

We've given Miria the ability to level up and improve her skills, a new script adding advanced functionality for her, and a new dialogue file to make conversation with her much more interesting. One final aspect of modding Miria (or making any new npc) is to consider how she interacts with other existing characters in the game (apart from the player-character). There are two questions we should ask ourselves at this point:

1) Are any other characters in the game already programmed to interact with Miria, and if so will the changes we have made to her cause any problems with those interactions?

2) Would we like to add new interactions for Miria with other characters in the game?

The Trouble with Trappers

In regard to the first question, there are several characters already programmed to interact with Miria--for example Billy in the Den, the Corsican Brothers, and the various slavers in places like the Den and Vault City. Most of the scripts for these characters won't be affected by the changes we've made to Miria, but there's at least one case where our new mod will cause an existing script to break--the trappers found in random encounters throughout the northern half of the world map. If the player-character has doesn't have enough money and asks a trapper about buying some gecko pelts, the trapper may offer to give the player some pelts in exchange for sexual favors from Miria.

In the original game it's not possible to ask Miria to wait anywhere; if the player is currently married to her, then she will be in the player's party at all times. The way the trapper scripts handle dealing with Miria rest on this assumption, resulting in a bug due to our mod--if Miria is waiting in NCR all the way across the map and the player meets a trapper up north, the trapper will still offer to trade sex with Miria for some gecko pelts, and the game will report that the trapper goes off into the woods with Miria for a few minutes (despite that fact that she's not around).

To fix this situation we need to make a few small changes to the trapper script. In your Fallout2\data\Scripts folder, find the file called ectrappr.int and decompile it with your script compiler/decompiler (you'll want to make a backup of the original first, of course). Open the resulting decompiled script file (which will be called ectrappr.ssl) in a plain text editor. What we want to do is change any check of whether the player is married to a check instead of whether Miria is currently present in the player's party (while we're at it, we'll also do the same for Davin in case we want to mod him someday).

The first change is found in procedure talk_p_proc in ectrappr.ssl. Replace the text in that procedure with the following (just copy what's here, and paste it over the existing talk_p_proc):

procedure talk_p_proc
begin
if (op_local_var(4) == 0) then
begin
op_start_gdialog(509, op_self_obj(), 4, -1, -1);
maybe_start_dialog();
call Node001();
maybe_close_dialog();
maybe_op_end_gdialog();
op_set_local_var(4, 1);
end
else
call Node008();
if (playerSoldSex) then
begin
playerSoldSex := 0;
if ((op_global_var(6) == 1) and (op_party_member_obj(16777380) != 0)) then
op_poison(op_party_member_obj(16777380), 30);
else if ((op_global_var(6) == 2) and (op_party_member_obj(16777379) != 0)) then
op_poison(op_party_member_obj(16777379), 30);
else
op_poison(op_dude_obj(), 30);
call Node006();
end
end

The next change we need to make is found in procedure Node005 of ectrappr.ssl. Change what's currently there so it looks like the following:

procedure Node005
begin
if ((op_global_var(6) == 1) and (op_party_member_obj(16777380) != 0)) then
else if ((op_global_var(6) == 2) and (op_party_member_obj(16777379) != 0)) then
else
op_giq_option(4, 509, 121, @Node006a, 50);
op_giq_option(4, 509, 122, @Node999, 50);
end

The next change is found in procedure Node006 of ectrappr.ssl. Note that what we're basically doing in all these changes is modifying the checks of global variable 6 (which track whether the player is married) into checks about whether Miria (whose critter pid is 16777380) is actually present in the party.

procedure Node006
begin
op_set_local_var(8, 1);
if ((op_global_var(6) == 1) and (op_party_member_obj(16777380) != 0)) then
op_display_msg(op_msg_string(509, 123));
else if ((op_global_var(6) == 2) and (op_party_member_obj(16777379) != 0)) then
op_display_msg(op_msg_string(509, 124));
else
op_display_msg(op_msg_string(509, 125));
end

The final change we need to make is in procedure Node006a of ectrappr.ssl. Change what's currently there so it looks like the following:

procedure Node006a
begin
playerSoldSex := 1;
if ((op_party_member_obj(16777380) != 0) or (op_party_member_obj(16777379) != 0)) then
op_debug_msg("you are married.");
else
begin
op_set_global_var(194, op_global_var(194) + (((((op_get_critter_stat(op_dude_obj(), 3) * 50) + (op_get_critter_stat(op_dude_obj(), 2) * 25) + (op_get_critter_stat(op_dude_obj(), 5) * 13) + (op_get_critter_stat(op_dude_obj(), 0) * 12)) / 100) + (op_has_trait(0, op_dude_obj(), 94) * 2) + op_has_trait(2, op_dude_obj(), 13) + (((op_global_var(194) >= 100) or (op_global_var(232) > 0)) * 2 * (op_dude_obj() == op_dude_obj()))) * 1));
if (op_global_var(358) >= 9) then
op_set_global_var(589, 1);
if (((((op_get_critter_stat(op_dude_obj(), 3) * 50) + (op_get_critter_stat(op_dude_obj(), 2) * 25) + (op_get_critter_stat(op_dude_obj(), 5) * 13) + (op_get_critter_stat(op_dude_obj(), 0) * 12)) / 100) + (op_has_trait(0, op_dude_obj(), 94) * 2) + op_has_trait(2, op_dude_obj(), 13) + (((op_global_var(194) >= 100) or (op_global_var(232) > 0)) * 2 * (op_dude_obj() == op_dude_obj()))) >= 9) then
op_set_global_var(588, 1);
if (op_global_var(590) == 1) then
op_set_global_var(590, 0);
op_set_global_var(358, op_global_var(358) + 1);
end
call Node999();
end

That it! Save ectrappr.ssl, and use your script compiler to recompile it into a new ectrappr.int file. Place the new ectrappr.int in your Fallout2\data\Scripts folder.

Further Customizations

In regard to the other question we asked above--whether or not we would like to add brand new interactions between Miria and other characters in the game--why not answer this for yourself and, using what you've (hopefully) learned from this article, make it happen the way you want in your game? Here are just a few sample ideas of additional depth you could build into Miria's character:

--In an unmodded game, the player-character can divorce Miria by talking to Father Tully in New Reno. The way this currently works, Miria's script is destroyed and replaced with a simple script called ncexspou.int. One could instead modify Father Tully's and Miria's existing scripts to allow for new interaction with Miria after divorcing her, possibly opening up new storylines. For example, perhaps Miria is looking for a good lawyer to sue the Chosen One for alimony--or perhaps she's so upset at being divorced and left on a New Reno curb that she's taken out a contract on the Chosen One with one of the local gangs. Perhaps she falls on hard times and is now working the streets or has become a prisoner at the Stables; if the player-character has a sentimental side, he may decide he was hasty in divorcing Miria and have to complete some quests to get her back. Perhaps she tries to make her way back to Modoc, and is captured by slavers--or maybe she ends up in San Francisco as a new recruiter for the Hubologist cult. You could implement any number of new additions to the game just from the single starting point of changing the way "divorce" works for the player-character and Miria.

--Perhaps Miria gets very jealous if the player-character cheats on her with anyone else, such as Angela/Leslie Bishop or the numerous other potential partners found around the game world. Or perhaps Miria has a secret love herself somewhere in the wasteland, a competitor for the Chosen One's affections?

--Perhaps Miria has news for the Chosen One: he's going to be a father! One could simulate a nine-month period of time during which Miria is pregnant (or perhaps she just insists on going home to Modoc during this time, as it's too dangerous to roam the wastelands). At the end of this time, Miria would present the Chosen One with his new son or daughter. Such an idea would likely require creating some new artwork (at the absolute minimum, some sort of "baby" critter) which would take some effort, but the idea of a Chosen One with a wife AND kids to look out for could take the game into completely uncharted new territory.

--If you're not that ambitious but would just like some more scripting practice, one thing you could do with the script I've presented in this mod is to convert the global variables I used into local variables. While I used global variables because I plan to expand the mod to include some other characters in the future, the drawback of this approach is that since the mod requires changes to vault13.gam one has to start a brand new game to use it (and do quite a bit of playing to Modoc before it can be tested). If Miria's script only used local variables, one could make changes to it anytime and get them into the game simply by revisiting Modoc for the first time.