Rusty's Guide to Basic Scripting with LUA
What is LUA?
LUA is a scripting language very similiar to C++ or Java. You can find more information about LUA in general at http://www.lua.org
What can LUA be used for in EUO?
The most common use of LUA scripts in EUO is to modify the stats and abilities of monsters. Scripts can also be used to create unique effects, modify map layouts or even generate completely random maps.
In this guide I'm going to cover how to use LUA scripts to make basic modifications to monsters and how to attach those scripts to spawners in MapEd.
Where to start
Assuming you already know how you want to modify your monster, the first thing you need to do is open notepad, or some other similar text editor. I don't recommend using a word processing type program like Word, Works or even Wordpad because they can add extra formatting characters that would mess up the script. Make sure you name the file with the map number and map name in the filename and end the filename with .lua (example: 219 the labyrinth.lua).
Once you have your blank file ready you are ready to start writing your script.
All LUA scripts (for EUO anyway) are grouped in functions. A function is simply a collection of commands to accomplish some purpose. A function can be made to modify a monster to have different stats when a spawner spawns it for example. Here is an example of a function:
function high_hp_and_xp(m) m:set_hp_max(1000) -- This sets the monster's hp to 1000 m.xp_kill = 750 -- This sets the experience gained from killing the monster to 750 end
This function sets the hp of a monster to 1000 and the XP for killing it to 750. The first line of any function must be the word "function" followed by the name of the function. The "(m)" following the function name is required. "m" refers to the monster we are currently modifying. For simple scripts you wont need to change this but it needs to be there.
It is important that your function name is descriptive and unique. I always use the initials of the map I'm working on as the first few letters of the name of every function that I write for a map. For example "tl_make_large" is the function name I used for the function for The Labyrinth that makes the monsters bigger and modifies their stats. See how I added a "tl_" to the beginning of the function name? This helps guarantee that your function names will be unique. If two functions are accidentally given the same name it can cause problems and conflicts.
The "m:set_hp_max(1000)" line of the function executes a command that sets the hp of the monster to 1000. The part of this line after the "--" is a comment. Anything after "--"'s will be ignored. It's always a good idea to put comments into your code. It is very easy to forget what you were trying to do if you write a lengthy script and it makes it easier for other people to understand if they try to read your code.
There are several commands similar to "m:set_hp_max(1000)" that can modify different things. Obviously the 1000 can be changed to be any number you like. There will be a list of most of the commands used to modify monster values at the end of this guide.
The line "m.xp_kill = 750" is a little different than the previous one. It has a little bit different format but does the same thing for XP that "m:set_hp_max(1000)" does for hp. Some things have to be changed like the the hp is changed and others have to be changed like the XP is changed.
The last line of the function is just the word "end" by itself. All functions end this way.
Attaching your function to a spawner in MapEd
Once you have your function written and the file saved you can attach it to a spawner in MapEd. First create the spawner using whatever monster you want to use and left click it to set it's attributes. The last of the attributes of a spawner is a "script" attribute. In here you simply put in the function name of the function you wrote. Leave off the word "function" and do not include the "(m)" at the end of the function name. Be sure to remember to type in any underscores in that are in the function name. Make sure to use the same capitalization as well.
At this point you are done. When you submit your map be sure to include the .lua file with all the other map files. Be sure to mention in your email that you are including a script and briefly explain what it is supposed to do.
More example functions
Here is some more examples of functions to modify monsters.
First a powered up minotaur.
function es_minotaur_warrior(m) m:unlearn_spells() -- This command causes a monster to unlearn all the spells they know. Nothing needs to go in the () m:set_magic_resistance(500) -- Sets the monster's magic resistance to 500 m:set_name("Minotaur Warrior") -- Gives the monster the name Minotaur Warrior m:set_align(ALIGN_EVIL) -- Makes the monster evil aligned (red health bar) ALIGN_GOOD makes monsters good (blue bar) and ALIGN_NEUTRAL makes them neutral (gray bar) m:set_hp_max(1000) -- Sets the monster's hp to 1000 m:set_intel(250) -- sets the monster's int to 250 m:set_dmg_dice(25) -- sets the number of damage dice rolled to 25. m:set_dmg_sides(3) -- sets the number of sides of the damage dice to 3 -- Damage is done in a XdY format where X is the number of dice rolled and Y is the number of sides the dice have. -- The dice and sides only effect damage done from normal melee or non magic ranged attacks. m:set_thaco(75) -- This sets the AS of the monster to 75 m:set_base_ac(40) -- This sets the defense of the monster to 40 m.xp_kill=700 -- This sets the experience gained when you kill the monster to 700 end
Next a more powerful minotaur shaman.
function es_minotaur_acolyte(m) m:unlearn_spells() -- Unlearn all known spells. I'll add some new spells later. m:set_magic_resistance(1000) -- Set the monster's MR to 1000 m:set_name("Minotaur Acolyte") -- Set name to Minotaur Acolyte m:set_align(ALIGN_EVIL) -- Make him evil aligned m:set_hp_max(500) -- set his hp to 500 m:set_intel(1000) -- set his int to 1000 m:set_dmg_dice(15) -- damage dice to 15 m:set_dmg_sides(3) -- damage sides to 3 m:set_thaco(35) -- AS to 35 m:set_base_ac(30) -- Def to 30 m:learn_spell("xmp") -- This teaches the monster the spell XMP m:learn_spell("ivpy") -- This teaches the monster the spell IVPY m.xp_kill=700 -- XP gained from killing the monster to 700 end
Here's a function to make a monster 2x2, double it's hp and damage dice
function es_large_monster(m) m.large = true -- This sets the monster to be a 2x2 monster. xx = m:get_hp_max() -- here I am getting the monster's current hp and putting that value into the variable x. -- Notice that there is a "xx = " before the command and that there is no value in the (). xx = xx * 2 -- This takes the value that is in the variable xx and multiplies it by 2. Then it puts the result back into the variable xx. m:set_hp_max(xx) -- This sets the monster's hit points the the value that is in the variable xx. yy = m:get_dmg_dice() -- get the current number of damage sides and put the value in the variable yy yy = yy * 2 -- multiply the value in yy by 2 and put it back into yy. m:set_dmg_dice(yy) -- set the damage dice to the value in yy. end
Note: In the example above I used 2 variables to hold values by the name of "xx" and "yy". I used these names instead of more descriptive names to to help keep you from confusing the variables with other things that have a similar name. I could have used "hp" instead of "xx" and "dice" instead of "yy" as that would have made the code a little easier to understand. I just wanted to make it clear that you don't have to use "xx" or "yy" for variable names. You can use any word you want as long as it isn't a word that is used by the scripting language. For example you cant use the word "function" or the word "end" as a variable name.
Function commands list
This is a list of some of the different commands used to modify monster attributes. These would be placed between the first line of the function and the "end" at the end of a function.
m:set_name("Text") -- Set name to the text in the quotes m:set_align(ALIGN_???) -- set value in the () to ALIGN_GOOD, ALIGN_NEUTRAL, or ALIGN_EVIL m:set_hp_max(number) -- set his hp to the value in the () m:set_intel(number) -- Set the monster's int to the number in the () m:set_magic_resistance(number) -- Set the monster's MR the the number in the () m:set_dmg_dice(number) -- set damage dice to the number in the () m:set_dmg_sides(number) -- set damage sides to the number in the () m:set_thaco(number) -- Set As to the number in the () m:set_base_ac(number) -- Set defense to the number in the () m:mk_boss() -- Makes the monster a boss. No values are needed in the () m.code = 0xcode -- Changes the avatar of a monster. Get the avatar codes from MapEd and put them exactly where the word code is. m.xp_kill = number -- Sets the XP gained from killing the monster to whatever the number is m.treasure = 0xcode -- This sets the treasure of a monster. A treasure code is 5 digits long. Examples: e966a, 83345, b23e6 -- This code uses hexadecimal digits (0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f) -- The first digit determines the drop quality. It ranges from 0 (worst) to f (best) -- The second digit determines artifact drop chance. Ranges 0 - f -- The third digit determines amount of apothecary type item drops. Ranges 0 - f -- I'm not sure what the fourth digit does. Set it to 1 or greater. -- The fifth digit determines amount of gold to give. Ranges 0 - f m.speed = number -- Sets the monster's speed to the number. Speeds typically range from 1000 (slow) to 200 (very fast) m.immune_to_glassing=true -- This makes the monster immune to glass weapons. m.large=true -- This makes the monster have a 2x2 avatar m.immobile=true -- This makes the monster unable to move but it can still attack. Like sandtraps or reapers. -- Setting this to false would make normally immobile monsters able to move normally m.flying=true -- This makes the monster able to fly. You can set this one to false as well to prevent flying. m:unlearn_spells() -- Unlearn all known spells. Good for making sure the monster you are modifying doesn't cast anything you don't want them to. m:learn_spell("spell letters") -- This teaches the monster the spell in the quotes. Use the spell letters not the full name. -- some monster spells are different than player spells. -- VM for monsters is "vm2" -- IP for monsters is "ip2" -- OG for monsters is "og2" -- A good rule to go by is to only use spells for monsters that you know some monsters already use. -- Some spells don't work well or at all for monsters.
Here are some commands you can use to get the current values of different monster attributes. The purpose of this is so you can use those values in calculation in your function if you need to. I'm using the variable xx in the following examples, you should use a more descriptive variable name in your script. You can see how these relate to the commands above.
xx = m:get_hp_max() xx = m:get_intel() xx = m:get_magic_resistance() xx = m:get_dmg_dice() xx = m:get_dmg_sides() xx = m:get_thaco() xx = m:get_ac() xx = m.xp_kill xx = m.speed
Special codes for the m.code function
The avatar code called by the m.code function is a 7 digit hexadecimal number. Basic avatars use only 3 digits of the code, e.g. 0x0000297 or in short 0x297 would display a cow avatar. The other 4 digits are used for dyes, split avatars and glow effects, respectively. The 7 digit code is split into three groups assigned to different function, e.g. 0xFDDDMMM. MMM is again the 3 digit code for basic avatars. DDD has two functions. On the one hand side, this part of the code is used for dyes using hexadecimal triple colour codes, or on the other hand, to create a split avatar, e.g. half cow half chicken. F has several function intertwined with the DDD code.
F = 0 -- DDD will be interpreted as a dye F = 2 -- DDD will be interpreted as a dye and the avatar will glow F = 4 -- DDD will be interpreted as secondary avatar code enabling split avatars
If F is set to 4 the avatar's lower part is defined by the MMM code and the upper part by the DDD code.