Zumbs' Blog

The truth may be out there, but lies are inside your head

Archive for the ‘FOMM’ Category

FOMM and FOMODs for Dummies 7: Load Order Magicks

Posted by Zumbs on November 13, 2009

FOMM and FOMODs for Dummies

  1. Installing Mods
  2. Making FOMODS
  3. Basic FOMOD Scripting I
  4. Basic FOMOD Scripting II
  5. Working with Forms I
  6. Working with Forms II
  7. Load Order Magicks

In a earlier tutorial, installation of compatibility patches were controlled by the mod user. It would, however, be nice if we could detect if the player had a mod installed, so we could set a good default. If a compatibility patch is to be installed, we may also want to manipulate the load order so that it is correct, instead of pushing the responsibility onto the shoulders of the mod user.

Simple manipulations

If your mod requires that the plugins are placed in a particular order w.r.t. each other, but can be loaded anywhere, the easiest way to control the load order is to use InstallFromFOMOD in the correct order. So if your mods must have the order

foobar.esm
foobar.esp
foobar-addon1.esp
foobar-addon2.esp
foobar-addon3.esp

simply install them in the correct order

InstallFromFOMOD("foobar.esm");
InstallFromFOMOD("foobar.esp");
InstallFromFOMOD("foobar-addon1.esp");
InstallFromFOMOD("foobar-addon2.esp");
InstallFromFOMOD("foobar-addon3.esp");

FOMM load order functions

FOMM comes with a number of functions to manipulate load order:

public static void SetPluginActivation(string pluginName, bool activate);

This function allows you to activate or deactivate a particular plugin.

public static string[] GetActivePlugins();
public static string[] GetAllPlugins();

These functions returns an in-order string array of either all active plugins or all plugins in the data folder.

public static void SetLoadOrder(int[] plugins);
public static void SetLoadOrder(int[] plugins, int position);

These two functions can be used to set the load order. The first one forces a load order, and the other moves the mods at the index positions specified in plugins to the position. There are, however, a number of cavities. Both functions work on the full list of mods (GetAllPlugins), and they use indexes. So, to use them, you would need to call GetAllPlugins(), search the list for the mods that you wish to move and record their index, and then perform the move.

Usually, we want to ensure that a particular mod is loaded before or after another. As an example, our mod somemod.esp had conflicts with FOOK2. This can be solved with a compatibility patch “somemod-FOOK2-compatibility-patch.esp”. Thus, we would like a load order of the form

somemod.esp
FOOK2 – Main.esp
somemod-FOOK2-compatibility-patch.esp

Detecting plugins

The following function can be used to investigate if a function is active:

public static bool IsPluginActive(String pluginName)
{
    string[] loadOrder = GetActivePlugins();
    for (int i = 0; i < loadOrder.Length; ++i)
    {
        if (loadOrder[i].Equals(pluginName, StringComparison.InvariantCultureIgnoreCase))
             return true;
    }
    return false;
}

This could be used to set a reasonable default value, such as

InstallFookCompatibilityCheckBox.Checked = IsPluginActive("FOOK2 - Main.esp")

Adjusting load order

As noted above, FOMMs default functions for manipulating load order are somewhat clunky to work with. What we want is something like

if(IsPluginActive("fook2 - main.esp"))
{
    PlaceBeforePlugin("FOOK2 - Main.esp", "mod-base.esp");
    PlaceAfterPlugin("FOOK2 - Main.esp", "mod-FOOK2-compatibility-patch.esp");
}

The functions needed, are shown below:

public static int GetPluginIndex(String pluginName)
{
    string[] loadOrder = GetAllPlugins();
    for (int i = 0; i < loadOrder.Length; ++i)
    {
        if (loadOrder[i].Equals(pluginName, StringComparison.InvariantCultureIgnoreCase))
            return i;
    }
    return -1;
}
public static void PlaceAtPlugin(String targetPlugin, String pluginToMove, int offset)
{
    int targetPluginIndex = GetPluginIndex(targetPlugin);
    int pluginToMoveIndex = GetPluginIndex(pluginToMove);
    if (targetPluginIndex != -1 && pluginToMoveIndex != -1)
    {
        int[] pluginIdxArray = { pluginToMoveIndex };
        SetLoadOrder(pluginIdxArray, targetPluginIndex + offset);
    }
}
public static void PlaceAfterPlugin(String targetPlugin, String pluginToMove)
{
    PlaceAtPlugin(targetPlugin, pluginToMove, 1);
}
public static void PlaceBeforePlugin(String targetPlugin, String pluginToMove)
{
    PlaceAtPlugin(targetPlugin, pluginToMove, 0);
}

These functions allow us to place one or more mods at a reasonable place in the load order of the user.

