Jump to content
Sign in to follow this  

TheKian's Geneforge Modding Tutorial

Recommended Posts

Posted (edited)

Part 2 link.

Useful information:

Ability and stat ID list


Welcome to my Geneforge modding tutorial. In this, we will be focusing on modding Geneforge 5, but the same principles underlying this apply to the entire series. Despite the minor differences between the definitions files and scripts of older and newer games, you can still apply this modding knowledge to older games (especially Geneforge 4, which is nearly identical to Geneforge 5 in terms of design and mechanics).


Zone Script Editing:
In each game's scripts folder, a zone has two separate scripts: the zone script and the dialog script. For example, the first zone in Geneforge 5, the Pacification Fields, has two zone scripts: z0pacific.txt and z0pacificdlg.txt. The first one holds data on the zone itself. This includes such things as event keys, such as cutscenes and mob states, as well as definitions for 'special' locations (for example, areas where dialog is triggered when you enter them) and the text that shows up above creatures' heads and above the text box at the bottom of the screen. Let's take a look at some parts of z0pacific.txt.


This indicates the beginning of the script. Without this, the script will not load properly.

variables; short crime_tolerance = 5;  short last_abil;  short i;  short roamer_warn = 0; short cutscene = 0;  short kludge_count = 0; 

This defines variables for local zone data. This includes how much you can steal before you get in trouble (crime_tolerance) as well as various variables for zone status. 'short' is a variant of number, technically a 16-bit integer, ranging from about -33000 to about 33000.

beginstate INIT_STATE;

Body defines the actual content of the zone script. The INIT_STATE defines how the zone behaves when first created, as player interactions can change it. Inside the zone are such things as:

set_name(38,"Crazed Roamer");

These set data on creatures by their universal ID in the game. This can only be determined by experimentation with modified scripts in-game. In order, they set creature 37 to be level 3, set creature 38 to be named "Crazed Roamer", set its aggression to '7' (likely a state of hostility with lower awareness) and its max health to 120. You will also note that each line is terminated with a semicolon. This is important.

if (get_sdf(1,6) > 0) {         make_zone_hostile();         }

This causes the zone to be hostile if a given SDF (a stuff done flag, which stores universal data across all zones) is true.


This sets the crime tolerance to be what was previously defined.


This finishes defining the state.

beginstate EXIT_STATE; break;

This defines the exit state, which is empty in this zone.

beginstate START_STATE;

This defines the start state. In this section are the tutorial guides from the beginning of the game, i.e. gathering your weapons and armor.

This section checks whether the flag for having equipped an item (ID 61) has been set and whether it is equipped. If so, the flag is set (so it cannot constantly repeat) and the map tells you to search for the armor in the storeroom.