Posted in Fallout 3, Fallout Mod Manager, FOMM, FOMOD, Game Mods | 6 Comments »

FOMM and FOMODs for Dummies 6: Working with Forms II

Posted by Zumbs on November 12, 2009

FOMM and FOMODs for Dummies

  1. Installing Mods
  2. Making FOMODS
  3. Basic FOMOD Scripting I
  4. Basic FOMOD Scripting II
  5. Working with Forms I
  6. Working with Forms II
  7. Load Order Magicks

The previous tutorial showed how to setup a form, apply a background image and add install and cancel buttons. This tutorial will show how to add and use checkboxes and radiobuttons to allow the user to customize the installation form. When you start making your own, I highly recommend that you take the time to draw a sketch of the form you wish to make before you start. The tutorial will end with an example, using the skills learned in this tutorial.

Adding a title

A title will tell the user which mod is being installed. A classic position of a title is in the upper center. Text can be added to the installation form by using a label, declared by

public static Label TitleLabel;

and constructed by

TitleLabel = new Label();
TitleLabel.Text = "My mod name";
TitleLabel.ForeColor = Color.Snow;
TitleLabel.BackColor = Color.Transparent;
TitleLabel.Location = new Point(45, 30);
TitleLabel.TextAlign = ContentAlignment.MiddleCenter;
TitleLabel.AutoSize = true;

It can be placed on the background picture by

BackgroundPicture.Controls.Add(TitleLabel);

You can also set the font of the label, but you have to be careful, as the user may not have all fonts installed. You may want to edit the background picture instead of using a label.

Adding a Checkbox

Checkboxes are used to allow the user to choose one or more of a number of options. This can be used to install an optional addon, such as DLC compatiblity. To make a checkbox it must be declared:

public static CheckBox InstallCustomAddonCheckBox;

and is initialized by:

InstallCustomAddonCheckBox = new CheckBox();
InstallCustomAddonCheckBox.Checked = true;
InstallCustomAddonCheckBox.Location = new Point(5, 102);
InstallCustomAddonCheckBox.Size = new Size(20, 20);

The checkbox starts as being checked. You may want to edit the placement, when you use it. Note, however, that it does not come with an explanatory text. To help the user discover what the checkbox does, you can add a label next to the checkbox. A label is declared by

public static Label InstallCustomAddonLabel;

and initialized for

InstallCustomAddonLabel = new Label();
InstallCustomAddonLabel.Text = "Install custom addon";
InstallCustomAddonLabel.Location = new Point(27, 105);
InstallCustomAddonLabel.AutoSize = true;

Note how the label is placed 22 px to the right and 3 px below the checkbox.

Depending on your background picture, the text may be difficult to read. This can be fixed by placing the options menu on a panel with a custom background color. A panel can be declared by:

public static Panel OptionsPanel;

and initialized and customized by:

OptionsPanel = new Panel();
OptionsPanel.Location = new Point(266, 110);
OptionsPanel.Size = new Size(210, 160);
OptionsPanel.BackColor = Color.WhiteSmoke;
OptionsPanel.BorderStyle = BorderStyle.FixedSingle;

The options panel can be placed on the background picture by:

BackgroundPicture.Controls.Add(OptionsPanel);

The checkbox and label can be placed on the panel by

OptionsPanel.Controls.Add(InstallCustomAddonCheckBox);
OptionsPanel.Controls.Add(InstallCustomAddonLabel);

After the user presses “Install”, you want to check the state of the checkbox – checked or not checked. This can be done by

if (InstallCustomAddonCheckBox.Checked)
{
    // handle custom option
}

Adding a Radiobutton

Radiobuttons are used to allow the user to choose exactly one from a number of options. An example could be which body replacer the user has installed. A radio button can be declared by

public static RadioButton DisableMinigamesRadioButton;

and initialized by

DisableMinigamesRadioButton = new RadioButton();
DisableMinigamesRadioButton.Checked = true;
DisableMinigamesRadioButton.Location = new Point(5, 33);
DisableMinigamesRadioButton.Size = new Size(20, 20);

The radiobutton comes without text, so you have to add a label, like shown above. Please note that only one of the radio buttons should be initialized to being checked. The radio button can be applied to the options panel by

OptionsPanel.Controls.Add(DisableMinigamesRadioButton);

Note, however, that all radio buttons in one panel will be viewed as a group (e.g. be mutually exclusive). To use multiple sets of radio buttons (e.g. choose both male and female body versions), you must place the radio buttons on separate panels. To check which option were chosen, you can use

if (Option1RadioButton.Checked)
{
    // handle option 1
}
else if (Option2RadioButton.Checked)
{
    // handle option 2
}

Other controls

Aside from buttons, radiobuttons and checkboxes, there are a number of other useful controls. ComboBoxes can be used to present the user with a drop-down, where a the user can make a choice. When selecting an option, you can code something to happen, such as showing a picture (take a look at Breezes male body mod for a code example). Check google for form tutorials and have a look at all the crazy options, if you like 🙂

Example

This example uses two checkboxes and one radiobutton set with three radiobuttons. The mod contains the following files

\meshes\mesh.nif
\meshes\mesh1.nif
\meshes\mesh2.nif
mod-base.esp
mod-FOOK2-compatibility-patch.esp
mod-the-pitt-compatibility.esp

Only one of the three meshes can be installed (mutually exclusive), but all three esps can be installed. The total form script is presented below, or can be saved from this odt file (wordpress does not allow one to upload .cs or .txt files).

using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using fomm.Scripting;

class Script : BaseScript
{
    public static bool install;
    public static Form InstallForm;
    public static PictureBox BackgroundPicture;
    public static Panel InstallPanel;
    public static Button InstallButton;
    public static Button CancelInstallButton;
    public static Panel OptionsPanel;
    public static CheckBox InstallFOOK2CompatibilityCheckBox;
    public static Label InstallFOOK2CompatibilityAddonLabel;
    public static CheckBox InstallDLCCompatibilityCheckBox;
    public static Label InstallDLCCompatibilityAddonLabel;
    public static RadioButton MeshDefaultRadioButton;
    public static Label MeshDefaultLabel;
    public static RadioButton Mesh1RadioButton;
    public static Label Mesh1Label;
    public static RadioButton Mesh2RadioButton;
    public static Label Mesh2Label;
    