if ((get_flag(0,7) == 0) && (has_item_equip(61))) {         
    set_terrain_string_range("Now that you have a weapon, search the locker in the back of the storeroom. Click on a locker, box, or other container to open it.",3);         

When the zone has been sufficiently completed, that is, when these conditions are met, the zone is set to have been cleared. In this case, it checks to see if the zone has not already been cleared and if a given flag is set. Take note also of the //, which comments out a line. In this file, lines are split by tabs, so only the // clear zone? is commented out. Comments do not impact the script at all.

// clear zone? 
if ((zone_clear(ME) == FALSE) && (get_flag(0,25) > 0)) {
	print_str_color("Now that this door is open, you can pass this area freely.",2);

This part checks to see if your crime level exceeeds the tolerance of the zone (and hence you could make an extremely crime-tolerant zone by raising crime tolerance to absurd levels) and, if it does, causes the zone to be hostile. In this case, you will notice that an SDF is also being checked. This checks whether you just automatically die, as happens when you anger the zone before being able to leave the Greyghost mountains.

  if ((get_crime_level() >= crime_tolerance) && (get_sdf(1,6) == 0)) {
  if ((gf(1,6) > 0) && (gf(2,1) < 2))

This performs a check on a random (get_ran) and, if it is an acceptable value, makes a creature (in this case the artila in a side room) hiss.

    if (get_ran(1,0,100) < 10)

Here, the actions in the final cutscene occur. If the cutscene has not yet occurred (gf(0,1) == 0), it checks to see whether creature 50 (the vlish) is dead (char_ok(50) == FALSE) or (the characters || mean a logical OR, while && means AND) its health is below one half, it starts a cutscene, spawning Rawal and moving him around before finally murdering everything.




if (gf(0,1) == 0) {
	if (((char_ok(50) == FALSE) || (get_health(50) < get_max_health(50) / 2)) && (party_near_nav(5,15))) {
        if (cutscene == 0) {
        	cutscene = 1;
} else if (cutscene == 1) {
	cutscene = 2;
    kludge_count = 0;
} else if (cutscene == 2) {
    kludge_count = kludge_count + 1;
    if ((kludge_count >= 8) || (cutscene_can_proceed())) {
    	kludge_count = 0;
        cutscene = 3;
} else if (cutscene == 3) {
	cutscene = 4;
} else if (cutscene == 4) {
	cutscene = 5;
} else if (cutscene == 5) {
// kludgy emergency stuff. had errors where this scene broke, think is
// fixed, but taking extra steps to keep it safe
    if (char_ok(59) == FALSE)
    cutscene = 6;
} else if (cutscene == 6) {
// kludgy emergency stuff
    if (char_ok(59) == FALSE)
        cutscene = 9;
} else if (cutscene == 9) {
    if ((char_ok(59) == FALSE) || ((dist_to_nav_point(59,5) <= 5) && (cutscene_can_proceed()))) {
        cutscene = 10;
} else if (cutscene == 10) {
	cutscene = 11;
    if ((cutscene == 11) && (char_ok(50) == FALSE) && (num_chars_in_group(4) == 0)) {
    	cutscene = 16;
} else if (cutscene == 11) {
	cutscene = 12;
} else if (cutscene == 12) {
	give_char_text_bubble(59,"I absorb you!");
    cutscene = 13;
} else if (cutscene == 13) {
	cutscene = 14;
    give_char_text_bubble(59,"I absorb you!");
} else if (cutscene == 14) {
    kludge_count = kludge_count + 1;
    if ((kludge_count >= 6) || (cutscene_can_proceed())) {
    	cutscene = 15;
        damage_char(1004,1000 + get_ran(1,0,200),2);
        damage_char(50,1000 + get_ran(1,0,200),2);
} else if (cutscene == 15) {
	if ((kludge_count >= 6) || (cutscene_can_proceed()))
    	cutscene = 16;
    if ((cutscene == 16) && (num_chars_in_group(0) == 1)) {
    	cutscene = 24;
} else if (cutscene == 16) {
	cutscene = 17;
} else if (cutscene == 17) {
    cutscene = 18;
} else if (cutscene == 18) {
	cutscene = 19;
} else if (cutscene == 19) {
	kludge_count = kludge_count + 1;
    if ((kludge_count >= 8) || (cutscene_can_proceed())) {
    	cutscene = 20;
        i = 0;
        while (i < 8) {
        	if ((char_ok(i)) && (pc_num() != i)) {
                damage_char(i,1000 + get_ran(1,0,200),2);
            i = i + 1;
} else if (cutscene == 20) {
	if ((kludge_count >= 8) || (cutscene_can_proceed()))
    	cutscene = 24;
} else if (cutscene == 24) {
	cutscene = 25;
} else if (cutscene == 25) {
    kludge_count = kludge_count + 1;
    if ((kludge_count >= 8) || (cutscene_can_proceed())) {
        cutscene = 26;
} else if (cutscene == 26) {
	cutscene = 27;         
} else if (cutscene == 27) {
	cutscene = 28;
} else if (cutscene == 28) {
    give_char_text_bubble(59,"On to the next mess ...");
    if ((char_ok(59) == FALSE) || (dist_to_zone_loc(59,12,59) <= 1) || (cutscene_can_proceed())) {
        cutscene = 29;
} else if (cutscene == 29) {
	cutscene = 30;





The INIT_STATE finishes with another break.

At the end of the file, a number of states are defined. Here, interactions with certain objects are defined, as well as extra tutorial information for the player.


beginstate 10;     if (gf(0,1) == 0)     set_terrain_string_range("Get comfortable with moving your character around. You can also select a character by drawing a box around it. Move the cursor onto the terrain, hold the mouse button down, and move the cursor to make the selection box.",7); break; beginstate 11;     activate_hint(5); break; beginstate 12;     if ((gf(0,7) > 0) && (gf(0,25) == 0)) {         sf(0,25,1);         give_object_message(26,103);         give_object_message(27,103);         }     break; beginstate 13;     if (gf(0,11) == 0) {         sf(0,11,1);         if (gf(0,2) == 0) {             sf(0,11,2);             begin_talk_mode(57);             }                      } break; beginstate 14;     if (gf(0,14) == 0) {         sf(0,14,1);         if (gf(0,2) == 0) {             sf(0,14,2);             begin_talk_mode(86);             }                      } break; beginstate 15;     clear_hints();     if (gf(0,15) == 0) {         if ((num_chars_in_group(0) > 1) && (gf(0,2) > 0)) {             sf(0,15,1);             }             else sf(0,15,2);         } break; beginstate 16;     if (gf(0,1) == 0)         set_terrain_string_range("This massive door blocks the way to the research warrens. It is sealed. You can't open it from this side.",3); break; beginstate 17;     set_terrain_string_range("The sign says - RESEARCH WARREN CORE.",3); break; beginstate 18;     activate_hint(11); break; beginstate 19;     if ((gf(0,20) == 0) && (char_ok(38)) && (gf(0,1) == 0) && (gf(0,21) == 0)) {         sf(0,20,1);         begin_talk_mode(125);         } break; beginstate 20;     if ((char_ok(38)) && (roamer_warn == 0)) {         roamer_warn = 1;         begin_talk_mode(9);         } break; beginstate 21;     roamer_warn = 1; break; beginstate 22;     if (gf(0,23) == 0) {         sf(0,23,1);         set_terrain_string_range("One useful tip: When you hold down the Tab key, you will see labels for all of the buttons (as well as other useful information). Try it out.",3);         } break; beginstate 23;     if ((char_ok(38)) && (get_attitude(38) < 10) && (gf(0,21) == 0)) {         print_str_color("When you get close to the rogue roamer, it starts to notice you.",2);         set_attitude(38,10);         } break; beginstate 24;     sf(1,21,1); break; //    print_str(""); //    set_terrain_string_range(".",3); //    set_terrain_string_range("The sign says - .",3);


Dialogue Scripts:

The dialogue script, z0pacificdlg.txt, is much more readable. It starts in a similar way.



Dialogue is split up into a set of talk nodes, each of which is defined by begintalknode;. There is a limit to the number of these you can have, although I'm not entirely sure how many are possible in total (per zone), but I believe you can have at least 200 per zone. Let's take a look at the first talk node.

begintalknode 1;
    state = -1;
    nextstate = 180;
    condition = get_sdf(0,5) == 0;
    question = "special";
    text1 = "As you stumble through the barracks, your head clears. A tiny bit.";
    text2 = "It looks like you have been living cramped in here with a dozen serviles, the short, humble servant race of the Shapers. It is peculiar. Why would a human be left to live in squalor with them?";
    text3 = "Also, your clothes are unusual. They seem like the outfit of someone in authority, perhaps a soldier or a Shaper. They are ill-fitting and torn, though. And in need of a wash.";    
    text4 = "It looks like you have been living cramped in here with a dozen serviles, the short, humble servant race of the Shapers. Since you are a servile yourself, that seems like it would make sense.";
    text5 = "And yet, it doesn't feel right. The Shapers keep their serviles ignorant and terrified of authority. Somehow, you know that you deserve better than to be living in this squalor.";
    text6 = "The sounds of chaos and panic coming from outside are showing no signs of ending. You start to look around for something you can use to defend yourself.";
    action = SET_SDF 0 5 1;
    code =
        if (creature_type(pc_num()) == 46) {
            else {

The state is, in a way, the address of the talk node. The nextstate value indicates the state of the next node in the 'series'. A state of -1 or nextstate of -1 indicates, respectively, that the talk node is the first in a conversation or the last. In this case, we have a modified dialogue script where the nextstate points to my Geneforge 5 character editor for testing purposes. Consequently, anything with state = 180 will show up as a conversation option in the list here. 


Note: In this scripting language (which appears to basically just be C++), the comparison to see if something is equal is ==. A single = is used to set a value, e.g. short value = 1. Condition indicates whether the talk node can be reached. If it's an option in conversation, condition will determine whether the node will show up in the list of responses. 'Question' indicates the text of the option in the conversation list. when a talk node starts as the result of - for example - talking to a creature or object, the question is named "special". In a dialog list, the question would be whatever the player says or does, e.g. "Continue.", "Nevermind.", "Did that creation just say yanny or laurel?", etc.


There follows a list of text items. Each is printed out in the dialog box, one after another. You can safely have--at most--8 text options. However, I would advise sticking to a maximum of 8. The lines of text of a few important characteristics. One, and this is very important, the length of the 'string' (that is, a section of text) cannot exceed 256 characters. If you attempt to do this, the dialog script will break. Secondly, as the string is enclosed in quotes, if you want to have quotes inside the text itself, you need to put underscores. That is, if you wanted to print out "Hail and well met," the cow said., the associated string would be "_Hail and well met,_ the cow said." Finally, the quotes enclosing the string are not optional. They indicate its beginning and end.


The action can do a few different things. For the most part, you'll probably want no action. However, when you want the conversation to terminate on this option, you will want to set action = END_TALK;. You should also set state to -1 for this. You can also, as this conversation does, set an SDF. You can do literally the exact same thing in the code section, except with multiple stuff done flags, so I personally do not see any reason to use this. Take a look at the various dialogue scripts to find what various other ones do.


The final section is the (optional!) code block. In this, you can do all the coolest things in a conversation. In this case, there are two functions being used. rs(number) removes a string with the appropriate number inside it. For example, rs(2) removes text2. In this case, it is being used to display different strings for serviles versus every other class. The other function is sf, which sets a flag (gf, for reference, gets the value of a flag). In this case, flag 97 0 is being set to a value of 100. There are various other things you can do here, including but not limited to:

Give items with reward_give(item id number);
Give special items with set_spec_item(special item id, number);
Give the party XP with award_party_xp(amount,level of xp); (if you want the XP to scale with the PC's level, use get_level(pc_num()) for the 'level of xp' parameter).
Alter the PC's stats with alter_stat(stat id, amount to increase);


In this last case, the PC's stats include not only attributes and skills, but also spell and creation levels and resistances. A partial list of the different stat IDs is:




0: Strength
1: Dexterity
2: Intelligence
3: Endurance

4: Melee Weapons
5: Missile Weapons
6: Quick Action
7: Parry 

9: Battle Magic
10: Mental Magic
11: Blessing Magic
12: Spellcraft

15: Fire Shaping
16: Battle Shaping
17: Magic Shaping
18: Healing Craft

20: Leadership
21: Mechanics
22: Luck

40-49: Battle Magic Spells
50-59: Mental Magic Spells
60-69: Blessing Magic Spells
70-79: Healing Craft Spells

80-84: Fire Creations
85-89: Battle Creations
90-94: Magic Creations
95: Ornk



The code block is terminated by a break statement. Talk nodes without code do NOT have break statements.


This concludes the script editing portion of the tutorial. Stay tuned for the definitions tutorial, where we will learn how to modify items, spells, and creations.

Edited by TheKian
Added useful information

Share this post

Link to post
Share on other sites
Posted (edited)

Could you perhaps link the other scripting thread we had a couple of years ago when I was making the Warrior Mod? There was good stuff there.


Something that one should keep in mind about the states: There can be only 8 visible answers. You can have as many "state 180" as you like, but they should either show up with different conditions (like a flag from a quest being at a value etc) or only the first 8 will show up.


Another hidden limit, aside of the 256 letters per paragraph, is the number of texts. Again, you can't have more than 8 text paragraphs in the same state. If you use a picture, like the tutorial pictures use, these may take up some of your possible text paragraphs.


A third and important limit, is the size of the file. You can't have a text file that is more than a certain number of kb. About 117-118 kb. So if you start adding new creations and items in the "gf5itemschars.txt" keep in mind that the game may crush quite soon.  

Edited by alhoon

Share this post

Link to post
Share on other sites
Posted (edited)


When compared to the previous two kinds of scripts, the item, spell, and creature definitions are most similar to the structure of dialogue scripts. Let's take a look at gf5itemschars.txt. This is one of the two definitions scripts you may want to edit in Geneforge. The third one--gf5floorster.txt--involves terrain definitions that you should not change. However, it also contains the definitions for graphic templates, so if you want to do custom graphics work, you may want to take a look.

Here is the beginning of gf5itemschars.txt. This defines creatures (in the first part of the file) and items (in the latter part of the file).

begindefinecreature 9;
// base creature
// This slot stores the base unedited creature.
// Used for importation.
    cr_size = 128;
    cr_default_script = "mobbasic";
    cr_default_aggression = 12;
    cr_statistic 0 = 1;
    cr_statistic 1 = 1;
    cr_statistic 2 = 1;
    cr_statistic 3 = 1;

The first line defines the beginning of the definition file. The first creature defined is creature 9 (later creatures start from 0, which is the Shaper), the default creature important. You will notice a few modifiers in here. cr_size, or creature size, of course, indicates its size. I believe it specifically defines the size of collision for the creature.  cr_default_script is the default script the creature follows for actions. All mob scripts can be found in the creature folder. The default script here, "mobbasic", tells the creature to attack any nearby enemy and then return to its original position. It also provides the default conversation text of "You make a bit of small talk...". cr_default_aggression indicates the default hostility of the creature. I am not entirely certain what all of the values mean, but I believe that, in this case, it is neutral or friendly. The final four lines define the creature's stats, as defined in the previous section of the tutorial. 0-3 are, of course, the basic attributes of the creature: its strength, dexterity, intelligence, and endurance are all set to 1.


The next definition is creature 0, the base for the Shaper.

begindefinecreature 0;
    cr_name = "Shaper";
    cr_graphic_template = 110;
    cr_max_health = 20;
    cr_max_energy = 20;
    cr_max_essence = 10;
    cr_regen_rate = 12;
    cr_energy_regen_rate = 12;
    cr_base_level = 1;
    cr_sound_when_slain = 127;
    cr_default_courage = 100;
    cr_resistances 0 = 40;
    cr_resistances 1 = 50;
    cr_resistances 2 = 50;
    cr_resistances 6 = 50;
    cr_resistances 7 = 70;
    // These are all of the main character's combat abils.
    // Abilities used in town are handled in hardcode
    cr_abil_num 0 = 0;
 // punch
    //cr_abil_level 0 = 1;
    cr_abil_step_of_launch 0 = 8;
    cr_abil_anim_in_reverse 0 = 1;
    cr_abil_num 1 = 3;
      cr_abil_level 1 = 1;
    cr_abil_step_of_launch 1 = 8;
    cr_abil_anim_in_reverse 1 = 1;

You will notice a number of additional qualities here. For the most part, they are fairly obvious. However, there are a few things to consider. The health, energy, and essence all scale with level and (in the case of health) endurance or (in the case of energy/essence) intelligence. This can result in things being very complicated when trying to change these values. The regeneration rate (cr_regen_rate) only applies to NPC instances of Shapers - the player himself will not regenerate. cr_default_courage indicates, I believe, something's resistance to becoming terrified as a result of combat (not as a result of mental magic). I believe that, in this case, 100 default courage means Shapers will never become fearful in combat. There are also new stat options here, the cr_resistances. I am not entirely certain what each resistance ID represents, but these stats can cover creature resistances to all kinds of damage, as well as mental effects. The Shaper, you may notice, has unusually high resistances. There are also two abilities defined. The first one, cr_abil_num 0, is set to 0, which is a basic melee attack. In this case, it is the Shaper's punch. The second ability, cr_abil_num 1, is set to 3, the basic firebolt spell. The associated values for these set the level of damage on the ability and the animation used.


You will also notice that the Shaper does not have the cr_size attribute of the previous creature. This is because all attributes of the previous entry, unless something is imported, are carried over to the next entry. As a result, something defined after the Shaper that did not import creature 9 would share its characteristics with a Shaper, except for those things directly changed in the new entry. This can make things convenient or problematic, depending on what you are trying to do.


There are two other kinds of creature attributes of which to be aware. The first is cr_color_adjust. This is what causes creatures to be colored differently, like fyoras versus cryoras, roamers versus pyroamers, battle alphas versus battle betas and so on. The exact correspondence of each value to each other value is not known, but you can determine how it changes graphics from the places it is used elsewhere in the fire. The second kind of attribute to consider are the cr_start_item ones. cr_start_item 0/1 = <item id> defines the item ID of the creature's default drops. Meanwhile, cr_start_item_chance 0/1 = <percent> gives the chance for the creature to drop the given item when it dies. Zone data can be altered to give creatures different drops, but these are the defaults for a creature of a given type.

The item definition format is quite similar to that of creatures. Let's take a look at a couple examples.

begindefineitem 0;
// basic import item, clears values
    it_graphic_template = 50;

All this has is the first graphic template, corresponding to G1500.bmp in the Graphics A folder. You can import it to clear the values inherited from previous entries, however. Take, for example, the flawed crystal and lovely crystal entries.

begindefineitem 5;
    import = 0;
    it_name = "Flawed Crystal";
    it_graphic_sheet = 3;
    it_which_icon_ground = 14;
    it_which_icon_inven = 15;
    it_variety = 11;
    it_weight = 20;
    it_charges = 1;
    it_value = 20;
begindefineitem 6;
    it_name = "Lovely Crystal";
    it_value = 40;
    it_graphic_coloradj = 2;

The flawed crystal (item ID 5) begins with "import = 0". This clears all the values it would otherwise have inherited from the previous item, the gemstone. After it, you can see a few more item attributes .
it_graphic_sheet defines which row (the first row being 0) of the graphic template the item is.
it_which_icon_ground and it_which_icon_inven define which tile in the row (the first tile also being 0) the item displays as, respectively, while on the ground and while in the player's inventory.
it_variety defines what kind of item it is.
it_weight defines the weight of the item--weight is in units of 0.1 pounds, meaning that this crystal would be 2 pounds.
it_charges defines the default number of the item there is. This should generally be 1, unless you're using wands or batons. In the case of those, by setting the charges to 0, it gains an unlimited number of charges.
it_value defines the value of an item. You always sell an item for one-fourth of its value. In this case, you could sell the crystal for 5 gold pieces.

The second crystal has far fewer entries. This is because it inherits most of its values from the previous item. However, it changes 3 properties: its name, its value, and its color adjustment. Color adjustment works the same for items as for creatures. Keep in mind, of course, that even though a color adjustment may look like it does one thing, it may do another. In this case, you have a green item being made blue--the same color adjustment on an item whose original graphic is orange or red, like some clothing, will likely result in an entirely different change.


Now, let's take a look at a few of the more interesting different kinds of items. We shall start with armor, in this case the quicksilver plate. 

begindefineitem 55;
    import = 41;
    it_name = "Quicksilver Plate";
    it_value = 3000;
    it_stats_to_affect 2 = 201;
    it_stats_addition 2 = 1;
    it_stats_to_affect 3 = 1;
    it_stats_addition 3 = 1;
    it_graphic_coloradj = 1024;

This item imports item 41, the shaped breastplate. As it does not have its own armor defined (with it_protection), it inherits the it_protection = 34 from the shaped breastplate, as well as its weight. However, it has two stat modifications. The first is set to (it_stats_to_affect <number of modification in item> = <stat ID>) ID 201, which corresponds to action points. The second is set to 1, which corresponds to dexterity. Both of these have a bonus of one, which is set by it_stats_addition <number of modification in item> = <amount to increase>. It also has color adjustment 1024, which I believe corresponds to a paler color.


Let's also look at the first charm defined, the lucky charm.

begindefineitem 321;
    // imported for charms
    import = 0;
    it_name = "Lucky Charm";
    it_graphic_template = 51;
    it_graphic_sheet = 0;
    it_which_icon_ground = 0;
     it_which_icon_inven = 0;
    it_variety = 11;
    it_value = 600;
    it_weight = 10;
    it_abil_work_in_pack = 1;
    it_stats_to_affect 0 = 22;
    it_stats_addition 0 = 1;

The charm imports the default item, clearing out the information from previous items. Its graphic template is set to 51, which corresponds to G1510.bmp in Graphics A. You will notice its graphic sheet and icon are both 0, which means that its graphic is the first tile in the first row of the image.

The most important thing here is it_abil_work_in_pack = 1, which is what makes something a charm. This attribute causes whatever changes the charm makes to apply to you whenever it is in your inventory. In this case, as the stat it is set to affect is 22 (luck) and the value of the change it set to 1, whenever it is in your pack, you will get +1 luck.


We will also take a look at the default potion import, the healing pod.

begindefineitem 220;
// imported for all pods
    import = 0;
    it_name = "Healing Pod";
    it_graphic_template = 50;
    it_graphic_sheet = 3;
    it_which_icon_ground = 2;
    it_which_icon_inven = 3;
    it_variety = 9;
    it_charges = 1;
    it_weight = 1;
    it_ability = 201;
    it_value = 70;
    it_level = 10;
    it_extra_description = 2; 

This has something new: an ability for the item. The item also has a level, set with it_level, which determines the potency of the ability. Depending on the ability, the level may increase healing, damage, etc. As each healing pod gives a single charge, its charge setting is also 1. One last new thing you will notice is "it_extra_description". This adds an additional (hardcoded) description to the item. In this case, it describes the healing pod as a gourd containing magical goop. The item variety set by it_variety determines the primary description.

Compare this to the ice-infused crystal.

begindefineitem 119;
    it_name = "Ice-Infused Crystal";
    it_variety = 9;
    it_graphic_template = 51;
    it_graphic_sheet = 5;
    it_which_icon_ground = 2;
    it_which_icon_inven = 3;
    it_ability = 32;
    it_charges = 1;
    it_weight = 2;
    it_value = 25;
    it_extra_description = 15;
    it_level = 12;
    it_graphic_coloradj = 1;

Similarly, this has an ability and level, although a different one from the healing pod. It also has a different 'extra description'.


Now, let's take a look at a vastly different item with an ability: items.

begindefineitem 60;
    import = 0;
    it_name = "Stick";
    it_graphic_sheet = 0;
    it_which_icon_ground = 2;
    it_which_icon_inven = 3;
    it_variety = 3;
    it_ability = 0;
    it_level = 1;
    it_value = 0;
    it_weight = 20;
begindefineitem 61;
    // imported for blades
    it_name = "Dagger";
    it_graphic_template = 51;
    it_graphic_sheet = 4;
    it_which_icon_ground = 0;
    it_which_icon_inven = 1;
    it_ability = 2;
    it_level = 2;
    it_value = 20;
    it_weight = 40;
    it_can_augment = 1;

The two items have different abilities, each corresponding to different melee attack abilities. The dagger, of course, has a higher level than the stick. The dagger also has something new: it_can_augment. This determines whether an item may be enchanted. In many cases, you will (of course) not want this to be enabled, like with potions, charms, and the like. It can also be used to limit the power of certain already powerful items by disabling augments for them. Remember, of course, that if enchanting is enabled for an item, any item after it will also be able to be enchanted until either a non-enchantable item is imported or until it_can_augment is set to 0.


Finally, let's take a look at batons.

begindefineitem 90;
    import = 0;
    it_name = "Thorn Baton";
    it_graphic_sheet = 3;
    it_which_icon_ground = 4;
     it_which_icon_inven = 5;
    it_variety = 3;
    it_ability = 50;
    it_level = 2;
    it_value = 24;
    it_weight = 25;
    it_charges = 6;
    it_extra_description = 11;

Most of this should look fairly familiar by now. I would, however, draw your attention to two things. One, the charges on the item are set to 6, i.e. the ammo of the item. I do not know whether increasing this will make the ammo clips restore more, but I do know that setting it to less than 1 should make it have unlimited ammo and not need to be reloaded (the primary basis of one of the currently extant Geneforge mods, artifact batons). Secondly, take careful note of the ability here. This can, in fact, be set to any ability: you could make a baton (or wand) which shoots purifying rain or kill.


Finally, let's take a look at the abilities. For the most part, you won't want to create new abilities from scratch. Rather, you should alter or copy an existing ability and use it for your purposes. So, we will just look at essence orbs and firebolt, as well as a custom ability we can derive from them.

begindefineability 3;
    // Basic missile -> radiate cloud for importation
    ab_name = "Firebolt";
    ab_abil_type = 2;
    ab_graphic_type = 0;
    ab_missile_short_range = 1;
    ab_missile_type_fired = 0;
    ab_impact_sfx_effect = -1;
    ab_random_effect_shift = 0;
         ab_stat_ability_linked_to = 40;
      ab_stat_for_ability_bonus = 9;
         ab_damage_type = 2;
    ab_effect_type = 0;
    ab_effect_base = 4;
    ab_effect_per_level = 3;
         ab_ability_sound = 191;
    ab_impact_sound = 9;
    ab_energy_cost = 4;
    ab_essence_cost = 0;
    ab_accuracy_adjust = 60;     

begindefineability 5;
    import = 3;
    ab_name = "Essence Orbs";
    ab_missile_type_fired = 5;
         ab_stat_ability_linked_to = 45; 
    ab_stat_for_ability_bonus = 9;
    ab_damage_type = 1;
    ab_effect_base = 20;
    ab_effect_per_level = 5;
         ab_num_of_missiles = 3;
    ab_ability_sound = 107;
    ab_impact_sound = 117;
    ab_energy_cost = 75;
    ab_essence_cost = 4; 

The ability name here does not change the name of the spell in the magic selection menu. However, it does change its name in items (e.g. crystals) and in the text box at the bottom of the screen when you are targeting enemies.
ab_impact_sfx_effect indicates the effect (e.g. a puff of fire) played on impact. -1 indicates no SFX should be played.
ab_stat_for_ability_bonus indicates what ability makes the spell more powerful. In this case, it is battle magic, but you could make spells that are even leadership-based or mechanics-based.
ab_effect_type indicates what kind of special effect (e.g. acid, lightning aura) the attack should have.
ab_damage_type indicates what kind of damage (e.g. fire, energy) the attack should do.
ab_effect_base indicates the base power of the spell, and ab_effect_per_level indicates how much a higher spell level should improve it.
ab_energy_cost and ab_essence_cost determine ability energy and essence requirements.
ab_accuracy_adjust does something to mess with the (base?) accuracy of an ability.
ab_missile_type_fired, for missile attacks, determines what kind of missile is fired (i.e. appearance).
ab_num_of_missiles determines the number of missiles that can be launched (i.e. essence orbs firing multiple orbs).

Fun fact: burning spray has this.

ab_num_of_missiles = 3;
 // ###this working?

Poor Jeff.


ab_ability_sound and ab_impact_sound indicate the sound played when the spell is launched and when it hits, respectively.Here is an example spell you can construct: my OP plasma lance spell from the Geneforge 4 Artifact Weapons mod.

begindefineability 8;
    import = 3;
    ab_stat_ability_linked_to = 45; 
    ab_stat_for_ability_bonus = 9;

    ab_damage_type = 1;
    ab_ability_sound = 107;
    ab_impact_sound = 117;

    ab_energy_cost = 100;
    ab_essence_cost = 5;

    ab_abil_type = 3;
    ab_missile_type_fired = 7;

    ab_name = "Plasma Lances";
    ab_damage_type = 1;
    ab_effect_base = 40;
    ab_effect_per_level = 15;    
    ab_num_of_missiles = 3;
    ab_accuracy_adjust = 100;

This creates a powerful attack that scales very well with level and has good base accuracy. It uses the pretty graphics of diamond spray and the base provided by diamond spray and essence orbs.


This concludes the item, creature, and ability section of the tutorial. Stay tuned for whenever the Geneforge Modding Suite is finished in the next several years.

Edited by TheKian

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this