    public static Image GetImageFromFomod(string filename)
    {
        byte[] data = GetFileFromFomod(filename);
        MemoryStream s = new MemoryStream(data);
        Image img = Image.FromStream(s);
        s.Close();
        return img;
    }
    public static void CreateInstallForm()
    {
        InstallForm = CreateCustomForm();

        // customize install form
        InstallForm.FormBorderStyle = FormBorderStyle.Fixed3D;
        InstallForm.StartPosition = FormStartPosition.CenterScreen;
        InstallForm.Size = new Size(500, 600);
        // place background picture box
        BackgroundPicture = new PictureBox();
        BackgroundPicture.Location = new Point(0, 0);
        BackgroundPicture.Size = new Size(500, 600);
        // load picture file from .fomod and stream into picture box
        BackgroundPicture.Image = GetImageFromFomod("fomod/screenshot.png");
        // add BackgroundPicture to list of controls
        InstallForm.Controls.Add(BackgroundPicture);
        // install button
        InstallButton = new Button();
        InstallButton.Text = "Install";
        InstallButton.BackColor = Color.Silver;
        InstallButton.Location = new Point(5, 540);
        InstallButton.Size = new Size(100, 23);
        // cancel button
        CancelInstallButton = new Button();
        CancelInstallButton.Text = "Cancel";
        CancelInstallButton.BackColor = Color.Silver;
        CancelInstallButton.Location = new Point(105, 540);
        CancelInstallButton.Size = new Size(100, 23);
        // options panel
        OptionsPanel = new Panel();
        OptionsPanel.Location = new Point(100, 300);
        OptionsPanel.Size = new Size(210, 250);
        OptionsPanel.BackColor = Color.WhiteSmoke;
        OptionsPanel.BorderStyle = BorderStyle.FixedSingle;
        // FOOK2 compatibility patch
        InstallFOOK2CompatibilityCheckBox = new CheckBox();
        InstallFOOK2CompatibilityCheckBox.Checked = true;
        InstallFOOK2CompatibilityCheckBox.Location = new Point(5, 5);
        InstallFOOK2CompatibilityCheckBox.Size = new Size(20, 20);
        InstallFOOK2CompatibilityAddonLabel = new Label();
        InstallFOOK2CompatibilityAddonLabel.Text = "Install FOOK2 Compatibility patch";
        InstallFOOK2CompatibilityAddonLabel.Location = new Point(27, 8);
        InstallFOOK2CompatibilityAddonLabel.AutoSize = true;
        // dlc compatibility patch
        InstallDLCCompatibilityCheckBox = new CheckBox();
        InstallDLCCompatibilityCheckBox.Checked = true;
        InstallDLCCompatibilityCheckBox.Location = new Point(5, 38);
        InstallDLCCompatibilityCheckBox.Size = new Size(20, 20);
        InstallDLCCompatibilityAddonLabel = new Label();
        InstallDLCCompatibilityAddonLabel.Text = "Install DLC Compatibility patch";
        InstallDLCCompatibilityAddonLabel.Location = new Point(27, 41);
        InstallDLCCompatibilityAddonLabel.AutoSize = true;
        // radiobutton menu
        MeshDefaultRadioButton = new RadioButton();
        MeshDefaultRadioButton.Checked = true;
        MeshDefaultRadioButton.Location = new Point(5, 71);
        MeshDefaultRadioButton.Size = new Size(20, 20);
        MeshDefaultLabel = new Label();
        MeshDefaultLabel.Text = "Vanilla mesh";
        MeshDefaultLabel.Location = new Point(27, 74);
        MeshDefaultLabel.AutoSize = true;
        Mesh1RadioButton = new RadioButton();
        Mesh1RadioButton.Checked = false;
        Mesh1RadioButton.Location = new Point(5, 104);
        Mesh1RadioButton.Size = new Size(20, 20);
        Mesh1Label = new Label();
        Mesh1Label.Text = "Breeze mesh";
        Mesh1Label.Location = new Point(27, 107);
        Mesh1Label.AutoSize = true;
        Mesh2RadioButton = new RadioButton();
        Mesh2RadioButton.Checked = false;
        Mesh2RadioButton.Location = new Point(5, 137);
        Mesh2RadioButton.Size = new Size(20, 20);
        Mesh2Label = new Label();
        Mesh2Label.Text = "Robert mesh";
        Mesh2Label.Location = new Point(27, 140);
        Mesh2Label.AutoSize = true;

        // build form
        BackgroundPicture.Controls.Add(InstallButton);
        BackgroundPicture.Controls.Add(CancelInstallButton);
        BackgroundPicture.Controls.Add(OptionsPanel);
        OptionsPanel.Controls.Add(InstallFOOK2CompatibilityCheckBox);
        OptionsPanel.Controls.Add(InstallFOOK2CompatibilityAddonLabel);
        OptionsPanel.Controls.Add(InstallDLCCompatibilityCheckBox);
        OptionsPanel.Controls.Add(InstallDLCCompatibilityAddonLabel);
        OptionsPanel.Controls.Add(MeshDefaultRadioButton);
        OptionsPanel.Controls.Add(MeshDefaultLabel);
        OptionsPanel.Controls.Add(Mesh1RadioButton);
        OptionsPanel.Controls.Add(Mesh1Label);
        OptionsPanel.Controls.Add(Mesh2RadioButton);
        OptionsPanel.Controls.Add(Mesh2Label);
        AttachHandlers();
    }
    public static void AttachHandlers()
    {
        //Attach a handler that will fire when the appropriate button is clicked 
        InstallButton.Click += delegate(object sender, EventArgs args)
        {
            install = true;
            InstallForm.Close();
        };
        CancelInstallButton.Click += delegate(object sender, EventArgs args)
        {
            install = false;
            InstallForm.Close();
        };
    }
    public static void PerformCustomInstall()
    {
        if(MeshDefaultRadioButton.Checked)
        {
            InstallFileFromFomod("meshes/mesh.nif");
        }
        else if(Mesh1RadioButton.Checked)
        {
            CopyDataFile("meshes/mesh1.nif", "meshes/mesh.nif");
        }
        else if(Mesh2RadioButton.Checked)
        {
            CopyDataFile("meshes/mesh2.nif", "meshes/mesh.nif");
        }
        InstallFileFromFomod("mod-base.esp");
        SetPluginActivation("mod-base.esp", true);
        if(InstallFOOK2CompatibilityCheckBox.Checked)
        {
            InstallFileFromFomod("mod-FOOK2-compatibility-patch.esp");
            SetPluginActivation("mod-FOOK2-compatibility-patch.esp", true);
        }
        if(InstallDLCCompatibilityCheckBox.Checked)
        {
            InstallFileFromFomod("mod-the-pitt-compatibility.esp");
            SetPluginActivation("mod-the-pitt-compatibility.esp", true);
        }
    }
    public static bool OnActivate()
    {
        CreateInstallForm();
        InstallForm.ShowDialog();
        if(install)
        {
            PerformCustomInstall();
        }
        return install;
    }
}

Posted in Fallout 3, Fallout Mod Manager, FOMM, FOMOD, Game Mods | Leave a Comment »

FOMM and FOMODs for Dummies 5: Working with Forms I

Posted by Zumbs on November 12, 2009

FOMM and FOMODs for Dummies

  1. Installing Mods
  2. Making FOMODS
  3. Basic FOMOD Scripting I
  4. Basic FOMOD Scripting II
  5. Working with Forms I
  6. Working with Forms II
  7. Load Order Magicks

install-formIn a previous tutorial, messageboxes were used to make a simple interface with the user. In some cases, however, you may want to present the user with a lot of choices which makes messageboxes clunky to work with. One alternative it to use forms. An example of an installation form is shown to the right.

This tutorial will try to give an overview of how to make a form yourself. A good way to learn how to script is to look at examples, such as Breeze’s male body replacer, MMM or my own Security Overhaul.

If you have no experience with C#, I recommend that you take a look at a few tutorials to get a grasp of the syntax. I also recommend that you use a development environment like Visual Studio or the free Visual Studio Express Edition instead of FOMMs text editor. An upcomming tutorial will show how to set it up. As shown in this tutorial, Visual Studio also has a GUI interface to make forms. For the classes used, a link to Microsofts documentation at http://msdn.microsoft.com/en-us/library/default.aspx is supplied. Be sure to use the left-hand menu!

Making your first form

Microsofts documentation on Forms can be found here. A form is created by declaring it, and setting it with

public static Form InstallForm;
InstallForm = CreateCustomForm();

Note that you have to use CreateCustomForm() and not new Form() when working with FOMM! The form is shown when you call

InstallForm.ShowDialog();

I favor making a separate function, CreateInstallForm, to make the form. In this case, you would have to make the form a static variable, declared as below

using System;
using System.Windows.Forms;
using fomm.Scripting;

class Script : BaseScript
{
    public static bool install;
    public static Form InstallForm;
    public static void CreateInstallForm()
    {
        InstallForm = CreateCustomForm();
    }
    public static bool OnActivate()
    {
        CreateInstallForm();
        InstallForm.ShowDialog();
        if(install)
        {
            PerformBasicInstall();
        }
        return install;
    }
}

The form doesn’t do anything yet. If you try to activate a mod with such a script, you will get an empty popup. Let us start by customizing the popup. Adding the following to CreateCustomForm() will make a form of size 500 x 600, and it will pop up in the center of the screen.

InstallForm.FormBorderStyle = FormBorderStyle.Fixed3D;
InstallForm.StartPosition = FormStartPosition.CenterScreen;
InstallForm.Size = new Size(500, 600);

The size can be changed, but I recommend not making it larger than 800 x 600. You may want to change the borderstyle once you get buttons added, but for now, use the above settings.

Adding a background image

We can also add a background image. This function by Breeze can be used

public static Image GetImageFromFomod(string filename)
{
    byte[] data = GetFileFromFomod(filename);
    MemoryStream s = new MemoryStream(data);
    Image img = Image.FromStream(s);
    s.Close();
    return img;
}

The function requires that you add two more namespaces:

using System.IO;
using System.Drawing;

We will also need to declare a picture. The declaration below should be placed just below the declaration of the InstallForm.

public static PictureBox BackgroundPicture;

The PictureBox documentation can be found here. The function GetImageFromFomod() can be called from CreateCustomForm()

// place background picture box
BackgroundPicture = new PictureBox();
BackgroundPicture.Location = new Point(0, 0);
BackgroundPicture.Size = new Size(500, 600);

The above script creates a picture box of the same size as the InstallForm and place it at the point (0,0). Most of the stuff you add to the InstallForm will need to be placed at some position. The position is set as a point. The control you add will have its upper left corner at the point. The first number is the x-position of the control, and the second position is the y-position. Unlike most coordinate systems you may know from math, the origin is placed in the upper left corner, and the y-axis points down, as shown below:

position

A picture can be loaded using the function above

// load picture file from .fomod and stream into picture box
BackgroundPicture.Image = GetImageFromFomod("fomod/screenshot.png");

You can use any path, but I recommend placing the picture in the fomod folder for convenience. Now, we need to tell the InstallForm that it should include our picture. This is done by adding the BackgroundPicture to its list of controls:

InstallForm.Controls.Add(BackgroundPicture);

So, the total script is now:

using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using fomm.Scripting;

class Script : BaseScript
{
    public static bool install;
    public static Form InstallForm;
    public static PictureBox BackgroundPicture;

    public static Image GetImageFromFomod(string filename)
    {
        byte[] data = GetFileFromFomod(filename);
        MemoryStream s = new MemoryStream(data);
        Image img = Image.FromStream(s);
        s.Close();
        return img;
    }

    public static void CreateInstallForm()
    {
        InstallForm = CreateCustomForm();

        // customize install form
        InstallForm.FormBorderStyle = FormBorderStyle.Fixed3D;
        InstallForm.StartPosition = FormStartPosition.CenterScreen;
        InstallForm.Size = new Size(500, 600);
        // place background picture box
        BackgroundPicture = new PictureBox();
        BackgroundPicture.Location = new Point(0, 0);
        BackgroundPicture.Size = new Size(500, 600);
        // load picture file from .fomod and stream into picture box
        BackgroundPicture.Image = GetImageFromFomod("fomod/screenshot.png");
        // add BackgroundPicture to list of controls
        InstallForm.Controls.Add(BackgroundPicture);
    }
    public static bool OnActivate()
    {
        CreateInstallForm();
        InstallForm.ShowDialog();
        if(install)
        {
            PerformBasicInstall();
        }
        return install;
    }
}

If you try the script out (and make sure to have a screenshot.png in your fomod folder), a window should pop up, showing the screenshot. Note that the image is not streched to fit the form.

Install and cancel buttons

We need to add some buttons to allow the user to start or cancel the installation of the mod. Before we add them, they must be declared:

public static Button InstallButton;
public static Button CancelInstallButton;

We initialize them in CreateInstallForm()

// install button
InstallButton = new Button();
InstallButton.Text = "Install";
InstallButton.BackColor = Color.Silver;
InstallButton.Location = new Point(5, 540);
InstallButton.Size = new Size(100, 23);
// cancel button
CancelInstallButton = new Button();
CancelInstallButton.Text = "Cancel";
CancelInstallButton.BackColor = Color.Silver;
CancelInstallButton.Location = new Point(105, 540);
CancelInstallButton.Size = new Size(100, 23);

To get them to show, we have to add them to the part of the control that they are to be in front of. In this case, it is the BackgroundPicture:

BackgroundPicture.Controls.Add(InstallButton);
BackgroundPicture.Controls.Add(CancelInstallButton);

If you run the code, the buttons will be added to the lower left corner. Pressing them doesn’t do anything. This is because we haven’t told the form what to do when the buttons are pressed. This is handled by something called EventHandlers. And we need to attach one to each of the buttons. This can be handled by the function AttachHandlers below:

public static void AttachHandlers()
{
    //Attach a handler that will fire when the apply button is clicked 
    InstallButton.Click += delegate(object sender, EventArgs args)
    {
        install = true;
        InstallForm.Close();
    };
    CancelInstallButton.Click += delegate(object sender, EventArgs args)
    {
        install = false;
        InstallForm.Close();
    };
}

This function tells the form what to do when the two buttons are clicked. It is called from CreateInstallForm(). With the buttons, the total script is now:

using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using fomm.Scripting;

class Script : BaseScript
{
    public static bool install;
    public static Form InstallForm;
    public static PictureBox BackgroundPicture;
    public static Panel InstallPanel;
    public static Button InstallButton;
    public static Button CancelInstallButton;
    public static Image GetImageFromFomod(string filename)
    {
        byte[] data = GetFileFromFomod(filename);
        MemoryStream s = new MemoryStream(data);
        Image img = Image.FromStream(s);
        s.Close();
        return img;
    }
    public static void CreateInstallForm()
    {
        InstallForm = CreateCustomForm();

        // customize install form
        InstallForm.FormBorderStyle = FormBorderStyle.Fixed3D;
        InstallForm.StartPosition = FormStartPosition.CenterScreen;
        InstallForm.Size = new Size(500, 600);
        // place background picture box
        BackgroundPicture = new PictureBox();
        BackgroundPicture.Location = new Point(0, 0);
        BackgroundPicture.Size = new Size(500, 600);
        // load picture file from .fomod and stream into picture box
        BackgroundPicture.Image = GetImageFromFomod("fomod/screenshot.png");
        // add BackgroundPicture to list of controls
        InstallForm.Controls.Add(BackgroundPicture);
        // install button
        InstallButton = new Button();
        InstallButton.Text = "Install";
        InstallButton.BackColor = Color.Silver;
        InstallButton.Location = new Point(5, 540);
        InstallButton.Size = new Size(100, 23);
        // cancel button
        CancelInstallButton = new Button();
        CancelInstallButton.Text = "Cancel";
        CancelInstallButton.BackColor = Color.Silver;
        CancelInstallButton.Location = new Point(105, 540);
        CancelInstallButton.Size = new Size(100, 23);
        BackgroundPicture.Controls.Add(InstallButton);
        BackgroundPicture.Controls.Add(CancelInstallButton);
        AttachHandlers();
    }
    public static void AttachHandlers()
    {
        //Attach a handler that will fire when the apply button is clicked 
        InstallButton.Click += delegate(object sender, EventArgs args)
        {
            install = true;
            InstallForm.Close();
        };
        CancelInstallButton.Click += delegate(object sender, EventArgs args)
        {
            install = false;
            InstallForm.Close();
        };
    }
    public static bool OnActivate()
    {
        CreateInstallForm();
        InstallForm.ShowDialog();
        if(install)
        {
            PerformBasicInstall();
        }
        return install;
    }
}

If this script is applied to your mod, a window will open with the background image and two buttons. Pressing either button will close the form. The cancel button will also exit the installation, whereas pressing the install button will run PerformBasicInstall().

The next part of the tutorial will investigate how to create and handle options.

Posted in Fallout 3, Fallout Mod Manager, FOMM, FOMOD, Game Mods | Leave a Comment »

FOMM and FOMODs for Dummies 4: Basic FOMOD Scripting II

Posted by Zumbs on November 8, 2009

FOMM and FOMODs for Dummies

  1. Installing Mods
  2. Making FOMODS
  3. Basic FOMOD Scripting I
  4. Basic FOMOD Scripting II
  5. Working with Forms I
  6. Working with Forms II
  7. Load Order Magicks

In the previous tutorial we had a look at how to validate the users install and manipulate the ini. This tutorial will cover the subject of making a custom install script, overriding FOMMs default install script.

It is assumed that the user has chosen which options to install beforehand.

The first step is to declare a custom install function. This has the advantage of increasing the readability of our install script, which will be handy if we ever have to update the mod. The custom install function can be declared by:

public static void InstallSomeMod()
{
}

Then we must change the line

PerformBasicInstall();

to

InstallSomeMod();

This makes FOMM call our new install script when the mod is activated. It doesn’t do anything yet, though.

Installing a file

To install a specific file from the fomod archive, one can use the InstallFileFromFomod function. It takes the name of the file to install as an argument, such as

InstallFileFromFomod("somemod.esp");
InstallFileFromFomod("textures/sometexture.dds");

An esp can be activated by using SetPluginActivation, like this

SetPluginActivation("somemod.esp", true);

Renaming installation files

Sometimes you want to give the user the choice between multiple files. A classic example is a body replacer, where you want to allow the user to choose between a number of body meshes, ie. muscular/average/skinny. These will often be saved in separate folders in your fomod archive. To install a particular set of meshes, you can use the function CopyDataFile. The function can be used on multiple types of data files, as shown below:

CopyDataFile("meshes/characters/_male/upperbodymale-skinny.nif", "meshes/characters/_male/upperbody.nif");
CopyDataFile("somemod_custom_option.esp", "somemod.esp");

The first argument is the location of the file in the fomod file, the other argument is where you wish to place it in the users data folder.

Example install function

Let us assume that you have a fomod with the following files

/textures/sometexture-option1.dds
/textures/sometexture-option2.dds
/textures/sometexture-option3.dds
somemod.esp
somemod_custom_option.esp

The user can choose between the texture options and the two esps. You asked which options the user wished, and those responses are saved in the variables textureChoice and useCustomOption. The installation can be handled by the function

public static void InstallSomeMod(int textureChoice, bool useCustomOption)
{
    CopyDataFile("/textures/sometexture-option" + textureChoice + ".dds", "/textures/sometexture.dds")
    if (useCustomOption)
    {
        CopyDataFile("somemod_custom_option.esp", "somemod.esp")
    }
    else
    {
        InstallFileFromFomod("somemod.esp")
    }
    SetPluginActivation("somemod.esp", true);
}

The function must be called from the OnActivate function with the user choices as arguments:

InstallSomeMod(textureChoice, useCustomOption)

Posted in Fallout 3, Fallout Mod Manager, FOMM, FOMOD, Game Mods | Leave a Comment »

FOMM and FOMODs for Dummies 3: Basic FOMOD Scripting I

Posted by Zumbs on November 8, 2009

FOMM and FOMODs for Dummies

  1. Installing Mods
  2. Making FOMODS
  3. Basic FOMOD Scripting I
  4. Basic FOMOD Scripting II
  5. Working with Forms I
  6. Working with Forms II
  7. Load Order Magicks

In the previous tutorial, we investigated how to make and work with fomod files. This two part tutorial will show how to make a basic install script. This part focus on how to validate the user’s installation of Fallout 3.

The FOMOD format allows some quite sophisticated install scripts, which can be a great help for mod users (and reduce the number of people complaining that they could not get it to work), and can assist in testing your mod under different configurations.

The scripts must be written in the programming language C#, and can draw on functions from the .NET library. C# is very similar to Java (not JavaScript) and somewhat similar to C++. For the scripts discussed in this tutorial, you will not need to know much about C# or .NET, but if you plan on using some of the more advanced features of the FOMOD install scripts, you may want to check out a few basic tutorials on C#.

The install scripts are placed in the scripts.cs file in the fomod folder, and can be opened and edited by pressing the Edit Script or Create Script button in the Package Manager:
package-manager-create-script

This opens the Script Editor:
script-editor

Aside from the code window, note how the toolbar allow you to save the file and check the syntax. Be sure to check the syntax regularly! If an error is found, the line number and an error message will be shown. Also note that even if the syntax is correct, the script may not do what you intended it to do, so be sure to test your code regularly!

When the user presses the Activate button in the Package Manager, the OnActivate function is run. When this function is done, it returns a value (true or false) to FOMM to indicate if the install were successful or not. Please note that files installed by an unsuccessful install are not automatically removed by the Package Manager.

Checking FOSE version

Your mod may use functionality introduced in a certain FOSE version. In this case, it would be a good idea to check if FOSE is present and have the correct version. If the following script is added to the first line of the OnActivate function, it detects if FOSE is installed with the correct version (1.1b9). If this is the case, installation can proceed, and if not, the installation is stopped and the user is prompted to get the latest version.

Version requiredFose = new Version(0, 1, 1, 9);
if (GetFoseVersion() < requiredFose)
{
    MessageBox("This mod requires FOSE v " + requiredFose + " or higher. You have " + GetFoseVersion() 
        + ". Please update from http://silverlock.org");
    return false;
}

Checking patch version

In some cases your mod works best with a certain version of the game. For instance, in unpatched version of Fallout 3, uninstalling a mod that added a perk to the player would cause a crash on load. This can be done like this:

Version requiredGameVersion = new Version(1, 6);
if (GetFalloutVersion() < requiredGameVersion)
{
    MessageBox("You are using an unpatched version of the game that cause a"
        + " crash on load after uninstalling this mod, unless you remove the perk first. Please patch your game.", "Error");
}

You may also want to allow the user to cancel the installation at this point, which can be performed by this script:

Version requiredGameVersion = new Version(1, 6);
if (GetFalloutVersion() < requiredGameVersion)
{
    DialogResult res = MessageBox("You are using an unpatched version of the game that cause a"
        + " crash on load after uninstalling this mod, unless you remove the perk first. Please patch your game.", 
        "Error", MessageBoxButtons.OKCancel);
    if (res == DialogResult.Cancel)
    {
        return false;
    }
}

Usage of DialogResult requires that you add the line below to the top of the script file:

using System.Windows.Forms;

Editing the .ini

A number of mods need to edit the ini. An example is DarNified UI, where the fonts used by the UI are changed. Many mods rely on having the ini setting bInvalidateOlderFiles set to 1. This can be handled by this piece of code:

if (GetFalloutIniInt("Archive", "bInvalidateOlderFiles") == 0) {
   EditFalloutINI("Archive", "bInvalidateOlderFiles", "1", true);
}

Note how an ini setting is found: The first argument is the ini group (“Archive”), the second is the ini setting itself (“bInvalidateOlderFiles”), and the third is the new value, all in quotation marks. The last argument to EditFalloutINI is an instruction to FOMM telling it to remember the original setting, so it can be restored when the mod is uninstalled. Usually, it is good practice to ask the users permission to change ini settings before doing so.

Pulling it together

The with the options above, our script is now

using System;
using System.Windows.Forms;
using fomm.Scripting;

class Script : BaseScript {
	public static bool OnActivate() {
	    Version requiredFose = new Version(0, 1, 1, 9);
	    if (GetFoseVersion() < requiredFose)
	    {
	        MessageBox("This mod requires FOSE v " + requiredFose + " or higher. You have " 
                    + GetFoseVersion() + ". Please update from http://silverlock.org");
	        return false;
	    }
	    Version requiredGameVersion = new Version(1, 6);
	    if (GetFalloutVersion() < requiredGameVersion)
	    {
	        DialogResult res = MessageBox("You are using an unpatched version of the game that cause a"
                    + " crash on load after uninstalling this mod, unless you remove the perk first. Please patch your game.", 
                    "Error", MessageBoxButtons.OKCancel);
	        if (res == DialogResult.Cancel)
	        {
	            return false;
	        }
	    }
	    DialogResult iniEdit = MessageBox("Do you wish to modify the ini?", "Ini change", MessageBoxButtons.YesNo);
	    if (iniEdit == DialogResult.Yes)
	    {
	        if (GetFalloutIniInt("Archive", "bInvalidateOlderFiles") == 0) {
	           EditFalloutINI("Archive", "bInvalidateOlderFiles", "1", true);
	        }
	    }
	    
        //Install all files from the fomod and activate any esps
        PerformBasicInstall();
		return true;
	}
}

Message boxes are an easy method for the mod author to communicate with the mod user. However, they also have a number of drawbacks, particularly if you wish to give the mod user a number of install options. This difficulty can be overcome by using forms, which is the topic for an upcomming tutorial. First, however, we will look at how to customize install scripts.

Posted in Fallout 3, Fallout Mod Manager, FOMM, FOMOD, Game Mods | Leave a Comment »