MMExtension v2.2 HelpBack

Hover your mouse over empty space on the left side of the page to see the table of contents.

Contents


General Information

You will need MMArchive. mm8leveleditor and MM Map Viewer may also come in handy.
Extract all *.txt files from appropriate LOD archive: icons.lod in MM6, events.lod in MM7, EnglishT.lod in MM8. You will need them.
Easiest thing to start with is editing text tables with TxtEdit. In addition to *.txt files that you've extracted from LOD archives MMExtension will create some tables in Data\Tables folder on first launch. You can change any values in them and add new lines to many of them.

Lua is a simple, yet powerful scripting language. You can read about it here, here and here. MMExtension exposes all standard Lua and LuaJIT libraries.
I used to use SciTE to edit Lua scripts before I switched to Sublime Text. Here are some of my settings for SciTE:
Open SciTEGlobal.properties.

Find and set up these settings:
tabsize=2
indent.size=2
braces.autoclose=0

Find user.shortcuts=\
delete line with Alt+X
add line: Ctrl+Shift+Z|IDM_REDO|\
add line: Ctrl+R|IDM_REPLACE|\

All scripts are located in Scripts directory. Subfolders determine when scripts get loaded and unloaded:
 Subfolder  Description
Core MMExtension core scripts. Don't put your scripts here.
General These scripts are loaded before the game starts and are never unloaded.
Global These scripts are loaded when a new game is started or a saved game is loaded and are unloaded when user exits to main menu or loads another game. This is a good place for most of your scripts that don't belong to specific maps. Quests scripts in particular.
Localization These scripts and text files are loaded on game start just before "General" scripts and can be reloaded with ReloadLocalization() function. They should be used for mods localization.
Maps These scripts correspond to maps. For example, scripts named oute3.lua and some_name.oute3.lua would be loaded when oute3.odm map (New Sorpigal) is loaded and unloaded when it is left.
Modules These scripts aren't loaded automatically. Instead they can be loaded with require function.
Structs These scripts are intended for structs definitions. These things are low-level, so I won't describe them yet. If you find some interesting address with ArtMoney or disassembler, contact me.
You can create your own subfolders. Scripts in them won't be loaded automatically and won't be unloaded either.

The word 'unload' means removing all events of a script. As a consequence of global and maps scripts being unloaded and then loaded again, you can change them and test changes by simply reloading a saved game. No need to exit Might and Magic for this.

Debug console is a convenient way to quickly test things. Press Ctrl+F1 to open it. You can write any script here. For example, dump(Party[0].Stats) would output first player's stats.
Press Ctrl+Enter to execute a script.
Press Ctrl+E to repeat the last script.
Press Esc to cancel debug console.

Variables used by your scripts can be of 4 types:
Local variables, declared with the word local in Lua. They can be used in the place where they were declared (i.e. function, script or code block) and aren't stored is saved games.
Global variables. They can be accessed from anywhere, but aren't stored in saved games.
Variables in vars table. They can be accessed from anywhere and are stored in savegames.
Variables in mapvars table. They belong to current map. When a new map is entered the appropriate variables table is set as mapvars table. They are stored in savegames. When a map is refilled, new mapvars table is created, but the old one is accessible at this moment as Map.Refilled.

Hello world!

Let's first use the debug console. In the game press Ctrl+F1 and paste this script:
Message("Hello world!")
Press Ctrl+Enter to execute your welcome script.

To make your first game script create out01.lua file (or oute3.lua for MM6) in Scripts\Maps directory and write this text there:
MessageBox("Hello world!")
This script will show a system message box each time you enter the first map.

To show a native MM message you can use a script like this:
Game.NeedRedraw = true -- I remember having problems with minimap not getting drawn
Sleep(1) -- sleep for 1 tick to let it be drawn
Message("Hello world!")
The reason for the first two lines of code is that Might and Magic doesn't support showing simple messages when the map is just loaded.

Decompiled Scripts

Original Might and Magic scripts are stored in binary format in files with extension .evt. MMExtension can decompile these scripts. Download decompiled scripts here.
Decompiled scripts come in the form of Lua scripts and also pseudo code that directly corresponds to binary format.
Just so you know, here are the differences between pseudo code commands and real MMExtension commands:
1) "evt." isn't written in them.
2) They use jumps instead of if-then and loops. They have their lines numbered.
3) They almost always supply parameter names in calls to Evt functions. You can do the same, but you can also use calls without parameter names.
4) Some commands are replaced by better analogs in MMExtension. For example, you cannot use evt.OnTimer command, instead you should use Timer function.
5) There are other differences, like declaration of events.

Here's an example (a Lua script):
Game.MapEvtLines:RemoveEvent(60) -- remove original event
evt.map[60] = function()
local i
if evt.Cmp("MapVar0", 4) then
evt.StatusText(5) -- "Nothing here"
else
evt.Add("MapVar0", 1)
evt.StatusText(4) -- "You found something!"
i = Game.Rand() % 6
if i == 1 then
evt.Add("Inventory", 1) -- "Longsword"
elseif i == 2 then
evt.Add("Inventory", 15) -- "Dagger"
elseif i == 3 then
evt.Add("Inventory", 58) -- "Club"
elseif i == 4 then
evt.Add("Inventory", 161) -- "Phirna Root"
elseif i == 5 then
evt.Add("Inventory", 309) -- "Inferno"
else
evt.Add("Inventory", 94) -- "Cloth Hat"
end
end
end
It comes from a decompiled script ZNWC.lua of MM6. I just added the first line to make it remove original event handler, so that this code fragment can be used on its own. Decompiled scripts remove all standard event handlers at once with Game.MapEvtLines.Count = 0 command. If you want to modify parts of decompiled scripts, you should also extract them like I did here. See RemoveEvent method for more info.

Now it's time for a script doing the same thing (if you play the game from start with it), but written using more fitting MMExtension features:
local TXT = Localize{
NothingHere = "Nothing here",
FoundSomething = "You found something!",
}
local items = {1, 15, 58, 161, 309, 94}
Game.MapEvtLines:RemoveEvent(60) -- remove original event
evt.map[60] = function()
if mapvars.Shelf60 == 4 then
return Game.StatusText(TXT.NothingHere)
end
mapvars.Shelf60 = (mapvars.Shelf60 or 0) + 1
Game.StatusText(TXT.FoundSomething)
local i = math.random(1, #items)
evt.Add("Inventory", items[i]) -- alternatively: evt.GiveItem{Id = items[i]}
end

You can decompile scripts by yourself if you ever need to. To do so, extract all *.evt and *.str files from the same LOD archive you used to extract *.txt files. Create "Decompile" sub-folder inside the game folder, put these files there and run this simple script:
local dir = "Decompile/"
for f in path.find(dir.."*.evt") do
evt.Decompile(f, 0, dir.."Scripts/"..path.setext(path.name(f), ".lua"))
evt.Decompile(f, 0, dir.."Scripts/txt/"..path.setext(path.name(f), ".txt"), true)
end

Short functions syntax

MMExtension features one language extension – short syntax for functions declaration. Here's an example:
sum = |x, y| x + y
-- translates into
sum = function(x, y)
return x + y
end
Return operator is only added when appropriate. For example,
check = |b| if b then
print(b)
end
-- translates into
check = function(b)
if b then
print(b)
end
end
Since such short functions can return only one value, you'll have no problems using them in function calls and table declarations:
Timer(|| evt.DamagePlayer{Damage = 1}, const.Minute)
-- translates into
Timer(function()
return evt.DamagePlayer{Damage = 1}
end, const.Minute)
If you want to return more than one value, put the whole short function into parentheses:
switch = (|x, y| y, x)
-- translates into
switch = (function(x, y)
return y, x
end)
You can even put multiple statements inside a short function in parentheses:
print2 = (|x, y|
print(x)
print(y)
)
-- translates into
print2 = (function(x, y)
print(x)
print(y)
end)
Using do block for the same effect would look better:
print2 = |x, y| do
print(x)
print(y)
end
-- translates into
print2 = function(x, y)
do
print(x)
print(y)
end
end
But don't go too wild with short functions, it's best to use traditional syntax for such multiline functions.

Quests

Original MM quests were spread across multiple files and manually programmed, which is inconvenient and error prone. My quests support has undergone a few iterations and I'm very happy with it now.
Here are 6 examples. They are for MM8. At the end of most examples there is extra information about functions used. Most examples utilize short functions syntax.

Start with Quest Example Simple.lua. It contains a simple quest and two text topics, as well as a greeting.
--[[
This is the simplest quest example. Go to the Clan Leader's Hall in Dagger Wound to see it in action.
It utilises new NPCTopic function for more convenient creation of simple text-only topics.
It also uses new Quest function ability to automatically find free quest slot if the Slot parameter isn't specified.
Texts are set using SetTexts function to reduce indentation level.
--]]

QuestNPC = 32 -- Frederick Talimere

-- another way to make a greeting
Greeting{
"Hello, world!",
"Hi.",
}

-- a simple text topic
NPCTopic{
"Blah 1",
"Blah Blah Blah",
}

-- a simple quest: require item #1 (Longsword), give 1000 exp, 1000 gold and an artifact hat
Quest{
"SimpleExampleQuest",
QuestItem = 1, -- quest item index (Longsword)
Gold = 1000, -- reward: gold
Exp = 1000, -- reward: experience
RewardItem = 536, -- reward: Lucky Hat
}
.SetTexts{
Topic = "Quest",
Give = "I need a Longsword!",

Done = "That's the sword I was looking for! Thank you! I have this hat and some gold coins for you!",
Undone = "You don't have the sword yet?",

After = "Thank you for the sword!",

Quest = "Bring a Longsword (the most basic of swords) to Frederick Talimere on Dagger Wound Islands.",
}

-- another simple text topic
NPCTopic{
"Blah 2",
"Second Blah Blah Blah!",
}

--[[
NPCTopic{topic, text} and Greeting{firstGreet, greet} functions just call Quest function with appropriate parameters.
You can specify any parameters you would normally pass to Quest function, like Slot, CanShow etc.
Note that if you pass a number as topic to NPCTopic function, it will set StdTopic to that number.
See Quest Example.lua for details on StdTopic and other parameters of Quest function.


The call of Greeting function in this script is equivalent to this:
Quest{
Slot = -1,
Texts = {
FirstGreet = "Hello, world!",
Greet = "Hi.",
}
}

The first call of NPCTopic function is equivalent to this:
Quest{
Texts = {
Topic = "Blah 1",
Ungive = "Blah Blah Blah",
}
}
]]
Quest Example.lua contains basically the same quest, but it is more complex. It has different NPC greetings depending on quest state and conditionally shown topics, one of which lets you buy items from NPC.
local A, B, C, D, E, F = 0, 1, 2, 3, 4, 5
local Q = vars.Quests

--[[
This is an example of a simple quest, dialog topics that depend on quest state and a 'sell item' topic.
Mostly it consists of texts rather than code. Go to the Clan Leader's Hall in Dagger Wound to see it in action.
It also demonstrates short functions syntax addon (see help for more info).
--]]

QuestNPC = 1 -- The lizard in the tavern

-- a simple quest: require item #1 (Longsword), give 1000 exp, 1000 gold and an artifact hat
Quest{
"ExampleQuest", -- Same as: Name = "ExampleQuest",
Slot = A,
Texts = {
FirstGreet = "Hello, world!",
Greet = "Hi.",

Topic = "Quest!",
Give = "I need a Longsword!",

GreetGiven = "How's it going?",
-- TopicGiven can be set as well, but I keep it at "Quest!" here
Done = "That's the sword I was looking for! Thank you! I have this hat and some gold coins for you!",
Undone = "You don't have the sword yet?",

GreetDone = "Greetings to you, The Man Who Gave The Sword!",
TopicDone = "Thanks!",
After = "Thank you for the sword!",

Quest = "Bring a Longsword (the most basic of swords) to that lizard in the tavern of Dagger Wound Islands.",
},
QuestItem = 1, -- quest item index (Longsword)
Gold = 1000, -- reward: gold
Exp = 1000, -- reward: experience
RewardItem = 536, -- reward: Lucky Hat
}

-- this will hide the standard topic in slot B
Quest{
Slot = B,
}

-- this will hide the standard topic in slot C
Quest{
Slot = C,
}

-- this topic is shown only when the quest is taken
Quest{
Slot = C,
CanShow = || Q.ExampleQuest == "Given", -- a check that the quest is taken (short function!)
-- Short function syntax language extension translates this into:
-- CanShow = function()
-- return Q.ExampleQuest == "Given"
-- end,

Texts = {
Topic = "Reverse Engineering",
Ungive = "If you bring me the sword, I can reverse-engineer it and make its copies. To tell you the truth, everything here is reverse-engineered.",
},
}

-- this topic is shown only when the quest is done in place of the topic above (sell swords)
Quest{
Slot = C,
CanShow = || Q.ExampleQuest == "Done", -- a check that the quest is finished (short function!)
Texts = {
Topic = "Buy Longsword for 50 gold",
Done = "Here's a sword I made for you!",
Undone = "No money - no Longsword, honey."
},
NeverGiven = true, -- skip "Given" state, perform Done/Undone check immediately
NeverDone = true, -- sell any number of swords. This makes the quest completable mutiple times
QuestGold = 50, -- pay: 50 gold
RewardItem = 1, -- reward: Longsword
}

--[[

Other Quest properties:
StdTopic -- use the standard topic with specified number. For example, a trainer topic or "Join" topic.
StdTopicGiven, StdTopicDone -- similarly, standard topics specific to Given and Done states.
FirstStdTopic -- standard topics specific to initial (ungiven) state.
Quest -- quest number in quests.txt, by default it's allocated automatically
BaseName -- for quests that require you to go from one NPC to another. Setting BaseName makes two quests share the same quest state defined by BaseName. See "Quest With 2 NPCs.lua".
GivenState -- by default it's "Given". This may be useful in a quest with many stages.
DoneState -- by default it's "Done". This may be useful in a quest with many stages.

If you don't pass Slot, any slot not occupied by an MMExt quest will be chosen. If you pass "same" as Slot value, the last used slot will be reused.


Localization:
To generate localization template for all scripts, press Ctrl+F1, write
GenerateLocalization()
and press Ctrl+Enter. It will generate the following items in Scripts\Localization folder:
Quests.txt -- for quests
Common.txt -- for strings passed to LocalizeAll function
Scripts.txt -- for strings passed to Localize function
These files should be edited with Txt Tables Editor from my site.
Alternatively, run GenerateLocalization(true) to generate *.lua localization files. Choose whichever format you prefer.
To generate localization for quests only you can use GenerateQuestsLocalization() instead of GenerateLocalization() command.
To generate localization excluding quests you can use GenerateLocalization(false, false) command.
Note that GenerateLocalization function assumes your scripts contain up to 1 use of LocalizeAll and up to 1 use of Localize function, both of which are at the beginning of the script.

To test localization changes without restarting the game you can create a script in Globals folder with this line:
ReloadLocalization()
Then you'll only need to reload a saved game to refresh localization.


For more complex quests you can set up the following functions:
(here 't' is the table that you passed to the Quest function, it also has some new fields set by Quest function)

Checks (return value is interpreted as true or false):
CanShow(t)
CheckGive(t)
CheckDone(t)

Called on corresponding events:
Give(t)
Ungive(t)
Done(t)
Undone(t)

For complete control - these will override default behavior:
GetGreeting(t, NotFirstVisit)
GetTopic(t)
Execute(t)
IsGiven(t)

GetGreeting and GetTopic functions return a string.

Note that you can also make custom quest states. Say, you have a quest called MyQuest. If you set vars.Quests.MyQuest = "MyState", Texts.TopicMyState (or StdTopicMyState) will be displayed. When you click it, Texts.MyState will be displayed and MyState function will be called.

]]
Quest With 2 NPCs.lua is an example of a quest that requires going to another NPC.
local A, B, C, D, E, F = 0, 1, 2, 3, 4, 5
local Q = vars.Quests

--[[
This is an example of a quest that requires you to go from one NPC to another.
Also demonstrates usage of StdTopic to make NPC join the party.
Like in Quest Example.lua, short function syntax addon is utilized.
--]]


QuestNPC = 1 -- The lizard in the tavern

-- quest start: take the quest in the tavern
Quest{
"PowerStone",
Slot = D,
GivenItem = 617, -- gives Power Stone upon giving the task
CheckDone = false, -- the quest can't be completed here
}
.SetTexts{
Topic = "Frederick Talimere",
TopicDone = false, -- don't show if it's done
Give = "Show this stone to Frederick Talimere. He will be interested.",
Undone = "Yes, just a stone. Frederick is obsessed with these stones. What a fool...",

Quest = "Show a stone to Frederick Talimere in Dagger Wound Islands.",
}



QuestNPC = 32 -- Frederick Talimere

-- quest end: talk to Frederick to get the stone
Quest{
BaseName = "PowerStone",
Slot = D,
Exp = 1000, -- reward: experience
QuestItem = 617, -- need Power Stone
KeepQuestItem = true, -- don't take power stone away
}
.SetTexts{
-- no Topic - don't show the topic if the quest isn't taken
TopicGiven = "Power Stone",
TopicDone = "Power Stone",
Done = "Wow, this is a stone! I love stones!",
Undone = "One lizard told me you have a stone, and so do I. Why don't you show me yours and I'll show you mine?",
After = "I have about 30 of these stones. You know what, let's go looking for stones together! But I need to get a sword first. Because who knows, we might meet some enemies on our way. With a sword in my hands I'll look more persuasive and will calm down any enemy. Trust me, negotiations are my thing!",
}

-- show Join topic when both example quests are completed
Quest{
Slot = D,
StdTopic = 602, -- Join topic of Frederick Talimere
CanShow = || Q.PowerStone == "Done" and Q.SimpleExampleQuest == "Done",
}
Quest Alchemy.lua demonstrates a quest similar to "collect ingredients for a potion" quests with a little extra twist.
local A, B, C, D, E, F = 0, 1, 2, 3, 4, 5

--[[
This is an example of an alchemic quest like those seen in MM8. It works smarter by removing weaker ingredients first.
It replaces default quest of Thistle that normally makes a Potion of Pure Speed.
Like the example with 2 NPCs, it uses BaseName property to make a cross-topic quest easily.
Then there is some stuff just for fun: I reinitiate a conversation 2 minutes after the quest is completed and show some text.
--]]

QuestNPC = 88 -- Thistle


Quest{ -- Get quest
"StreetAlchemy",
}
.SetTexts{
FirstTopic = "Street Alchemy", -- only show if it isn't given
Give = "Hey! Hey fellas! I'm chronicling a Street Alchemy special. You wanna see some alchemy?",
Quest = "Bring Thistle on the Dagger Wound Islands the basic ingredients for a Potion of Disappearance.",
}


NPCTopic{ -- Ingredients topic
"Ingredients",
"Ultimate Potions are made of a complex blending of the three basic ingredients: Swords, Boots and Armor. Potion of Disappearance requires 6 Longswords, 2 pairs of boots and 2 leather armors."
}


Quest{ -- Finish quest
BaseName = "StreetAlchemy",
QuestItem = {
{1,2,3,4,5, Count = 6}, -- all kinds of Longswords, 6 in total
{132,133,134,135,136, Count = 2}, -- all kinds of Boots, 2 in total
{84,85,86,87,88, Count = 2}, -- all kinds of Leather Armor, 2 in total
},
Exp = 1000,
RewardItem = 535, -- Ring of Fusion
Done = function(t)
evt.Add("Inventory", 220) -- add an empty bottle to make it appear as if it's the reward

-- now make him speak to us again after some time
local npc = QuestNPC -- QuestNPC is set to NPC being spoken to in a dialog
Sleep(const.Minute*3, nil, {0}) -- sleep for 3 minutes and only wake up when no dialog is active (hence, the 3rd parameter)
evt.SpeakNPC(npc)
end
}
.SetTexts{
TopicGiven = "Do you have the Ingredients?", -- only show if it's given
Done = "Hey look, the Potion of Disappearance has disappeared! Take this empty bottle, it's yours now.",
Undone = "You are missing all or some of the needed ingredients. Remember, to make a Potion of Disappearance I need 6 Longswords, 2 pairs of boots and 2 leather armors.",
}


Quest{ -- Instead of Ingredients topic
Slot = B,
CanShow = function(t)
return Game.CurrentScreen ~= const.Screens.House -- only show if NPC was met on the street
end,
}
.SetTexts{
Greet = "I think there's something in your backpack...",
}
Quest Kill Monsters.lua has two "kill monsters" quests, MMExtension supports them natively so you don't have to add all the checks for slain monsters into effected maps.
--[[
These are 2 example quests that require killing multiple kinds of monsters.
Go to the Clan Leader's Hall in Dagger Wound to see the quests in action.
--]]

QuestNPC = 182 -- Dirthic, an empty NPC in a house on an island

evt.MoveNPC(QuestNPC, 173) -- move him to Clan Leader's Hall


-- Quest 1: Kill all pirates
KillMonstersQuest{
-- quest name is optional
{Map = "out01.odm", Monster = {181, 182, 183}},

Exp = 2000,
Gold = 2000,
}
.SetTexts{
Greet = "Hi there!",

Topic = "Pirates!",
Give = "Kill all da Pirates on Dagger Wound Islands.",
Done = "It's great that you've killed them! 2000 gold for you.",
Undone = "Just kill 'em, ok?",
TopicDone = false, -- hide the topic when the quest is completed

Quest = "Kill all Pirates on Dagger Wound Islands. Return to Dirthic in Clan Leader's Hall.",
Killed = "You have killed all Pirates!", -- completion message
}


-- Quest 2: Kill all creatures in Abandoned Temple
KillMonstersQuest{
"ClearAbandonedTemple", -- quest name

{Map = "d05.blv", Monster = {7, 8, 9}},
"You have killed all Couatls! Serpentmen are yet to be killed.", -- partial completion message (optional)
{Map = "d05.blv", Monster = {94, 95, 96}},
"You have killed all Serpentmen! Some Couatls are alive.", -- partial completion message (optional)

Exp = 5000,
Gold = 5000,
}
.SetTexts{
Topic = "Snakes!",
Give = "Kill all of them creatures in Abandoned Temple.",
Done = "It's great that you've killed them! 5000 gold for you.",
Undone = "Just kill 'em, ok?",
TopicDone = false, -- hide the topic when the quest is completed

Quest = "Kill all creatures in Abandoned Temple. Return to Dirthic in Clan Leader's Hall.",
Killed = "You have killed all Couatls and Serpentmen!", -- completion message
}

--[[
KillMonstersQuest function takes a list of tasks that it checks with CheckMonstersKilled.
Here are ways of using CheckMonstersKilled:
CheckMonstersKilled{} -- killed all monsters on the map?
CheckMonstersKilled{Group = 1} -- killed all monsters belonging to group 1?
CheckMonstersKilled{Monster = 7} -- killed all monsters of kind 7 (Young Couatl)?
CheckMonstersKilled{NameId = 3} -- killed all monsters with NameId = 3 in placemon.txt (Dragon Hunter Pet)?
CheckMonstersKilled{MonsterIndex = 5} -- killed monster with index 5 in Map.Monsters array?
Instead of a single number you can pass a table with numbers, like I do in this example.
Additonal parameters:
Count -- need to kill at least this many monsters
InvisibleAsDead -- treat invisible (that is, currently disabled) monsters as dead when counting (MM8 only. 'true' by default)

MM6 currently isn't supported, because it doesn't have evt.CheckMonstersKilled command. InvisibleAsDead = false is only supported in MM8.

KillMonstersQuest tasks have an extra required Map parameter. A quest can span across multiple maps.

You can specify partial completion messages. They are placed after a group of tasks. For example:
{task1},
{task2},
{task3},
"first 3 tasks done",
{task4},
{task5},
"tasks 4 and 5 done",
{task6},
"task 6 done",

KillMonstersQuest adds completion messages to Texts under names Killed1, Killed2, Killed3 and so on, for localization.

KillMonstersQuest supports all parameters of Quest function. It sets Quest parameter to 'true' if it isn't specified.
]]
Multilevel Quest.lua is a complex tree-style dialog, yet elegant in execution. QuestBranch function is utilized.
local A, B, C, D, E, F = 0, 1, 2, 3, 4, 5

--[[
This example demonstrates a complex branched dialog.
It isn't too easy to understand, but it's elegant.
It also shows how you can have item name as topic name and some other bells and whistles.
Go to the Clan Leader's Hall in Dagger Wound to see it in action.
--]]

local MyNPC = 2 -- Dadeross in the lizards tavern

-- For fun: play sound when entering the conversation
function events.EnterNPC(npc)
if npc == MyNPC then
Game.PlaySound(130)
end
end

local function SetBranch(t)
QuestBranch(t.NewBranch)
end

local function ItemTopic(t)
-- return 'false' if the quest is given, which means the item is given away
return not vars.Quests[t.Name] and Game.ItemsTxt[t.MyItem].Name
end

local function GiveItem(t)
evt.ForPlayer().Add("Inventory", t.MyItem) -- give item
-- Game.PlaySound(205) -- make only sound
evt.Add("Experience", 0) -- make sound and animation
evt.FaceAnimation(Game.CurrentPlayer, const.FaceAnimation.SmileHuge) -- a happy face
QuestBranch("Thanks")
end

-- sipmlify similar quests creation
local QuestBase = {}
local function MyQuest(t)
table.copy(QuestBase, t) -- copy common values
QuestBase.Slot = QuestBase.Slot and QuestBase.Slot + 1 -- auto-increment Slot
return Quest(t)
end

--[[
Now, let's get to the quests themselves.

Dialog structure:

- Weapons
- Swords
- Sword 1
- Sword 2
- Sword 3
- Daggers
- Dagger 1
- Axes
- Axe 1
- Axe 2
- Axe 3
- Blasters
- Magic
- Book 1
- Book 2
- Book 3
- Book 4
- Dadeross' Letter to Fellmoon
- Certificate of Authentication (for Axe of Balthazar)
(+ Thanks screen)
]]

QuestNPC = MyNPC

-- greeting

Greeting{
"I'm placed here to give you free stuff.",
"Please choose your free stuff.",
}

-- default topics

QuestBase = {Slot = A}

-- get rid of standard topics of this NPC
MyQuest{}
MyQuest{}
MyQuest{}
MyQuest{}
MyQuest{}
-- A topic that's shown when there are no items left. This one is a bit hackish.
-- Since the quest-matching function goes from slot A to slot F, by the time it
-- asks for topic in slot F it has done all other slots. So, I check that these
-- slots have no topics and then enable the topic of this slot
MyQuest{
Ungive = SetBranch,
NewBranch = "",
GetTopic = function(t)
for i = 0, 4 do
if Game.NPC[MyNPC].Events[i] ~= 0 then
return
end
end
return t.Texts.Topic
end,
Texts = {
Topic = "Sorry, I don't have any of these",
Ungive = "Sorry, I don't have any of these. Maybe you want something else?"
}
}

-- base branch topics

QuestBase = {Branch = "", Slot = A, Ungive = SetBranch}

MyQuest{
NewBranch = "Weapons",
Texts = {
Topic = "Weapons",
Ungive = "Choose which you prefer."
}
}
MyQuest{
NewBranch = "Magic",
Texts = {
Topic = "Magic",
Ungive = "I have a few books."
}
}

-- Weapons branch

QuestBase = {Branch = "Weapons", Slot = A, Ungive = SetBranch}

MyQuest{
NewBranch = "Swords",
Texts = {
Topic = "Swords",
}
}
MyQuest{
NewBranch = "Daggers",
Texts = {
Topic = "Daggers",
}
}
MyQuest{
NewBranch = "Axes",
Texts = {
Topic = "Axes",
}
}
MyQuest{
NewBranch = "Blasters",
Texts = {
Topic = "Blasters",
}
}

-- Swords branch

QuestBase = {
Branch = "Swords", Slot = A,
GetTopic = ItemTopic,
Give = GiveItem,
Texts = {
Give = "Use it well!"
}
}

MyQuest{MyItem = 1}
MyQuest{MyItem = 10}
MyQuest{MyItem = 502}

-- Daggers branch

QuestBase = table.copy(QuestBase, {
Branch = "Daggers", Slot = A,
})

MyQuest{MyItem = 508}

-- Axes branch

QuestBase = table.copy(QuestBase, {
Branch = "Axes", Slot = A,
})

MyQuest{MyItem = 34}
MyQuest{MyItem = 37}
MyQuest{MyItem = 541}

-- Magic branch

QuestBase = table.copy(QuestBase, {
Branch = "Magic", Slot = A,
})

MyQuest{MyItem = 460}
MyQuest{MyItem = 430}
MyQuest{MyItem = 444}
MyQuest{MyItem = 404}

-- Letter and Certificate of Authentication items in main branch

QuestBase = table.copy(QuestBase, {
Branch = "", Slot = C,
})

MyQuest{MyItem = 741} -- Dadeross' Letter to Fellmoon
MyQuest{MyItem = 732, -- Certificate of Authentication
CanShow = function()
return evt.All.Cmp("Inventory", 541) -- check for Axe of Balthazar
end
}

-- Thanks branch

NPCTopic{
Branch = "Thanks", Slot = A,
Ungive = SetBranch,
NewBranch = "",
"Thanks!",
"Maybe you want something else?",
}

--[[
Here's how dialog branches work:

A quest with Branch field is only shown if that's the current branch.

Current branch can be set with QuestBranch function:
QuestBranch("BranchName")
You can also make the branch persist after you reenter NPC dialog:
QuestBranch("BranchName", true)
Or you can obtain current branch:
local branch = QuestBranch()

If there is no persisted branch name, when you enter NPC dialog the branch is set to "".

Branches support is really simple. Previous version of this example implemented it manually.
]]
Some examples also work in MM7 if you find the NPCs they operate on. As for MM6, it lacks NPC greetings and only has 3 dialog topics, plus two text-only topics. The first quest should work in it.

Localization

In order to make a script localizeable you should call Localize function in it, passing a table with default strings. The function will return a table with localized strings. See an example above.
For strings shared by multiple scripts you should use LocalizeAll function which works the same way, but normally you should only use the table returned by Localize. It automatically falls back to common localization strings if there is no script-specific one.
Also note that you aren't limited to strings, localization table can contain any values, including subtables.
Quests are localized automatically.

Localization is very much automated. GenerateLocalization() function automatically extracts localization information from all scripts and generates localization files. It requires scripts in Maps and Modules folders not to do anything prior to calling Localize and/or LocalizeAll functions. Also, each function should be called at most once per script, otherwise strings passed in subsequent calls may get ignored.
To generate localization files for all scripts, load any game, press Ctrl+F1, write GenerateLocalization() and press Ctrl+Enter. It will generate the following files in Scripts\Localization folder:
 File Description
Quests.txtQuests localization.
Common.txtStrings passed to LocalizeAll function.
Scripts.txtStrings passed to Localize function.
These files should be edited with Txt Tables Editor.
Alternatively, you can run GenerateLocalization(true) to generate *.lua localization files. Choose whichever format you prefer.
To generate localization only for quests you can use GenerateQuestsLocalization() command.
To generate localization excluding quests you can use GenerateLocalization(false, false) command.

To test localization changes without restarting the game you can create a script in Global folder with this line:
ReloadLocalization()
Then you'll only need to reload a saved game to test localization changes.



Examples

You can find more examples in the MMExtension discussion thread.

Players Skills And Spells

Below are some scripts demonstrating how you can work with skills and spells. You can test them by pasting the one you like into debug console.
-- learn all spells
for _, pl in Party do
for i in pl.Spells do
pl.Spells[i] = true
end
end
-- give Expert Perception for all players
for _, pl in Party do
local skill, mastery = SplitSkill(pl.Skills[const.Skills.Perception])
pl.Skills[const.Skills.Perception] = JoinSkill(math.max(skill, 4), math.max(mastery, const.Expert))
end
-- get all skills at Master 12
for _, pl in Party do
for i, val in pl.Skills do
local skill, mastery = SplitSkill(val)
pl.Skills[i] = JoinSkill(math.max(skill, 12), math.max(mastery, const.Master))
end
end
-- get all learned skills to Master 12
for _, pl in Party do
for i, val in pl.Skills do
if val ~= 0 then
local skill, mastery = SplitSkill(val)
pl.Skills[i] = JoinSkill(math.max(skill, 12), math.max(mastery, const.Master))
end
end
end
-- learn all available skills at Expert
for _, pl in Party do
for i, learn in EnumAvailableSkills(pl.Class) do
if learn >= const.Expert then
local skill, mastery = SplitSkill(pl.Skills[i])
skill = math.max(skill, 4) -- learn at least level 4
mastery = math.max(mastery, const.Expert) -- learn the mastery
pl.Skills[i] = JoinSkill(skill, mastery)
end
end
end
-- learn all available skills at their maximum level
local LearnLevel = (Game.Version > 6 and {1, 4, 7, 10} or {1, 4, 12})

for _, pl in Party do
for i, learn in EnumAvailableSkills(pl.Class) do
local skill, mastery = SplitSkill(pl.Skills[i])
skill = math.max(skill, LearnLevel[learn]) -- learn at least the usual needed level
mastery = math.max(mastery, learn) -- learn the mastery
pl.Skills[i] = JoinSkill(skill, mastery)
end
end

Artifact Bonuses

Giving Hareck's Leather an 'Of Earth Magic' enhancement. (untested)
function events.CalcStatBonusByItems(t)
if t.Stat ~= const.Stats.EarthMagic or t.Player.Skills[const.Skills.EarthMagic] == 0 then
return
end
for item, slot in t.Player:EnumActiveItems() do
if item.Number == 516 then
t:SetMagicBonus(SplitSkill(t.Player.Skills[const.Skill.EarthMagic]):div(2))
return
end
end
end

Giving Hareck's Leather 'Armsmaster + 8' bonus. (untested)
function events.CalcStatBonusByItems(t)
if t.Stat ~= const.Stats.Armsmaster or t.Player.Skills[const.Skills.Armsmaster] == 0 then
return
end
for item, slot in t.Player:EnumActiveItems() do
if item.Number == 516 then
t:SetArtifactBonus(8)
return
end
end
end

Q: Is there a way to change values of enchantments? For example, to make Of the Gods one give say +30 stats instead of +10?
A: (untested)
function events.CalcStatBonusByItems(t)
if t.Stat >= const.Stats.Might and t.Stat <= const.Stats.Luck then
for it in t.Player:EnumActiveItems() do
if it.Bonus2 == 2 then
t.Result = t.Result + 20
end
end
end
end

Spells Damage

Change damage of spell 2 – Flame Arrow. You can also make damage depend on t.Mastery and t.HP (monster hit points).
local function Randoms(min, max, count)
local r = 0
for i = 1, count do
r = r + math.random(min, max)
end
return r
end

function events.CalcSpellDamage(t)
if t.Spell == 2 then -- Flame Arrow
t.Result = 100 + Randoms(1, 100, t.Skill) -- 100 + (1-100) per skill level
end
end

Controlling monsters aggression in MM6

Put this script into Scripts\Global folder. It would make archers in Free Haven friendly and female peasants aggressive. In other places archers would still be aggressive and peasants still friendly.
function events.BeforeLoadMap()
if Game.Map.Name == "outc2.odm" then
LocalMonstersTxt()
Game.MonstersTxt[1].HostileType = 0 -- ArcherA
Game.MonstersTxt[2].HostileType = 0 -- ArcherB
Game.MonstersTxt[3].HostileType = 0 -- ArcherC
Game.MonstersTxt[121].HostileType = 4 -- PeasantF1A
Game.MonstersTxt[122].HostileType = 4 -- PeasantF1B
Game.MonstersTxt[123].HostileType = 4 -- PeasantF1C
end
end
Instead of map name check you can put any condition. For example, after player completes a quest you can make some monsters friendly or aggressive.

Flowers you can pick up (MM8)

Put this script into Scripts\Global folder.
-- You can find such flowers in Ravenshore at X = 16921, Y = 4112
-- Flowers disappear when picked up, which makes life easier than in Barrels script
-- The game remembers which sprites are hidden by itself

local SpriteEvents = 20000
local TXT = Localize{
FlowerHint = "Flowers",
}

local function Flower(EvtId)
local i = EvtId – SpriteEvents
evt.Add("Inventory", 208)
evt.SetSprite(i, false) -- alternatively, for the same effect: Map.Sprites[i].Invisible = true
end

local function InitFlower(i, a)
a.Event = SpriteEvents + i
evt.map[SpriteEvents + i] = Flower
evt.hint[SpriteEvents + i] = TXT.FlowerHint
end

function events.LoadMap()
for i, a in Map.Sprites do
if a.DecName == "plant27" then
InitFlower(i, a)
end
end
end

Unusually looking barrels (MM7)

Put this script into Scripts\Global folder to turn trees into barrels.
-- Turns trees into barrels

local SpriteEvents = 20000
local TopicBase = 383
local TextBase = 582
local Reorder = {[0] = 0, 1, 4, 3, 5, 2, 6, 7} -- NPC topics order is messed up
local AutonotesBase = 32

local function Barrel(EvtId)
local i = EvtId – SpriteEvents
local v = mapvars.Barrels[i]
Game.ShowStatusText(Game.NPCText[TextBase + Reorder[v]])
if v > 0 then
evt.Add(evt.VarNum.BaseStats[v – 1], 2)
evt.Set("AutonotesBits", AutonotesBase + v)
mapvars.Barrels[i] = 0
evt.hint[SpriteEvents + i] = Game.NPCTopic[TopicBase]
end
end

local function InitBarrel(i, a)
mapvars.Barrels = mapvars.Barrels or {}
mapvars.Barrels[i] = mapvars.Barrels[i] or math.random(1, 7)

a.Event = SpriteEvents + i
evt.map[SpriteEvents + i] = Barrel
evt.hint[SpriteEvents + i] = Game.NPCTopic[TopicBase + Reorder[mapvars.Barrels[i]]]
end

function events.LoadMap()
for i, a in Map.Sprites do
if a.DecName and a.DecName:match("^tree") then
InitBarrel(i, a)
end
end
end

Other Examples

Summon monster (Peasant):
local mon = SummonMonster(151, Party.X, Party.Y, Party.Z, true)
mon.NPC_ID = 52
mon.Hostile = false

See global event number (copy to console to quickly test what event is triggered by a dialog item):
-- on:
function events.EvtGlobal(evt)
Message(evt)
end
-- off:
events.EvtGlobal.clear()

Q: How to change the home position after the death of the team on current map?
A: Pass any coordinates in call to XYZ and set any Direction:
function events.DeathMap(t)
t.Name = "out05.odm"
XYZ(Party, 0, 0, 0)
Party.Direction = 0
Party.LookAngle = 0
end

Changing starting map (similar to previous example):
Game.NewGameMap = "out05.odm"
function events.NewGameMap()
XYZ(Party, 0, 0, 0)
Party.Direction = 0
Party.LookAngle = 0
end

Q: How to run a method when a user presses a specific key?
Method #1 (preferred):
function events.KeyDown(t)
if t.Key == const.Keys.F2 then
Message("F2 pressed")
end
end
Method #2 (doesn't repeat when holding the key):
Keys[const.Keys.F2] = function()
Message("F2 pressed")
end




Evt Commands


evt.EnterHouse

 Parameters:
Id In 2DEvents.txt
600 = you won
601 = you won 2 / you lost

evt.PlaySound

 Parameters:
Id
X
Y

evt.MoveToMap

Notes:
If cancel is pressed, event execution is stopped
If X, Y, Z, Direction, LookAngle, SpeedZ are all 0, the party isn't moved
If HouseId and Icon are 0, the enter dungeon dialog isn't shown

 Parameters:
X
Y
Z
Direction -1 = special case
LookAngle
SpeedZ
HouseId In 2DEvents.txt
Icon
Name if unspecified or starts with "0" => current map

evt.OpenChest

 Parameters:
Id

evt.FaceExpression

 Parameters:
Player
Frame

evt.DamagePlayer

 Parameters:
Player
DamageType
Damage

evt.SetSnow

 Parameters:
EffectId only 0 available
On

evt.SetTexture

 Parameters:
Facet [MM6] Index in Map.Facets indoors.
[MM7+] Id of facets group.
Name

evt.SetTextureOutdoors

[MM6]

 Parameters:
Model
Facet
Name

evt.ShowMovie

[MM7+]

 Parameters:
DoubleSize
ExitCurrentScreen Use true only before using evt.MoveToMap command in houses and before showing game ending.
Prevents loading of house anmation after the movie stops playing, but doesn't exit the screen properly.
Name

evt.SetSprite

 Parameters:
SpriteId
Visible bit 0x20 of sprite
Name If Name is unspecified or "0", the sprite isn't changed

evt.Cmp

Usually performs Variable >= Value comparison

 Parameters:
VarNum
Value

evt.SetDoorState

 Parameters:
Id
State 0 – state (0),
1 – state (1),
2 – switch state if the door isn't moving,
3 – switch state

evt.Add

 Parameters:
VarNum
Value

evt.Subtract

Also available as evt.Sub.

 Parameters:
VarNum
Value

evt.Set

 Parameters:
VarNum
Value

evt.SummonMonsters

 Parameters:
TypeIndexInMapStats
Level
Count
X
Y
Z
NPCGroup [MM7+]
unk [MM7+]

evt.CastSpell

 Parameters:
Spell
Mastery
Skill
FromX
FromY
FromZ
ToX
ToY
ToZ

evt.SpeakNPC

 Parameters:
NPC

evt.SetFacetBit

 Parameters:
Id [MM6] Index in Map.Facets indoors.
[MM7+] Id of facets group.
Bit
On

evt.SetFacetBitOutdoors

[MM6]

 Parameters:
Model Model index in Map.Models
Facet -1 = for all faces of model
Bit
On

evt.SetMonsterBit

[MM7+]

 Parameters:
Monster
Bit
On

evt.Question

Use Question function instead, e.g.
if Question("Restricted area - Keep out.", "What's the password?"):lower() == "jbard" then ...


 Parameters:
Question
Answer1
Answer2

evt.StatusText

Use Game.ShowStatusText function instead, e.g.
Game.ShowStatusText("Hi!")


 Parameters:
Str

evt.SetMessage

Use Message function instead, e.g.
Message("Hi!")


 Parameters:
Str

evt.SetLight

 Parameters:
Id [MM6, MM7] Map.Lights index
[MM8] Light group id
On

evt.SimpleMessage

Use Message function instead, e.g.
Message("Hi!")


 Has no parameters.

evt.SummonObject

 Parameters:
Item [MM8] Item index. Index over 1000 means random item of the same kind as Item % 1000 of strength Item div 1000.
Type [MM6, MM7] Object kind index (ObjList.txt)
X
Y
Z
Speed
Count
RandomAngle

evt.ForPlayer

Sets current player and returns evt. You can thus write things like this:
evt.ForPlayer("All").Add("Exp", 1000)

You can also manipulate evt.Player and evt.CurrentPlayer variables.
Usually a better approach is to specify player after evt, this way it only effects one call that follows:
evt.All.Add("Exp", 1000)
evt[0].Add("Gold", 1000)


 Parameters:
Player

evt.SetNPCTopic

 Parameters:
NPC
Index
Event

evt.MoveNPC

 Parameters:
NPC
HouseId In 2DEvents.txt

evt.GiveItem

 Parameters:
Strength 1-6 (like described at the end of STDITEMS.TXT)
Type
Id If Id is 0, a random item is chosen from the specified class with specified strength,
otherwise, Type and Strength determine the enchantments

evt.ChangeEvent

 Parameters:
NewEvent Changes global event for barrels, pedestals etc. The kinds of sprites with such events are hard-coded.

evt.CheckSkill

Checks that the skill meets specified Mastery and Level requirements

 Parameters:
Skill
Mastery
Level Includes "Double effect" enchantments and NPC bonuses

evt.SetNPCGroupNews

[MM7+]

 Parameters:
NPCGroup
NPCNews

evt.SetMonsterGroup

[MM7+]

 Parameters:
Monster
NPCGroup

evt.SetNPCItem

[MM7+]

 Parameters:
NPC
Item
On

evt.SetNPCGreeting

[MM7+]

 Parameters:
NPC
Greeting

evt.CheckMonstersKilled

[MM7+]

 Parameters:
CheckType 0 – any monster, 1 – in group, 2 – of type, 3 – specific monster, 4 – specific monster by name (MM8)
Id Depending on CheckType: 0 – not used, 1 – group id, 2 – monster type minus 1, 3 – monster id, 4 – id in placemon.txt (MM8 only)
Count 0 – all must be killed, else a number of monsters that must be killed
InvisibleAsDead [MM8] 1 (default) – treat invisible (that is, currently disabled, like pirates in Ravenshore before you enter Regna) monsters as dead when counting, 0 – include invisible monsters

evt.ChangeGroupToGroup

[MM7+]

 Parameters:
Old
New

evt.ChangeGroupAlly

[MM7+]

 Parameters:
NPCGroup
Ally Monster class that guards this group. That is, (Id + 2):div(3), like in Hostile.txt.

evt.CheckSeason

[MM7+]

 Parameters:
Season

evt.SetMonGroupBit

[MM7+]

 Parameters:
NPCGroup
Bit
On

evt.SetChestBit

[MM7+]

 Parameters:
ChestId
Bit
On

evt.FaceAnimation

[MM7+]

 Parameters:
Player
Animation

evt.SetMonsterItem

[MM7+]

 Parameters:
Monster
Item
Has

evt.StopDoor

[MM8]

 Parameters:
Id

evt.CheckItemsCount

[MM8]

 Parameters:
MinItemIndex
MaxItemIndex
Count

evt.RemoveItems

[MM8]

 Parameters:
MinItemIndex
MaxItemIndex
Count

evt.Jump

[MM8]

 Parameters:
Direction
ZAngle
Speed

evt.IsTotalBountyInRange

[MM8]

 Parameters:
MinGold
MaxGold

evt.IsPlayerInParty

[MM8]

 Parameters:
Id Roster.txt



Events


Core\ events.lua

 Events:

CalcSpellDamage

{
HP
HitPoints
Mastery:const
Result
Skill
Spell
}

WalkToMap

{
Days [MM7+]
EnterMap
EnterSide [MM7+]
LeaveMap
LeaveSide [MM7+]
X
Y
}
Sides:
0, "up", "down", "left", "right".
0 means "party start" sprite.

NewGameMap

( )

DeathMap

{
Name
}

FogRange

( )

GameInitialized1

( )
loaded .bin data

GameInitialized2

( )
loaded .txt data

CanSaveGame

{
IsArena
SaveKind
}

CanCastLloyd

( )

IsUnderwater

{
Map
Result
}
[MM7+]

SetMapNoNPC

( )
[MM7]

EnterNPC

( i )

ShowNPCTopics

( i )

DrawNPCGreeting

{
NPC
Seen
Text
}

WindowMessage

{
Handled
LParam
Msg
Result
WParam
Window
}

KeyUp

{
Alt
ExtendedKey
Handled
Key
WasPressed
}

KeyDown

{
Alt
ExtendedKey
Handled
Key
WasPressed
}

Action

{
Action
Handled
Param
Param2
}

MenuAction

{
Action
Handled
Param
Param2
}

ExitNPC

( i )

KeysFilter

{
Key
On
Result
}

BeforeSaveGame

( )

AfterSaveGame

( )

SkyBitmap

{
FirstVisit
Result
}

ShowMovie

{
Allow
CallDefault
DoubleSize
ExitCurrentScreen
Name
Y
}

CalcStatBonusByItems

{
ArtifactBonus [MM7+]
IgnoreExtraHand
MagicBonus [MM7+]
Player
PlayerIndex
Result
SetArtifactBonus
SetMagicBonus
Stat
}
Here's how SetArtifactBonus(value) method works:
[MM7+] If value is bigger than ArtifactBonus, it modifies ArtifactBonus and increases Result.
[MM6] It just adds the value to Result.

SetMagicBonus does the same to MagicBonus.

CalcStatBonusByMagic

{
Player
PlayerIndex
Result
Stat
}

CalcStatBonusBySkills

{
Player
PlayerIndex
Result
Stat
}

GetSkill

{
Player
PlayerIndex
Result
Skill
}

GetAttackDelay

{
Player
PlayerIndex
Ranged
Result
}

CalcDamageToPlayer

{
Damage
DamageKind
Player
PlayerIndex
Result
}

DoBadThingToPlayer

{
Allow
Monster [MM7+]
MonsterIndex [MM7+]
Player
PlayerIndex
Thing
}

GetStatisticEffect

{
Result
Value
}

UseMouseItem

{
ActivePlayer
ActivePlayerIndex
Allow
CallDefault
IsPortraitClick
Player
PlayerIndex
}

MonsterKilled

( mon, monIndex, defaultHandler, player, playerIndex )
player and playerIndex parameters are only passed in some cases

ItemAdditionalDamage

{
DamageKind
Item
Monster
Player
Result
Vampiric
}
Monster, MonsterIndex, Player and PlayerIndex fields are only set if the function is called by the game itself and not a script

CalcDamageToMonster

{
Damage
DamageKind
Monster
MonsterIndex
Player
Result
}
Player and PlayerIndex fields are only set in some cases. For example, in MM6 they're not set when bonus elemental damage of weapons is applied

PickCorpse

{
Allow
CallDefault
Monster
MonsterIndex
}

CastTelepathy

{
Allow
CallDefault
Monster
MonsterIndex
}


Core\ evt.lua

 Events:

LeaveMap

( )

LeaveGame

( )

BeforeLoadMap

( WasInGame )

CancelLoadingMapScripts

( )
Return true to cancel execution of map scripts. Used by the Editor.

LoadMap

( WasInGame, NoScripts )
NoScripts = true if map scripts execution was cancelled by CancelLoadingMapScripts event.

AfterLoadMap

( )

GetEventHint

( evtId )

GetMazeInfo

( )

EvtMap

( evtId, seq )

EvtGlobal

( evtId, seq )


Core\ main.lua

 Events:

StructsLoaded

( )

ScriptsLoaded

( )


Core\ timers.lua

 Events:

Tick

( )



General Functions


Structs\After\ Backup.lua

 Functions:
LocalFile
( t )
Pass any table from Game.* to this function to make it restore its original state after the player exits the map.
LocalMonstersTxt
( )
LocalHostileTxt
( )
[MM7+]
LocalNPCNews
( )


Structs\After\ DataTablesSupport.lua

 Functions:
SplitLines
( str, startIdx )
\r\n, \r
SplitLinesAny
( str, startIdx )
\r\n, \n, \r
SplitTabs
( str, startIdx )


Structs\After\ Functions.lua

 Functions:
SplitSkill
( val )
JoinSkill
( skill, mastery:const )
XYZ
( t, x, y, z )
Get X,Y,Z, fields:
local x, y, z = XYZ(Party)

Set X,Y,Z, fields:
XYZ(Party, x, y, z)

Enumerate "X", "Y", "Z" strings:
for X in XYZ do
print(Party[X])
end

Message
( text )
Question
( text, qtext )
Returns the reply. text is shown as message, qtext is shown at the beginning of reply field.
Doesn't work in houses in MM7.
ReplaceNPCTopic
( old, new )
Searches through all NPC topics and replaces one topic with another
AddGoldExp
( gold, exp )
ShowQuestEffect
( )
Plays sound and shows visual effect on current character's face
TakeItemFromParty
( id, keep )
id can also be a table or a table of tables. See Quest Alchemy.lua from quest examples
CheckMonstersKilled
{
Group
Monster
MonsterIndex
NameId
Count
InvisibleAsDead
}
See Quest Kill Monsters.lua from quest examples
EnumAvailableSkills
( class )
Returns Skill, MaxMastery
SummonMonster
( id, x, y, z, treasure, place )
Unless treasure is true, the monster doesn't have any items or gold.
place defines monster index in Map.Monsters array if specified.
SummonItem
( number, x, y, z, speed )
RebildIDList
( )
ChangeSprite
( n, name )
CreateSprite
{ name, x, y, z;
Bits
X
Y
Z
}
MoveModel
( m, dx, dy, dz, MoveParty )
MoveParty isn't supported yet


Structs\After\ LocalizationAndQuests.lua

 Variables:
TakeQuestOperation
Should be either "Add" or "Set". This determines the overlay flash on character face when a quest is taken.
[MM6, MM8] Defaults to "Add".
[MM7] Defaults to "Set".
Quests
QuestNPC
vars.Quests
[name]
Quest states: nil, "Given", "Done" or a custom state.

 Functions:
LocalizeAll
( t, over )
Possible values of over:
true: permanent setup – overwrite all (used in Localization scripts only)
false: temporary setup – overwrite temporary setup only
"update": remove all previous temporary setup, overwrite temporary setup only
Localize
( t, over, lev = 1 )
Possible values of over:
true: permanent setup – overwrite all (used in Localization scripts only)
false: temporary setup – overwrite temporary setup only
"update": remove all previous temporary setup, overwrite temporary setup only
GenerateQuestsLocalization
( IsLua )
GenerateLocalization
( IsLua, IncludeQuests )
QuestBranch
( branch, persist )
Sets current dialog branch to branch if it's specified.
persist parameter makes the branch persist after you reenter NPC dialog.
Returns current branch when called without parameters.
If there is no persisted branch name, when you enter NPC dialog the branch is set to "".
Quest
{ name;
After
Awards
BaseName
Branch
CheckDone
CheckGive
Done
DoneState
Event
Execute
Exp
Experience
FirstStdTopic
GetGreeting
GetTopic
Give
GivenItem
GivenState
Gold
IsGiven
KeepQuestItem
NPC
Name
NeverDone
NeverGiven
Quest
QuestGold
QuestItem
RewardItem
SetTexts
Slot
StdTopic
StdTopicDone
StdTopicGiven
TakeQuestOperation
Texts
Undone
Ungive
}
See quest examples
Greeting
{ text, textSeen;
Text
TextSeen
... Quest() parameters ...
}
See quest examples
NPCTopic
{ topic, text;
Topic
Text
... Quest() parameters ...
}
See quest examples
KillMonstersQuest
{ name = nil, ... A list of either tables with CheckMonstersKilled() parameters or partial completion messages ...;
... Quest() parameters ...
}
See Quest Kill Monsters.lua from quest examples


Structs\After\ Text Tables.lua

 Functions:
ParseTextTable
( s, r, SkipEmpty, AssignTables )
LoadTextTable
( s, r, SkipEmpty, AssignTables )
ParseBasicTextTable
( s, StartingLinesCount )
LoadBasicTextTable
( s, StartingLinesCount )
ParseNumbersTextTable
( s, StartingLinesCount )
LoadNumbersTextTable
( s, StartingLinesCount )
TransposeTextTable
( t )
ReadLodTextTable
( fname, row, col )


Core\ Common.lua

 Functions:
assertnum
( v, level, msg )
tget
( t, k, ... )
Returns t[k] if it exists, otherwise sets t[k] = {} and returns t[k].
The process is repeated for additional parameters, e.g. t[k][k1]
pcall2
( ... )
Like pcall, but in case of an error shows error message
xpcall2
( ... )
Like xpcall, but in case of an error shows error message
cocall
( f, ... )
Same as coroutine.resume(coroutine.create(f), ...)
cocall2
( f, ... )
Like cocall, but in case of an error shows error message
dofile2
( path, ... )
Loads file in protected mode, in case of an error shows error message. Return format is the same as that of pcall
coroutine.resume2
( ... )
Like coroutine.resume, but in case of an error shows error message
os.GetErrorText
( code )
path.find
( filter, dir )
path.FindFirst
( filter, dir )
path.findfirst
( filter, dir )
os.chdir
( [dir] )
Returns previous current directory. Call without parameters to look up current dirrectory
os.mkdir
( dir )
os.copy
( old, new, FailIfExists )
path.GetRelativePath
( from, to, isDir )
string.convert
( s, encFrom, encTo, defChar )
debug.FunctionFile
( f )


Core\ Debug.lua

 Functions:
debug.HideConsole
( )


Core\ ErrorFunction.lua

 Functions:
errorinfo
( s )
tostring2
( v, lim, tabs )


Core\ RSFunctions.lua

 Functions:
table.swap
( t, min, max )
Swaps order of the array. min and max default to 1 and #t respectively
table.move
( t, from, to )
Moves an element from one index to another
table.copy
( src, dest, overwrite )
Performs shallow copy. If dest = nil, a new table is created
table.find
( t, v )
Finds value v, returns corresponding key
table.ifind
( t, v, start )
Finds value v in array part of the table, returns first match. Uses raw access (rawget)
table.invert
( t, out )
Swaps keys and values
table.clear
( t )
Removes all elements from the table
coroutine.yieldN
( n, ... )
n times in a raw calls coroutine.yield(...). Returns the result of last call
path.ext
( s )
Extracts extension (e.g. returns ".txt" etc.)
path.setext
( s, ext )
Changes extension (e.g. path.setext("my.txt", "_2.txt") == "my_2.txt")
path.name
( s )
Extracts file name
path.dir
( s )
Extracts file path including trailing slash
path.addslash
( s )
Adds trailing slash
path.noslash
( s )
Removes trailing slash (or multiple slashes)
io.save
( path, s, translate )
Saves a string into a file (overwrites it)
io.load
( path, translate )
Loads a file as a string
string.split
( str, delim, plain )
Returns a table of strings. delim can be a plain string (plain = true) or a pattern
string.csplit
( str, charlist )
Any character from charlist string is a delimiter
string.replace
( str, old, new )
Parameters are treated as plain strings, not patterns
sortpairs
( t )
Returns pairs in ascending order with the following comparison rule: number < boolean < string < userdata < table < function < thread
debug.findupvalue
( f, name )
Returns index, value of an upvalue with the given name, or nil if it doesn't exist
debug.findlocal
( thread, lev, name )
Returns index, value of a local variable with the given name, or nil if it doesn't exist
debug.upvalues
( f, cache )
If cache = true, upvalue indexes are cached.
Usage:
1) v = debug.upvalues(f).upvalue_name
2) debug.upvalues(f).upvalue_name = v
3) for k, v in debug.upvalues(f) do print(k, v) end


Core\ RSMem.lua

 Functions:
mem.string ( p, size, ReadNull ) mem.string(p) – read null-terminated string
mem.string(p, size) – read null-terminated string not more than size bytes
mem.string(p, size, true) – read size bytes as string
mem.call ( t, ... )
mem.IgnoreProtection ( on )
mem.malloc ( size )
mem.alloc ( size )
mem.free ( p )
mem.realloc ( p, size )
mem.new ( size, f, ... )
mem.StaticAlloc ( size )
mem.copy ( dest, src, count ) count can be omitted if src is a string or a structure
mem.fill ( ptr, n, c = 0 )
mem.LuaAlloc ( size )
mem.func ( ... )
mem.LoadDll ( name, cc )
mem.UnloadDll ( t )
mem.GetProcAddress ( p, proc )
mem.structs.getdefine ( )
mem.structs.getunions ( )
mem.structs.CustomType ( name, size, f )
mem.struct ( f, class, p )
mem.GetHookSize ( p )
mem.GetInstructionSize ( p )
mem.hook ( p, f, size ) Primitive call hook: 5-byte call instruction that calls into Lua code
mem.hookjmp ( p, f, size ) Primitive jump hook
mem.hookalloc ( size ) Allocate memory for code
mem.hookfree ( p )
mem.copycode ( ptr, size, MemPtr, NoJumpBack ) Copies standard code into a memory block and then writes a jump back into the function
(the copied code must not contain jumps or calls, except within the copied block)
MemPtr can optionally specify a pre-allocated memory address.
mem.autohook ( p, f, size ) hookjmp with automatic calling of overwritten code (see copycode note)
If the function returns true, the jump to original code isn't performed
mem.autohook2 ( p, f, size ) hookjmp with automatic calling of overwritten code (see copycode note)
The function is called after the overwritten code
If the function returns true, the jump to original code isn't performed
mem.bytecodehook ( p, code, size ) Like autohook, but takes a compiled Asm code string as parameter
code can also be a function f(ptr). ptr is the address of memory allocated for hook code or nil (to calculate size)
mem.bytecodehook2 ( p, code, size ) Like autohook2, but takes a compiled Asm code string as parameter
See note of bytecodehook about code
mem.bytecodepatch ( p, code, size ) Replaces original instructions with new ones, jumping out if needed
See note of bytecodehook about code
mem.asmhook ( p, code, size ) Like autohook, but takes an Asm code string as parameter
mem.asmhook2 ( p, code, size ) Like autohook2, but takes an Asm code string as parameter
mem.asmpatch ( p, code, size ) Replaces original instructions with new ones, jumping out if needed
mem.asmproc ( code ) Creates an Asm function
mem.hookfunction ( p, nreg, nstack, f, size ) Set hook at the beginning of a function, allows calling the original function (see copycode note)
mem.hookcall ( p, nreg, nstack, f ) Replaces an existing CALL instruction and uses the same protocol as hookfunction
mem.nop ( p, n ) Writes n NOPs
mem.nop2 ( p, p2 ) Writes NOPs from p to p2 - 1


Core\ RSPersist.lua

 Functions:
persist
( t, perm )
unpersist
( buf, perm, data )


Core\ dump.lua

 Functions:
dump
( t, depth, exact )
Useful for debugging and experiments. Shows t, expanding all tables in it up to the depth level. In exact = true mode outputs proper Lua code.


Core\ events.lua

 Variables:
VFlipUnfixed
[MM6] Textures on horizontal outdoor surfaces are flipped vertically. This is default to preserve look of standard maps.

 Functions:
HookManager
( ref )
GetCurrentNPC
( )
FixVFlip
( )
[MM6] Turns off texture flip on horizontal outdoor surfaces. Note that the editor accounts for vertical flip, so you probably shouldn't call this function.


Core\ evt.lua

 Variables:
vars
Variables that are stored in saved game
mapvars
Variables stored in a saved game that belong to current map. On map refill mapvars are cleared, but old table is stored in Map.Refilled.
evt.CanShowTopic
[]
[MM7+] Functions that can return true or false to change topic visibility
evt.map
[]
Event handlers

Event indexes convention:
Indexes 20000 – 22999 are for sprite events, so that event (20000 + i) corresponds to Map.Sprites[i].
evt.hint
[]
evt.MazeInfo
[MM6]
evt.str
[]
evt.house
[]
House name used for hint
evt.Player
evt.CurrentPlayer

 Functions:
evt.InGlobal
( )
evt.ForPlayer
( n )
evt.HouseDoor
( evtId, houseId )
Here's what it does:
evt.house[evtId] = houseId
evt.map[evtId] = function()
evt.EnterHouse(houseId)
end



Core\ main.lua

 Functions:
MessageBox
( text, caption, typ )
debug.Message
( ... )
debug.ErrorMessage
( msg )
ErrorMessage
( msg )
ReloadLocalization
( )


Core\ timers.lua

 Examples:

Damage selected player every minute:
Timer(function()
evt.DamagePlayer{Damage = 1}
end, const.Minute)


Check some condition (e.g. that you killed all monsters) every 5 minutes, including the moment you enter the map:
Timer(CheckCondition, 5*const.Minute, true)


Refill a well every week on Tuesday at 3 AM:
RefillTimer(RefillWell, const.Week, const.Day + 3*const.Hour)


Make "eat" sound at 3 AM every day:
Timer(function()
evt.PlaySound(Game.Version == 8 and 144 or 211)
end, const.Day, 3*const.Hour, false)


 Variables:
Keys
[key]
Example:
Keys[const.Keys.F2] = function()
Message("F2 pressed")
end

However, using events.KeyDown is recommended instead.

 Functions:
timeGetTime
( )
Timer
( f, Period = const.Minute, [Start,] [PastAware,] [Exact] )
f = function(TriggerTime, Period, LastTick, Tick):
Function to call when the timer is triggered.
Start is Game.Time + Period if not specified (or Game.Time if PastAware = true).
PastAware = remember last visit time and fire right away if timer condition was met in the period of your absence.
If not specified, it's true if Start is specified, false otherwise.
Possible Exact values:
false: re-fires after Period passes since last invocation (this is the default if Start is not specified).
true: fires whenever (start + period*N) line is crossed (this is the default if Start is specified).
function(TriggerTime, Period, LastTick, IsInit): returns next trigger time when called.
IsInit = true if it's called by Timer function itself which happens if Start has already passed.
Note that the timer remembers last time you were in the location, so for example,
an exact weekly timer would fire right away if you haven't visited the map for a week.
RefillTimer
( f, Period = const.Day, Start )
f = function(TriggerTime, Period, LastTick, Tick):
Called when the timer is triggered.
If Start is not specified, triggers when Period passes since last time it was triggered and on map refill.
If Start is specified, acts like exact Timer, but also fires at map refills.
Sleep
( time, realtime, screens )
Sleep2
( f, time, realtime, screens )
RemoveTimer
( f )
Keys.IsPressed
( key )
Keys.IsToggled
( key )



Structures


Game

 Fields:
Version (6 – 8)
Races [MM7]
Classes
ClassKinds
Party
Map
Mouse
Weather
PatchOptions
CustomLods
WindowHandle
Windowed
CurrentPlayer
SkillRecoveryTimes[skill]
CurrentScreen
CurrentCharScreen
StatsNames[stat]
StatsDescriptions[stat]
SkillNames[skill]
SkillDescriptions[skill]
ClassNames[class]
ClassDescriptions[class]
Actions[]
NeedRedraw
StatusMessage
MouseOverStatusMessage
StatusDisappearTime
ItemsTxt[]
StdItemsTxt[]
SpcItemsTxt[]
MonstersTxt[]
PlaceMonTxt[] [MM7+]
MapStats[]
MapDoorSound[]
MapFogChances[]
MoveToMap.Pos[]
MoveToMap.X
MoveToMap.Y
MoveToMap.Z
MoveToMap.Direction 0 – 2047. 0 is East.
MoveToMap.LookAngle
MoveToMap.SpeedZ
MoveToMap.Defined
Lucida_fnt
Smallnum_fnt
Arrus_fnt
Create_fnt
Comic_fnt
Book_fnt
Book2_fnt
Cchar_fnt [MM6, MM7]
Autonote_fnt
Spell_fnt
TextBuffer
TextBuffer2
KeyCodes[]
KeyTypes[]
Time Since 00 AM, January 1st, 1165/1168/1172
Year Actual value, like 1172
Month (0 – 11)
WeekOfMonth (0 – 3)
DayOfMonth (0 – 27)
Hour (0 – 23)
Minute (0 – 59)
Second (0 – 59)
BaseYear
NeedRender Same as Party.NeedRender
TurnBased
TurnBasedPhase 1 = monsters move, 2 = combat, 3 = party walking
PlaySoundStruct
RedbookHandle
MSSHandle
BinkVideo [MM7+]
SmackVideo
EquipStat2ItemSlot[]
MonsterClassSex[] [MM7] MonClass = (Id + 2):div(3)
MonsterClassRace[] [MM7] MonClass = (Id + 2):div(3)
MonsterSex[] [MM6]
Paused checked by event timers
Paused2 checked by water damage
ShopItems[house][slot]
ShopSpecialItems[house][slot]
GuildItems[house][school][slot] In MM8 in each guild items for all 12 schools of magic are generated. In MM6 and MM7 school can only be 0.
ScanlineOffset[] [MM6, MM7]
ShopNextRefill[house]
ObjectByPixel[y][x]
ArmageddonTimeLeft maximum is 417
ArmageddonSkill damage is 50 + skill
GlobalTxt[]
Houses[] 2DEvents.txt
HouseMovies[]
TransTxt[]
SpecialEnterX[] Used for Free Haven Sewer entrances in MM6. Negative Questbit Restrictions field in 2DEvents.txt corresponds to array index
SpecialEnterY[]
SpecialEnterZ[]
SpecialEnterDirection[]
NPCTopic[]
NPCText[]
NPCGreet[][] [MM7+]
NPCGroup[] [MM7+]
NPCNews[]
HistoryTxt[] [MM7+]
NPCNewsCountByMap[] [MM6]
NPCDataTxt[]
NPC[]
Spells[]
SpellsTxt[]
QuestsTxt[]
AwardsTxt[]
AwardsSort[] [MM7+]
AutonoteTxt[]
AutonoteCategory[] [MM7+] 0 = potion
1 = stat
2 = obelisk
3 = seer
4 = misc
5 = teacher
MerchantTxt[][]
CtrlPressed
TownPortalInfo[]
TownPortalX[] Town portal picture: townport
TownPortalY[] Town portal icons [MM7+]: tpharmndy, tpelf, tpwarlock, tpisland, tpheaven, tphell
TownPortalHeight[] [MM6, MM7]
TownPortalWidth[] [MM6, MM7]
TransportLocations[]
TransportIndex[][]
HostileTxt[mon1][mon2] [MM7+] 0 – 4. Attitude of mon1 towards mon2. mon2 = 0 is party. mon1 and mon2 are monster classes: mon1 = (Id1 + 2):div(3)
NewGameMap
GlobalEvtLines[]
MapEvtLines[]
SFTBin
DecListBin[]
PFTBin[]
IFTBin[]
TFTBin[]
ChestBin[]
OverlayBin[]
ObjListBin[]
MonListBin[]
SoundsBin[]
TileBin[]
Tile2Bin[] [MM8]
Tile3Bin[] [MM8]
CurrentTileBin [MM8]
MainMenuCode -1 = in game, 1 = show new game, 6 = in new game, 3 = load menu, 4 = exit, 2 = show credits, 8 = in credits, 9 = load game
ExitLevelCode 0 = in game, 2 = load other map, 8 = death
GamesLod
IconsLod
BitmapsLod
SpritesLod
SaveGameLod
EventsLod [MM7]
RendererD3D [MM7+]
IsD3D [MM7+]
RandSeed
MonsterKinds[] [MM7+]

 Functions:
Rand ( )
SetInterfaceColor ( Color, Unk = 1 ) [MM7] 0 = good, 1 = neutral, 2 = evil
DoShowMovie ( Name, Y, DoubleSize, ExitCurrentScreen ) Only call from events.ShowMovie, use evt.ShowMovie otherwise.
CalcSpellDamage ( Spell, Skill, Mastery, MonsterHP )
GetSpellDamageType ( Spell )
GetStatisticEffect ( Stat )
EscMessage ( Text, Unk = 0 )
SummonMonster ( Id, X, Y, Z )
IsMonsterOfKind ( Id, Kind ) [MM7+]
LoadSound ( SoundId, Unk = 0 )
PlaySound ( SoundId, Object = -1, Loops = 0, X = -1, Y = 0, Unk = 0, Volume = 0, PlaybackRate = 0 )
LoadDecSprite ( Name ) Loads a sprite and returns its ID.
LoadBitmap ( Name ) Loads a texture and returns its ID.
UpdateDialogTopics ( )
ShowStatusText ( Text, Seconds = 2 )
LoadPalette ( PalNum )
LoadDataFileFromLod ( Name, UseMalloc )
LoadTextFileFromLod ( Name )


Party

 Fields:
Pos[]
X
Y
Z
Direction 0 – 2047. 0 is East.
LookAngle -512 – 512. Values allowed with mouse look: -200 – 200. Without mouse look: -128 – 128
LastX
LastY
LastZ
LastDirection
LastLookAngle
LastEyeLevel
SpeedX
SpeedY
SpeedZ
StableZ Z changes up and down while flying, StableZ stays the same
LastStandFacet
FallStartZ
Flying
PlayersArray[]
PlayersIndexes[] [MM8]
Players[] (Default)
HiredNPC[] [MM6, MM7]
LastRegenerationTime
SpellBuffs[buff]
Gold
BankGold
Food
Deaths
PritsonTerms
Fine [MM7+]
MontersHunted [MM7+]
MonsHuntTarget[] [MM7+]
MonsHuntKilled[] [MM7+]
QBits[]
AutonotesBits[]
InArenaQuest
ArenaWinsPage [MM7+]
ArenaWinsSquire [MM7+]
ArenaWinsKnight [MM7+]
ArenaWinsLord [MM7+]
ArcomageWins[] [MM7+]
ArtifactsFound[]
Alignment [MM7] 0 = good, 1 = neutral, 2 = evil
Reputation
History[] [MM7+]
CurrentPlayer
StateBits
NeedRender
Drowning
InAir
EnemyDetectorRed
EnemyDetectorYellow
FlyingBit
WaterWalkingBit
InJumpSpell
InLava

 Functions:
RestAndHeal ( )
Wait ( Minutes )
FindActivePlayer ( )
GetFame ( )
GetRepuatation ( )
AddGold ( Gold, Kind = 0 ) Kind values:
0 = increase by Banker, give some part to followers
1 = take exect amount, ignore followers
2 = [MM7+] take all and don't show message, just clear status message
3 = [MM7+] take all and don't change status message
AddKillExp ( Experience ) Experience is shared among conscious players and effected by Learning skill
HasNPCProfession ( arg1 ) [MM6, MM7]
CountItems ( {item1, item2, ...} )


Map

 Fields:
Refilled If the map has been refilled this visit, contains the last mapvars table.
Name
IndoorOrOutdoor
Monsters[]
Vars[] Variables for barrels/contests/etc events start at 75
Objects[] Items, spells effects
Sprites[]
SoundSprites[]
Chests[]
MapStatsIndex
NoNPC [MM7]
OutdoorHeader
Tilesets[]
HeightMap[y][x] [(64 - Party.Y / 0x200):round()] [(64 + Party.X / 0x200):round()] = (Party.Z / 32):floor()
TileMap[y][x] [(64 - Party.Y / 0x200):floor()] [(64 + Party.X / 0x200):floor()]
UnknownMap[][]
Models[]
IDList[] IDs of sprites on map (in ObjectRef form)
IDOffsets[y][x] OMAP – offsets in IDList
LoadedSkyBitmap
OutdoorSpawns[]
OutdoorRefillCount
OutdoorLastRefillDay First visit day
OutdoorExtra
OutdoorLastVisitTime
VisibleMap1[][]
VisibleMap2[][]
OutdoorReputation [MM7+]
TilesetsFile [MM8] 0 = dtile.bin, 1 = dtile2.bin, 2 = dtile3.bin
UnknownMap2[][] [MM8]
Notes[] [MM8]
TerNormDist[][][] [MM7+]
TerNormId[][][] [MM7+]
TerNorm[] [MM7+]
IndoorHeader
Vertexes[]
Facets[]
FacetData[]
Rooms[]
Lights[]
Doors[]
BSPNodes[]
Outlines
IndoorSpawns[]
IndoorRefillCount
IndoorLastRefillDay
IndoorExtra
IndoorLastVisitTime
VisibileOutlines[]
IndoorReputation [MM7+]
Spawns
RefillCount
LastRefillDay
LastVisitTime
Reputation
SpriteLights[] [MM7+]

 Functions:
Render ( )
IsIndoor ( )
IsOutdoor ( )
LoadTileset ( Id )
RoomFromPoint ( x, y, z )
GetFloorLevel ( x, y, z, room ) Returns FloorZ, FacetId.
GetGroundLevel ( x, y )
GetFacet ( Id )


Mouse

 Fields:
Target Use Mouse.GetTarget instead.
X
Y
Item

 Functions:
GetTarget ( )

 Methods:
SetIcon ( Icon = "MICON1" ) There are 3 special values:
"MICON1" = arrow cursor
"MICON2" = crosshair cursor for spells
"MICON3" = this cursor doesn't exist, don't use it
Other values change the picture of item carried by mouse.
RemoveItem ( ) Deletes item carried by the mouse and restores arrow cursor.
AddItem ( Item ) If there already was an item carried by the mouse, it will be taken into inventory or dropped.
ReleaseItem ( ) If there is an item carried by the mouse, it will be taken into inventory or dropped.


structs.ActionItem

 Fields:
Type
Info1
Info2


structs.BSPNode

 Fields:
FrontNode
BackNode
CoplanarOffset
CoplanarSize


structs.BaseBonus

 Fields:
Base
Bonus


structs.BaseLight

[MM7+]

 Fields:
Pos[]
X
Y
Z
Radius
R
G
B
Type


structs.BitmapsLod

 Fields:
File
FileName
Loaded
IOBuffer
IOBufferSize
LodHeaderSignature
Description
ArchivesCount
ArchivesCArray
Type
ChapterHandle
ChapterSize
Files[]
FilesOffset
Bitmaps[]
KeepCompressed [MM7+]
IsHardware [MM7+]
D3D_Surfaces[] [MM7+]
D3D_Textures[] [MM7+]

 Methods:
LoadBitmap ( )
LoadTFTBitmap ( )


structs.BlvHeader

 Fields:
Name
FacetDataSize
RoomDataSize
RoomLightDataSize
DoorDataSize


structs.CurrentTileBin

[MM8]

 Fields:
Items[] (Default)


structs.CustomLods

 Fields:
RecordIndex
Records[]

 Functions:
LoadCustomLod ( StdLod, Name )
FreeCustomLod ( Ptr )


structs.DChestItem

 Fields:
Name
Width
Height
ImageIndex


structs.DecListItem

 Fields:
Name
GameName
Type
Height
Radius
LightRadius
SFTIndex
SFTGroup
NoBlockMovement
NoDraw
FlickerSlow
FlickerMedium
FlickerFast
Marker
SlowLoop
EmitFire
SoundOnDawn
SoundOnDusk
EmitSmoke
Bits
SoundId
Red [MM7+]
Green [MM7+]
Blue [MM7+]


structs.EventLine

 Fields:
Event
Line
Offset

 Methods:
RemoveEvent ( id ) It's a method of arrays of EventLine rather than EventLine itself.
E.g. Game.MapEvtLines:RemoveEvent(100) would remove standard map event number 100, while Game.GlobalEvtLines:RemoveEvent(100) would remove standard global event number 100.
To know exactly what would be disabled by RemoveEvent method, you can look into text representations of decompiled events. For example, if you disable event 226 in OUTE3 in MM6, it will disable both standard evt.map[226] handler and events.LoadMap event handler you see after it in the decompiled Lua script. When you see an event handler not associated with a script number in decompiled scripts, it usually belongs to the event right before it.


structs.Events2DItem

 Fields:
Type
Picture
Name
OwnerName
EnterText
OwnerTitle
PictureUnk
State
Rep
Per
C
Val
A [MM7+]
OpenHour
CloseHour
ExitPic
ExitMap
QuestBitRestriction


structs.FacetData

 Fields:
FacetIndex
BitmapIndex
TFTIndex
BitmapU Bitmap U Offset
BitmapV Bitmap V Offset
Id
Event


structs.FloatVector

[MM7+]

 Fields:
1 same as X
X
2 same as Y
Y
3 same as Z
Z


structs.FogChances

 Fields:
Thick
Medium
Light


structs.GameClassKinds

 Fields:
HPBase[] [MM6, MM7]
SPBase[] [MM6, MM7]
StartingStats[][stat] [MM6]
StartingSkills[][skill] [MM6] 0 = not available, 1 = given on start, 2 = can choose on start, 3 = can learn
[MM7+] 0 = can't choose, 1 = can choose on start, 2 = given on start


structs.GameClasses

 Fields:
HPFactor[class]
SPFactor[class]
HPBase[class] [MM8]
SPBase[class] [MM8]
Skills[class][skill] [MM7+] 0 = not available, 1 = Basic, 2 = Expert, 3 = Master, 4 = GM
StartingStats[class] [MM8]
SPStats[class] 0 = no SP, 1 = Intellect, 2 = Personality, 3 = both


structs.GameRaces

[MM7]

 Fields:
StartingStats[race][stat]


structs.HistoryTxtItem

[MM7+]

 Fields:
Text
Title
Time


structs.HouseMovie

 Fields:
FileName
Background EVTPAR*, used only in MM6
NPCPic
HouseType
Sounds 30000 + Sounds*100 is the Id in Sounds.txt


structs.IFTItem

 Fields:
GroupName animation name
IconName image name in icons.lod
Time time for this frame, units in 1/16 of a second
TotalTime total time for this group
NotGroupEnd
GroupStart
Bits
IconIndex


structs.Item

 Fields:
Number
Bonus
BonusStrength
Bonus2 Value in case of gold
Charges
Identified
Broken
TemporaryBonus
Stolen
Hardened
Condition
BodyLocation
MaxCharges
Owner
BonusExpireTime [MM7+]

 Methods:
GetValue ( )
GetName ( )
GetIdentifiedName ( )
GenerateArtifact ( )
Randomize ( Strenght, Type )


structs.ItemsTxtItem

 Fields:
Picture
Name
NotIdentifiedName
Notes
Value
EquipStat Subtract 1 from const.ItemType value
Skill
Mod1DiceCount
Mod1DiceSides
Mod2
Material 0 = normal, 1 = artifact, 2 = relic, 3 = special
ChanceByLevel[]
IdRepSt
SpriteIndex
EquipX
EquipY
Bonus2 [MM7+] VarA
Bonus [MM7+] VarA
BonusStrength [MM7+] VarB


structs.LloydBeaconSlot

 Fields:
ExpireTime
Pos[]
X
Y
Z
Direction
LookAngle
Active
MapIndex
Map


structs.Lod

 Fields:
File
FileName
Loaded
IOBuffer
IOBufferSize
LodHeaderSignature
Description
ArchivesCount
ArchivesCArray
Type
ChapterHandle
ChapterSize
Files[]
FilesOffset


structs.LodBitmap

 Fields:
Name
BmpSize
DataSize
Width
Height
WidthLn2
HeightLn2
WidthMinus1
HeightMinus1
Palette
LoadedPalette
UnpackedSize
Bits
Image
ImageDiv2
ImageDiv4
ImageDiv8
Palette16
Palette24

 Methods:
LoadBitmapPalette ( )


structs.LodFile

 Fields:
Name
Offset
Size


structs.LodRecord

 Fields:
LodPtr
NamePtr Pointer passed to Load* function
Name


structs.LodSprite

 Fields:
Name
DataSize
Width
Height
Palette
YSkip
UnpackedSize
Lines[]
Buffer


structs.LodSpriteD3D

 Fields:
Name
Palette
Surface
Texture
AreaX
AreaY
BufferWidth
BufferHeight
AreaWidth
AreaHeight


structs.LodSpriteLine

 Fields:
L
R
Pos[]


structs.MapChest

 Fields:
ChestPicture 0..7 chest id
Trapped
ItemsPlaced
Identified
Bits
Items[]
Inventory[] (Items index) for main item cell, -(1 + main Inventory cell index) for other cells


structs.MapDoor

 Fields:
StartState2
SilentMove
NoSound
Stopped
Bits
Id
TimeStep time since triggered
Direction[]
DirectionX
DirectionY
DirectionZ
MoveLength
Speed2 State 3 velocity (speed*time/128 = position)
OpenSpeed State 3 velocity (speed*time/128 = position)
Speed1 State 1 velocity (speed*time/128 = position)
CloseSpeed State 1 velocity
VertexIds[]
FacetIds[]
RoomIds[]
FacetStartU[]
FacetStartV[]
VertexStartX[]
VertexStartY[]
VertexStartZ[]
State State compared with evt.SetDoorState:
0 = state (0)
1 = move to (1)
2 = state (1)
3 = move to (0)


structs.MapExtra

 Fields:
LastVisitTime
SkyBitmap
Foggy
DayBits
FogRange1
FogRange2
Raining [MM8]
Snowing [MM8]
Underwater [MM8] elemw.odm
NoTerrain [MM8] elema.odm
AlwaysDark [MM8]
AlwaysLight [MM8] elema.odm
AlwaysFoggy [MM8] elemf.odm, elemw.odm
RedFog [MM8] elemf.odm
Bits [MM8]
Ceiling [MM8]
LastWeeklyTimer
LastMonthlyTimer
LastYearlyTimer
LastDailyTimer


structs.MapFacet

 Fields:
NormalF[] [MM7+] normal float
NormalFX [MM7+] normal X float
NormalFY [MM7+] normal Y float
NormalFZ [MM7+] normal Z float
NormalFDistance [MM7+] normal distance float
Normal[] normal fixed pt (0..0x10000)
NormalX normal X fixed pt (0..0x10000)
NormalY normal Y fixed pt (0..0x10000)
NormalZ normal Z fixed pt (0..0x10000)
NormalDistance normal distance fixed pt (0..0x10000)
ZCalc1 = -(NormalX * 2^16) / NormalZ (or 0 if NormalZ is 0)
ZCalc2 = -(NormalY * 2^16) / NormalZ (or 0 if NormalZ is 0)
ZCalc3 = -(NormalDistance * 2^16) / NormalZ (or 0 if NormalZ is 0)
ScrollUp [MM7+] moving texture
TriggerByObject [MM6, MM7] happens even if there's no event assigned
IsLava
ScrollLeft [MM7+] moving texture
HasData
FlipV
AnimatedTFT
Invisible
TriggerByStep
IsSecret [MM7+] show in red with Perception
AlignLeft [MM7+] align door texture in D3D
TriggerByClick
AlternativeSound
TriggerByMonster [MM6, MM7] happens even if there's no event assigned
MoveByDoor
EventDisabledByCtrlClick [MM8]
DisableEventByCtrlClick [MM8] indoor only: click event gets disabled by Ctrl+Click
IsPortal
IsWater
IsEventJustHint [MM7+]
ScrollDown [MM7+] moving texture
IsSky outdoor in software mode: horizontal flow
Untouchable
FlipU
AlignRight [MM7+] align door texture in D3D
AlignTop [MM7+] align door texture in D3D
ScrollRight [MM7+] moving texture
AlignBottom [MM7+] align door texture in D3D
Bits
VertexIds[]
XInterceptDisplacement[]
YInterceptDisplacement[]
ZInterceptDisplacement[]
UList[]
VList[]
DataIndex
BitmapId Bitmap Index
Room Room #
RoomBehind Room # Behind facet
MinX Bounding Box Min X
MaxX Bounding Box Max X
MinY Bounding Box Min Y
MaxY Bounding Box Max Y
MinZ Bounding Box Min Z
MaxZ Bounding Box Max Z
PolygonType Polygon type:
0 = empty
1 = wall
2 = unused
3 = horizontal floor
4 = irregular floor (non-horizontal)
5 = horizontal ceiling
6 = irregular ceiling (non-horizontal)
VertexesCount


structs.MapLight

 Fields:
Pos[]
X
Y
Z
Off
Bits
Radius
R [MM7+]
G [MM7+]
B [MM7+]
Type [MM7+]
Brightness [MM7+]
Id [MM8]


structs.MapModel

 Fields:
Name
Name2
ShowOnMap
Bits
Vertexes[]
ConvexFacetsCount
Facets[]
Ordering[]
BSPNodes[]
GridX center X
GridY center Y
Pos[]
X
Y
Z
MinX Bounding MIN X
MinY Bounding MIN Y
MinZ Bounding MIN Z
MaxX Bounding MAX X
MaxY Bounding MAX Y
MaxZ Bounding MAX Z
BFMinX
BFMinY
BFMinZ
BFMaxX
BFMaxY
BFMaxZ
BoxCenterX Bounding center X
BoxCenterY Bounding center Y
BoxCenterZ Bounding center Z
BoundingRadius


structs.MapMonster

 Fields:
Name [MM6]
NPC_ID
ShowOnMap monster was once seen by party
OnAlertMap
Active ?inside the active radius?
ShowAsHostile show as hostile on map
Hostile
TreasureGenerated treasure is in Items[0] and Items[1], gold is in Items[3]
Invisible
IsObeliskChest [MM8]
NoFlee
Bits
HP
HitPoints
Id Changing may cause random crashes after loading the game! Be careful.
Level
TreasureItemPercent
TreasureDiceCount
TreasureDiceSides
TreasureItemLevel
TreasureItemType
Fly
MoveType
AIType
HostileType
Prefers.Vampire [MM8]
Prefers.Troll [MM8]
Prefers.Monk [MM7]
Prefers.Thief [MM7]
Prefers.Cleric
Prefers.Male
Prefers.Sorcerer [MM6, MM7]
Prefers.Female
Prefers.Dragon [MM8]
Prefers.Minotaur [MM8]
Prefers.DarkElf [MM8]
Prefers.Necro [MM8]
Prefers.Goblin [MM7]
Prefers.Archer [MM6, MM7]
Prefers.Paladin [MM6, MM7]
Prefers.Druid [MM6, MM7]
Prefers.Dwarf [MM7]
Prefers.Ranger [MM7]
Prefers.Elf [MM7]
Prefers.Human [MM7]
Prefers.Knight
PrefClass Preferred target
Bonus (steal, curse, ...)
BonusMul (Disease1x5 etc. I wish I knew what it means)
Attack1
Attack2Chance
Attack2
SpellChance
Spell
Spell2Chance [MM7+]
Spell2 [MM7+]
SpellSkill
Resistances[kind] For immunity use const.MonsterImmune
FireResistance
AirResistance [MM7+]
WaterResistance [MM7+]
EarthResistance [MM7+]
MindResistance [MM7+]
SpiritResistance [MM7+]
BodyResistance [MM7+]
LightResistance [MM7+]
DarkResistance [MM7+]
ColdResistance [MM6]
ElecResistance [MM6]
PoisonResistance [MM6]
PhysResistance
Special [MM7+] {shot, summon, explode}
SpecialA [MM7+] shot: C = count
summon: A = {RandomLevel = 0, fixed = 1} – monster level (0 means A, B or C is chosen randomly, monster index should be that of A variation. Values of 2 and 3 are the same as 1, but in MM7 before GrayFace Patch v2.1 it was causing a bug), B = {ground = 0, air = 1}, C = already summoned count (up to 3), D = monster index
explode: AdB + C, D = attack type
SpecialB [MM7+]
SpecialC [MM7+]
MagicResistance [MM6]
PrefNum Number of party members to hit using Attack1 & Attack2
BloodSplat [MM7+]
Spell2Skill [MM7+]
SpecialD [MM7+] (summoned monster or damage type in case of explosive attack)
QuestItem [MM6]
FullHP
FullHitPoints
ArmorClass
Exp
Experience
MoveSpeed
AttackRecovery
RangeAttack
Id2
BodyRadius
BodyHeight
Velocity
Pos[]
X
Y
Z
VelocityX
VelocityY
VelocityZ
Direction
LookAngle
Room
CurrentActionLength
StartX
StartY
StartZ
GuardX
GuardY
GuardZ
GuardRadius
AIState
GraphicState
Item
CurrentActionStep
Frames[]
FramesStand
FramesWalk
FramesAttack
FramesShoot
FramesStun
FramesDie
FramesDead
FramesFidget
Sounds[]
SoundAttack
SoundDie
SoundGetHit
SoundFidget
SpellBuffs[buff]
Items[] [MM7+]
Group
Ally Monster class that guards or is guraded by this one. That is, (Id + 2):div(3), like in Hostile.txt.
Schedules[]
Summoner
LastAttacker last one who hit the monster
NameId

 Methods:
LoadFrames ( SoundLoaded = false ) If SoundLoaded = false, sound indexes would be loaded for the monster as well.
LoadFramesAndSounds ( )
ChangeLook ( )
GetPropertiesFromId ( )
SetId ( )
SetCustomFrames ( )


structs.MapNote

[MM8]

 Fields:
Active
X
Y
Text
Id


structs.MapObject

 Fields:
Type look type (see Id in dobjlist.bin)
TypeIndex line in dobjlist.bin
Pos[]
X
Y
Z
Velocity[]
VelocityX
VelocityY
VelocityZ
Direction
LookAngle
Visible
Temporary
HaltTurnBased
DroppedByPlayer
IgnoreRange
NoZBuffer
SkipAFrame
AttachToHead
Missile
Removed
Bits
Room
Age
MaxAge
LightMultiplier
Item
SpellType
SpellSkill
SpellLevel
SpellEffect [MM7+]
Owner
Target
Range Distance to target: 0 – less than 307.2, 1 – less than 1024, 2 – less then 2560, 3 – 2560 or more
AttackType 0 – Attack1, 1 – Attack2, 2 – Spell, 3 – Spell2
StartPos[]
StartX starting x
StartY starting y
StartZ starting z


structs.MapOutline

 Fields:
Vertex1
Vertex2
Facet1
Facet2
Z
Visible
Bits


structs.MapOutlines

 Fields:
Items[] (Default)


structs.MapRoom

 Fields:
HasBSP
Bits
EaxEnvironment [MM8]
Floors[]
Walls[]
Ceils[]
Fluids[]
Portals[]
NonBSPDrawFacetsCount # of non-BSP Node facets to draw
DrawFacets[] drawing order
Cogs[]
Sprites[]
Markers[]
Lights[]
Darkness Min Ambient Light Level
FirstBSPNode First BSP Node Index
ExitTag
MinX Bounding Box Min X
MaxX Bounding Box Max X
MinY Bounding Box Min Y
MaxY Bounding Box Max Y
MinZ Bounding Box Min Z
MaxZ Bounding Box Max Z


structs.MapSprite

 Fields:
DecListId
DecName
ShowOnMap
TriggerByMonster triggered when a monster comes into TriggerRadius
Invisible
IsObeliskChest
TriggerByObject triggered when an object gets into TriggerRadius
TriggerByTouch triggered when a player comes into TriggerRadius
IsChest
Bits
Pos[]
X
Y
Z
Direction
Id [MM7+]
EventVariable event variable for barrels etc.
Event normal event
TriggerRadius


structs.MapStatsItem

 Fields:
Name
FileName
Monster1Pic
Monster2Pic
Monster3Pic
ResetCount
FirstVisitDay
RefillDays
AlertDays [MM7+]
StealPerm [MM7+]
Per [MM7+]
Lock x5Lock
Trap D20sTrap
Tres
EncounterChance
EncounterChanceM1
EncounterChanceM2
EncounterChanceM3
Mon1Dif
Mon1Low
Mon1Hi
Mon2Dif
Mon2Low
Mon2Hi
Mon3Dif
Mon3Low
Mon3Hi
RedbookTrack
EaxEnvironments [MM7+]


structs.MapVertex

 Fields:
1 same as X
X
2 same as Y
Y
3 same as Z
Z


structs.ModelFacet

 Fields:
Normal[] normal fixed pt (0..0x10000)
NormalX normal X fixed pt (0..0x10000)
NormalY normal Y fixed pt (0..0x10000)
NormalZ normal Z fixed pt (0..0x10000)
NormalDistance normal distance fixed pt (0..0x10000)
ZCalc1 = -(NormalX * 2^16) / NormalZ (or 0 if NormalZ is 0)
ZCalc2 = -(NormalY * 2^16) / NormalZ (or 0 if NormalZ is 0)
ZCalc3 = -(NormalDistance * 2^16) / NormalZ (or 0 if NormalZ is 0)
ScrollUp [MM7+] moving texture
TriggerByObject [MM6, MM7] happens even if there's no event assigned
IsLava
ScrollLeft [MM7+] moving texture
HasData
FlipV
AnimatedTFT
Invisible
TriggerByStep
IsSecret [MM7+] show in red with Perception
AlignLeft [MM7+] align door texture in D3D
TriggerByClick
AlternativeSound
TriggerByMonster [MM6, MM7] happens even if there's no event assigned
MoveByDoor
EventDisabledByCtrlClick [MM8]
DisableEventByCtrlClick [MM8] indoor only: click event gets disabled by Ctrl+Click
IsPortal
IsWater
IsEventJustHint [MM7+]
ScrollDown [MM7+] moving texture
IsSky outdoor in software mode: horizontal flow
Untouchable
FlipU
AlignRight [MM7+] align door texture in D3D
AlignTop [MM7+] align door texture in D3D
ScrollRight [MM7+] moving texture
AlignBottom [MM7+] align door texture in D3D
Bits
VertexIds[]
UList[]
VList[]
XInterceptDisplacement[]
YInterceptDisplacement[]
ZInterceptDisplacement[]
BitmapId
BitmapU
BitmapV
MinX Bounding Box Min X
MaxX Bounding Box Max X
MinY Bounding Box Min Y
MaxY Bounding Box Max Y
MinZ Bounding Box Min Z
MaxZ Bounding Box Max Z
Id
Event
GradientVertexes[]
VertexesCount
PolygonType Polygon type:
0 = empty
1 = wall
2 = unused
3 = horizontal floor
4 = irregular floor (non-horizontal)
5 = horizontal ceiling
6 = irregular ceiling (non-horizontal)


structs.ModelVertex

 Fields:
1 same as X
X
2 same as Y
Y
3 same as Z
Z


structs.MonListItem

 Fields:
Height
Radius overall monster radius
Velocity
Radius2 [MM7+] monster radius for "to-hit" purposes
Tint [MM7+] tint color for graphic
TintB [MM7+]
TintG [MM7+]
TintR [MM7+]
TintA [MM7+]
Sounds[]
SoundAttack
SoundDie
SoundGetHit
SoundFidget
Name
FrameNames[]
FramesStand
FramesWalk
FramesAttack
FramesShoot
FramesStun
FramesDie
FramesDead
FramesFidget


structs.MonsterAttackInfo

 Fields:
Type
DamageDiceCount
DamageDiceSides
DamageAdd
Missile


structs.MonsterKind

[MM7+]

 Fields:
Undead
Demon [MM7]
Dragon
Elf [MM7]
Swimmer
Immobile
Peasant [MM8]
Titan [MM7]
NoArena
Ogre [MM8]
Elemental [MM8]


structs.MonsterSchedule

 Fields:
Pos[]
X
Y
Z
Bits (1 – on)
Action
Hour
Day
Month


structs.MonstersTxtItem

 Fields:
Name
Picture
Id Changing may cause random crashes after loading the game! Be careful.
Level
TreasureItemPercent
TreasureDiceCount
TreasureDiceSides
TreasureItemLevel
TreasureItemType
Fly
MoveType
AIType
HostileType
Prefers.Vampire [MM8]
Prefers.Troll [MM8]
Prefers.Monk [MM7]
Prefers.Thief [MM7]
Prefers.Cleric
Prefers.Male
Prefers.Sorcerer [MM6, MM7]
Prefers.Female
Prefers.Dragon [MM8]
Prefers.Minotaur [MM8]
Prefers.DarkElf [MM8]
Prefers.Necro [MM8]
Prefers.Goblin [MM7]
Prefers.Archer [MM6, MM7]
Prefers.Paladin [MM6, MM7]
Prefers.Druid [MM6, MM7]
Prefers.Dwarf [MM7]
Prefers.Ranger [MM7]
Prefers.Elf [MM7]
Prefers.Human [MM7]
Prefers.Knight
PrefClass Preferred target
Bonus (steal, curse, ...)
BonusMul (Disease1x5 etc. I wish I knew what it means)
Attack1
Attack2Chance
Attack2
SpellChance
Spell
Spell2Chance [MM7+]
Spell2 [MM7+]
SpellSkill
Resistances[kind] For immunity use const.MonsterImmune
FireResistance
AirResistance [MM7+]
WaterResistance [MM7+]
EarthResistance [MM7+]
MindResistance [MM7+]
SpiritResistance [MM7+]
BodyResistance [MM7+]
LightResistance [MM7+]
DarkResistance [MM7+]
ColdResistance [MM6]
ElecResistance [MM6]
PoisonResistance [MM6]
PhysResistance
Special [MM7+] {shot, summon, explode}
SpecialA [MM7+] shot: C = count
summon: A = {RandomLevel = 0, fixed = 1} – monster level (0 means A, B or C is chosen randomly, monster index should be that of A variation. Values of 2 and 3 are the same as 1, but in MM7 before GrayFace Patch v2.1 it was causing a bug), B = {ground = 0, air = 1}, C = already summoned count (up to 3), D = monster index
explode: AdB + C, D = attack type
SpecialB [MM7+]
SpecialC [MM7+]
MagicResistance [MM6]
PrefNum Number of party members to hit using Attack1 & Attack2
BloodSplat [MM7+]
Spell2Skill [MM7+]
SpecialD [MM7+] (summoned monster or damage type in case of explosive attack)
QuestItem [MM6]
FullHP
FullHitPoints
ArmorClass
Exp
Experience
MoveSpeed
AttackRecovery


structs.NPC

 Fields:
Name
Pic
Hired
Bits
Fame
Rep
House
Profession
Greet [MM7+]
Joins
TellsNews
Events[]
EventA
EventB
EventC
EventD [MM7+]
EventE [MM7+]
EventF [MM7+]
Sex
UsedSpell
NewsTopic


structs.NPCNewsItem

[MM6]

 Fields:
Topic
Text
Map


structs.ObjListItem

 Fields:
Name
Id
Radius
Height
Invisible
Untouchable
Temporary
LifetimeInSFT
NoPickup
NoGravity
InterceptAction
Bounce
TrailParticles
TrailFire
TrailLine
Bits
SFTIndex
SFTGroup
LifeTime
LoadedParticlesColor munged 16-bit color
Speed default speed of object
ParticlesColor[] color for particles
ParticleR
ParticleG
ParticleB
ParticleA [MM7+]


structs.ObjectRef

 Fields:
ZBuf
Value raw value, in inventory screen this is item index
Kind
Index

 Methods:
Get ( )


structs.OdmHeader

 Fields:
Name
FileName
VersionStr
TilesetsFile [MM8] 0 = dtile.bin, 1 = dtile2.bin, 2 = dtile3.bin
Tilesets[]
Bits [MM8]


structs.OverlayItem

 Fields:
Id
Type
SFTIndex
SFTGroup


structs.PFTItem

 Fields:
GroupId
FrameIndex
Time time for this frame in 1/32 of a second
TotalTime total time for this group
NotGroupEnd
GroupStart
Bits


structs.PatchOptions

 Fields:
Size
MaxMLookAngle
MouseLook
MouseLookUseAltMode
CapsLockToggleMouseLook
MouseFly
MouseWheelFly
MouseLookTempKey
MouseLookChangeKey
InventoryKey
CharScreenKey
DoubleSpeedKey
QuickLoadKey
AutorunKey
HDWTRCount [MM7+]
HDWTRDelay [MM7+]
HorsemanSpeakTime
BoatmanSpeakTime
PaletteSMul [MM7+]
PaletteVMul [MM7+]
NoBitmapsHwl [MM7+]
PlayMP3
MusicLoopsCount
HardenArtifacts [MM7+]
ProgressiveDaggerTrippleDamage
FixChests
DataFiles
FixDualWeaponsRecovery [MM6]
IncreaseRecoveryRateStrength [MM6]
BlasterRecovery [MM6, MM7]
FixSkyBitmap [MM8]
NoCD
FixChestsByReorder
LastLoadedFileSize
FixTimers
FixMovement
MonsterJumpDownLimit
FixHeroismPedestal [MM8]
SkipUnsellableItemCheck [MM7]
FixGMStaff [MM7]
FixObelisks [MM8]
BorderlessWindowed
CompatibleMovieRender
SmoothMovieScaling
SupportTrueColor
RenderRectLeft
RenderRectTop
RenderRectRight
RenderRectBottom

 Functions:
Present ( name ) Returns true if the option is supported by patch version being used


structs.Player

 Fields:
Biography [MM8]
Sex [MM6, MM7]
Conditions[cond]
Exp
Experience
Name
Class
Face
Stats[stat]
MightBase
MightBonus
IntellectBase
IntellectBonus
PersonalityBase
PersonalityBonus
EnduranceBase
EnduranceBonus
SpeedBase
SpeedBonus
AccuracyBase
AccuracyBonus
LuckBase
LuckBonus
ArmorClassBonus
LevelBase
LevelBonus
AgeBonus
Skills[skill]
Awards[]
Spells[]
UsedBlackPotions[]
Items[]
Inventory[] (Items index) for main item cell, -(1 + main Inventory cell index) for other cells
Resistances[kind]
FireResistanceBase
AirResistanceBase [MM7+]
WaterResistanceBase [MM7+]
EarthResistanceBase [MM7+]
SpiritResistanceBase [MM7+]
MindResistanceBase [MM7+]
BodyResistanceBase [MM7+]
FireResistanceBonus
AirResistanceBonus [MM7+]
WaterResistanceBonus [MM7+]
EarthResistanceBonus [MM7+]
SpiritResistanceBonus [MM7+]
MindResistanceBonus [MM7+]
BodyResistanceBonus [MM7+]
Voice [MM7+]
ColdResistanceBase [MM6]
ColdResistanceBonus [MM6]
ElecResistanceBase [MM6]
ElecResistanceBonus [MM6]
PoisonResistanceBase [MM6]
PoisonResistanceBonus [MM6]
MagicResistanceBase [MM6]
MagicResistanceBonus [MM6]
SpellBuffs[buff]
RecoveryDelay
SkillPoints
HP
HitPoints
SP
SpellPoints
BirthYear
EquippedItems[slot]
ItemExtraHand
ItemMainHand
ItemBow
ItemArmor
ItemHelm
ItemBelt
ItemCloak
ItemGountlets
ItemBoots
ItemAmulet
ItemRing1
ItemRing2
ItemRing3
ItemRing4
ItemRing5
ItemRing6
SpellBookPage
QuickSpell
PlayerBits[]
RosterBitIndex [MM8]
MeleeAttackBonus [MM6, MM7]
MeleeDamageBonus [MM6, MM7]
RangedAttackBonus [MM6, MM7]
RangedDamageBonus [MM6, MM7]
FullHPBonus [MM6, MM7]
FullHitPointsBonus [MM6, MM7]
FullSPBonus [MM6, MM7]
FullSpellPointsBonus [MM6, MM7]
Expression
ExpressionTimePassed
ExpressionLength
Beacons[]
DevineInterventionCasts
ArmageddonCasts
FireSpikeCasts [MM7+]

 Methods:
GetSex ( BasedOnVoice = false ) [MM8] Determines sex based on Face or Voice
GetBaseMight ( )
GetBaseIntellect ( )
GetBasePersonality ( )
GetBaseEndurance ( )
GetBaseAccuracy ( )
GetBaseSpeed ( )
GetBaseLuck ( )
GetBaseLevel ( )
GetLevel ( )
GetMight ( )
GetIntellect ( )
GetPersonality ( )
GetEndurance ( )
GetAccuracy ( )
GetSpeed ( )
GetLuck ( )
GetMeleeAttack ( IgnoreExtraHand [MM7+] = false )
CalcMeleeDamage ( JustWeaponDamage = false, IgnoreExtraHand = false, MonsterId = -1 )
GetRangedAttack ( )
CalcRangedDamage ( MonsterId = -1 )
GetMeleeDamageRangeText ( )
GetRangedDamageRangeText ( )
CanTrain ( )
AddHP ( Amount )
DoDamage ( Damage, DamageKind = const.Damage.Phys )
DoBadThing ( Thing )
GetAttackDelay ( Shoot = false )
GetFullHP ( )
GetFullSP ( )
GetMeleeDamageMin ( ) [MM7+]
GetMeleeDamageMax ( ) [MM7+]
GetRangedDamageMin ( ) [MM7+]
GetRangedDamageMax ( ) [MM7+]
HasItemBonus ( ) [MM7+]
WearsItem ( ) [MM7+]
GetBaseResistance ( arg1 ) [MM7+]
GetResistance ( arg1 ) [MM7+]
GetBaseFireResistance ( ) [MM6]
GetBaseElectricityResistance ( ) [MM6]
GetBaseColdResistance ( ) [MM6]
GetBasePoisonResistance ( ) [MM6]
GetBaseMagicResistance ( ) [MM6]
GetFireResistance ( ) [MM6]
GetElectricityResistance ( ) [MM6]
GetColdResistance ( ) [MM6]
GetPoisonResistance ( ) [MM6]
GetMagicResistance ( ) [MM6]
GetBaseArmorClass ( )
GetArmorClass ( )
GetBaseAge ( )
GetAge ( )
Recover ( )
SetRecoveryDelay ( Delay )
GetMainCondition ( )
CalcStatBonusByItems ( Stat, IgnoreExtraHand [MM7+] = false )
CalcStatBonusByMagic ( Stat )
CalcStatBonusBySkills ( Stat )
GetMerchantTotalSkill ( )
GetDisarmTrapTotalSkill ( )
ShowFaceExpression ( Expression, Time = 0 )
GetSkill ( arg1 ) [MM7+]
ShowFaceAnimation ( Animation ) [MM7+]
GetPerceptionTotalSkill ( ) [MM7+]
GetLearningTotalSkill ( ) [MM7+]
GetRace ( ) [MM7]
GetDiplomacyTotalSkill ( ) [MM6]
EnumActiveItems ( )
CountItems ( {item1, item2, ...} )


structs.SFT

 Fields:
MatchIndex used when searching for a group by name
Frames[] (Default)
Groups[][] sorted by name
GroupIndex[]

 Methods:
FindGroup ( arg1 = "" )
LoadGroup ( arg1 )


structs.SFTItem

 Fields:
GroupName
SpriteName
SpriteIndex[] loaded from sprite list at runtime, chosen based on sprite orientation
Scale
NotGroupEnd
Luminous
GroupStart
Image1 has 1 image (not 8 for different angles)
Center center sprite
Fidget part of monster figet sequence
Loaded group is loaded
Mirror0
Mirror1
Mirror2
Mirror3
Mirror4
Mirror5
Mirror6
Mirror7
Images3 only views 0,2,4 exist (mirrored)
Glow
Transparent
Bits
LightRadius
PaletteId
PaletteIndex palette index (0 if not loaded)
Time time for this frame in 1/32 of a second
TotalTime total time for this group


structs.SoundsItem

 Fields:
Name name of sound file
Id
Type type of sound
0 = (0) level specific sound, load during level initialization
1 = (system) system sound, always loaded
2 = (swap) level specific sound, that gets loaded and flushed
3 = (?)
4 = (lock) delete sound only when game ends
Locked
Is3D [MM7+]
Bits
Data[] data pointer
Data3D [MM7+] 3d data pointer
Decompressed [MM7+] true if decompressed and needs to be freed separately


structs.SpawnPoint

 Fields:
Pos[]
X
Y
Z
Radius
Kind
Index Index: monster (1-3: M1-M3, 4-6: M1a-M1c, 7-9: M2a-M2c, 10-12: M3a-M3c) or item (1-6)
OnAlertMap
Bits
Group [MM7+]


structs.SpcItemsTxtItem

 Fields:
NameAdd
BonusStat
ChanceForSlot[]
W1
W2
Miss
Arm
Shld
Helm
Belt
Cape
Gaunt
Boot
Ring
Amul
Value
Lvl


structs.SpellBuff

 Fields:
ExpireTime
Power
Skill
OverlayId
Caster
Bits


structs.SpellEffect

[MM7+]

 Fields:


structs.SpellInfo

 Fields:
CastByMonster [MM7+]
CastByEvent [MM7+]
CauseDamage [MM7+]
SpecialDamage [MM7+]
Bits "Stats" from spells.txt
SpellPoints[]
SpellPointsNormal
SpellPointsExpert
SpellPointsMaster
SpellPointsGM [MM7+]
Delay[]
DelayNormal
DelayExpert
DelayMaster
DelayGM [MM7+]
DamageAdd [MM7+]
DamageDiceSides [MM7+]


structs.SpellsTxtItem

 Fields:
Name
ShortName
Description
Normal
Expert
Master
GM [MM7+]
GrandMaster [MM7+]
DamageType
SpellPoints[]
SpellPointsNormal
SpellPointsExpert
SpellPointsMaster
SpellPointsGM [MM7+]


structs.SpritesLod

 Fields:
File
FileName
Loaded
IOBuffer
IOBufferSize
LodHeaderSignature
Description
ArchivesCount
ArchivesCArray
Type
ChapterHandle
ChapterSize
Files[]
FilesOffset
SpritesSW[]
IsHardware
SpritesD3D[]

 Methods:
LoadSprite ( )


structs.StartStat

[MM7+]

 Fields:
Base
Max
Spend how much you spend on it to add a point
Add how much is added when you spend a point


structs.StdItemsTxtItem

 Fields:
NameAdd
BonusStat
ChanceForSlot[]
Arm
Shld
Helm
Belt
Cape
Gaunt
Boot
Ring
Amul


structs.TFTItem

 Fields:
Name texture name
Index index in bitmaps.lod
Time time for this frame in 1/32 of a second
TotalTime total time for this group
NotGroupEnd
GroupStart
Bits


structs.TileItem

 Fields:
Name
Id
Bitmap
TileSet
Section
Burn
Water
Block
Repulse
Flat
Wave
NoDraw
WaterTransition
Transition
ScrollDown
ScrollUp
ScrollLeft
ScrollRight
Bits


structs.TilesetDef

 Fields:
Group
Offset


structs.TownPortalTownInfo

 Fields:
Pos[]
X
Y
Z
Direction
LookAngle
MapStatsIndex
MapIndex [MM6]
Map


structs.TravelInfo

 Fields:
MapIndex
DaysAvailable[]
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
DaysCount
Pos[]
X
Y
Z
Direction
QBit
Map


structs.Weather

 Fields:
Snow [MM6]
Shade 0 = sunny, 1 = dark, 2 = misty
Fog
FogRange1
FogRange2

 Functions:
SetFog ( Range1, Range2 )
RandomFog ( LightChance, MiddleChance, ThickChance )
New ( )



Constants


const.*

 Values:
Novice = 1
Expert = 2
Master = 3
GM = 4 [MM7+]
Minute = 256
Hour = 15360
Day = 368640
Week = 2580480
Month = 10321920
Year = 123863040
MonsterImmune
MapLimit = 22528


const.AIState

 Values:
Stand = 0
Active = 1
MeleeAttack = 2
RangedAttack = 3
Dying = 4
Dead = 5
Pursue = 6
Flee = 7
Stunned = 8
Fidget = 9
Interact = 10
Removed = 11
RangedAttack2 = 12
CastSpell = 13
Stoned = 14
Paralyzed = 15
Resurrect = 16
Summoned = 17
RangedAttack4 = 18
Invisible = 19


const.ChestBits

 Values:
Trapped = 1
ItemsPlaced = 2
Identified = 4


const.Class

 Values:
Necromancer = 0 [MM8]
Knight
Cavalier = 1 [MM6, MM7]
Champion
BlackKnight = 3 [MM7]
Thief = 4 [MM7]
Rogue = 5 [MM7]
Spy = 6 [MM7]
Assassin = 7 [MM7]
Monk = 8 [MM7]
Initiate = 9 [MM7]
Master = 10 [MM7]
Ninja = 11 [MM7]
Cleric
Priest [MM6, MM7]
HighPriest = 5 [MM6]
Sorcerer [MM6, MM7]
Wizard [MM6, MM7]
ArchMage [MM6, MM7]
Paladin [MM6, MM7]
Crusader [MM6, MM7]
Hero [MM6, MM7]
Villain = 15 [MM7]
Archer [MM6, MM7]
BattleMage = 13 [MM6]
WarriorMage [MM6, MM7]
MasterArcher = 18 [MM7]
Sniper = 19 [MM7]
Ranger = 20 [MM7]
Hunter = 21 [MM7]
RangerLord = 22 [MM7]
BountyHunter = 23 [MM7]
PriestLight [MM7+]
PriestDark = 27 [MM7]
Druid [MM6, MM7]
GreatDruid [MM6, MM7]
ArchDruid [MM6, MM7]
Warlock = 31 [MM7]
Lich [MM7+]
Troll = 6 [MM8]
WarTroll = 7 [MM8]
Minotaur = 8 [MM8]
MinotaurLord = 9 [MM8]
DarkElf = 10 [MM8]
Patriarch = 11 [MM8]
Vampire = 12 [MM8]
Nosferatu = 13 [MM8]
Dragon = 14 [MM8]
GreatWyrm = 15 [MM8]


const.Condition

 Values:
Cursed = 0
Weak = 1
Asleep = 2
Afraid = 3
Drunk = 4
Insane = 5
Poison1 = 6
Disease1 = 7
Poison2 = 8
Disease2 = 9
Poison3 = 10
Disease3 = 11
Paralyzed = 12
Unconscious = 13
Dead = 14
Stoned = 15
Eradicated = 16
Zombie = 17 [MM7+]


const.Damage

 Values:
Phys
Magic
Fire
Air = 1 [MM7+]
Water = 2 [MM7+]
Earth = 3 [MM7+]
Spirit = 6 [MM7+]
Mind = 7 [MM7+]
Body = 8 [MM7+]
Light = 9 [MM7+]
Dark = 10 [MM7+]
Dragon = 50 [MM7+]
Elec = 3 [MM6]
Cold = 4 [MM6]
Poison = 5 [MM6]
Energy = 6 [MM6]


const.FaceAnimation

 Values:
KillSmallEnemy = 1
KillBigEnemy = 2
StoreClosed = 3
DisarmTrap = 4
TrapWillBlow = 5 it's gonna blow!
AvoidTrapDamage = 6 sit down
IdentifyUseless = 7
IdentifyGreat = 8
IdentifyFail = 9
RepairItem = 10
RepairFail = 11
SetQuickSpell = 12
CantRestHere = 13
SmileRandom = 14
CantCarry = 15
MixPotion = 16
PotionExplode = 17
DoorLocked = 18
Strain = 19 like pulling sword out of stone in MM6
CantLearnSpell = 20
LearnSpell = 21
Hello = 22
HelloNight = 23
Damaged = 24
Weak = 25
Afraid = 26
Poisoned = 27
Deseased = 28
Insane = 29
Cursed = 30
Drunk = 31
Unconsious = 32
Death = 33
Stoned = 34
Eradicated = 35
Smile = 36
ReadScoll = 37
NotEnoughGold = 38
CantEquip = 39
ItemBrokenStolen = 40
SPDrained = 41
Aged = 42
SpellFailed = 43
DamagedParty = 44
Tired = 45
EnterDungeon = 46 come on let's go in
LeaveDungeon = 47 let's get out of here
AlmostDead = 48
CastSpell = 49
Shoot = 50
AttackHit = 51
AttackMiss = 52
Beg = 53
BegFail = 54
ThreatFail = 56
SmileHuge = 57
BribeFail = 58
NPCDontTalk = 59
SmileRandom2 = 60
LookUp = 63
LookDown = 64
Yell = 65
Falling = 66
ShakeHeadNo = 67 shakes head
TavernGotDrunk = 69
TavernTip = 70
ShakeHeadYes = 71
ShopIdentify = 73
ShopRepair = 74
ShopAlreadyIdentified = 76
ShopWrongShop = 79
ShopRude = 80
BankDeposit = 81
SmileBig = 82
TempleDonate = 83
HelloHouse = 84
AfraidSilent = 98
InPrison = 100
ChooseMe = 102
Awaken = 103
IdMonsterWeak = 104
IdMonsterBig = 105
IdMonsterFail = 106
LastManStanding = 107
Hungry = 108


const.FacetBits

 Values:
IsPortal = 0x1
IsSecret = 0x2 [MM7+] show in red with Perception
ScrollDown = 0x4 [MM7+] moving texture
AlignTop = 0x8 [MM7+] align door texture in D3D
IsWater = 0x10
ScrollUp = 0x20 [MM7+] moving texture
ScrollLeft = 0x40 [MM7+] moving texture
ScrollRight = 0x800 [MM7+] moving texture
AlignLeft = 0x1000 [MM7+] align door texture in D3D
Invisible = 0x2000
AnimatedTFT = 0x4000
AlignRight = 0x8000 [MM7+] align door texture in D3D
AlignBottom = 0x20000 [MM7+] align door texture in D3D
MoveByDoor = 0x40000
IsEventJustHint = 0x100000 [MM7+]
AlternativeSound = 0x200000
IsSky = 0x400000 outdoor in software mode: horizontal flow
FlipU = 0x800000
FlipV = 0x1000000
TriggerByClick = 0x2000000
TriggerByStep = 0x4000000
DisableEventByCtrlClick = 0x8000000 [MM8] indoor only: click event gets disabled by Ctrl+Click
EventDisabledByCtrlClick = 0x10000000 [MM8]
TriggerByMonster = 0x8000000 [MM6, MM7] happens even if there's no event assigned
TriggerByObject = 0x10000000 [MM6, MM7] happens even if there's no event assigned
Untouchable = 0x20000000
IsLava = 0x40000000
HasData = 0x80000000


const.GameActions

 Values:
Exit = 113


const.HouseType

 Values:
Weapon Shop = 1
Armor Shop = 2
Magic Shop = 3
Alchemist = 4 [MM7+]
General Store = 4 [MM6]
Fire Guild = 5
Air Guild = 6
Water Guild = 7
Earth Guild = 8
Spirit Guild = 9
Mind Guild = 10
Body Guild = 11
Light Guild = 12
Dark Guild = 13
Elemental Guild = 14 [MM7+]
Element Guild = 14 [MM6]
Self Guild = 15
Thieves Guild = 17 [MM6]
Merc Guild = 18
Town Hall
Throne = 20
Tavern = 21
Bank = 22
Temple = 23
Castle Entrance = 24
Dungeon Ent = 25
Seer = 26
Stables = 27
Boats = 28
House = 29
Training = 30
Jail = 31
Circus = 32
The Adventurer's Inn = 35


const.ItemSlot

 Values:
ExtraHand = 0
MainHand = 1
Bow = 2
Armor = 3
Helm = 4
Belt = 5
Cloak = 6
Gountlets = 7
Boots = 8
Amulet = 9
Ring1 = 10
Ring2 = 11
Ring3 = 12
Ring4 = 13
Ring5 = 14
Ring6 = 15


const.ItemType

 Values:
Any = 0
Weapon = 1
Weapon2H = 2
Missile = 3
Armor = 4
Shield = 5
Helm = 6
Belt = 7
Cloak = 8
Gountlets = 9
Boots = 10
Ring = 11
Amulet = 12
Wand = 13 weaponw
Scroll = 16 sscroll
Book = 17
MScroll = 18 always creates item 001
Weapon_ = 20
Armor_ = 21
Misc = 22
Sword = 23
Dagger = 24
Axe = 25
Spear = 26
Bow = 27
Mace = 28
Club = 29
Staff = 30
Leather = 31
Chain = 32
Plate = 33
Shield_ = 34
Helm_ = 35
Belt_ = 36
Cloak_ = 37
Gountlets_ = 38
Boots_ = 39
Ring_ = 40
Amulet_ = 41
Wand_ = 42
Scroll_ = 43
Potion = 44 bottle
Reagent = 45 herb
Gems = 46
Gems2 = 47
Gold = 50


const.Keys

 Values:
LBUTTON = 1
RBUTTON = 2
CANCEL = 3
MBUTTON = 4 NOT contiguous with L & RBUTTON
XBUTTON1 = 5
XBUTTON2 = 6
BACK = 8
BACKSPACE = 8
TAB = 9
CLEAR = 12
RETURN = 13
SHIFT = 16
CONTROL = 17
CTRL = 17
ALT = 18
MENU = 18
PAUSE = 19
CAPITAL = 20
CAPSLOCK = 20
HANGUL = 21
KANA = 21
JUNJA = 23
FINAL = 24
HANJA = 25
KANJI = 25
ESCAPE = 27
CONVERT = 28
NONCONVERT = 29
ACCEPT = 30
MODECHANGE = 31
SPACE = 32
PGUP = 33
PRIOR = 33
NEXT = 34
PGDN = 34
END = 35
HOME = 36
LEFT = 37
UP = 38
RIGHT = 39
DOWN = 40
SELECT = 41
PRINT = 42
EXECUTE = 43
SNAPSHOT = 44
INSERT = 45
DELETE = 46
HELP = 47
0 = 48
1 = 49
2 = 50
3 = 51
4 = 52
5 = 53
6 = 54
7 = 55
8 = 56
9 = 57
A = 65
B = 66
C = 67
D = 68
E = 69
F = 70
G = 71
H = 72
I = 73
J = 74
K = 75
L = 76
M = 77
N = 78
O = 79
P = 80
Q = 81
R = 82
S = 83
T = 84
U = 85
V = 86
W = 87
X = 88
Y = 89
Z = 90
LWIN = 91
RWIN = 92
APPS = 93
SLEEP = 95
NUMPAD0 = 96
NUMPAD1 = 97
NUMPAD2 = 98
NUMPAD3 = 99
NUMPAD4 = 100
NUMPAD5 = 101
NUMPAD6 = 102
NUMPAD7 = 103
NUMPAD8 = 104
NUMPAD9 = 105
MULTIPLY = 106
ADD = 107
SEPARATOR = 108
SUBTRACT = 109
DECIMAL = 110
DIVIDE = 111
F1 = 112
F2 = 113
F3 = 114
F4 = 115
F5 = 116
F6 = 117
F7 = 118
F8 = 119
F9 = 120
F10 = 121
F11 = 122
F12 = 123
F13 = 124
F14 = 125
F15 = 126
F16 = 127
F17 = 128
F18 = 129
F19 = 130
F20 = 131
F21 = 132
F22 = 133
F23 = 134
F24 = 135
NUMLOCK = 144
SCROLL = 145
LSHIFT = 160
RSHIFT = 161
LCONTROL = 162
RCONTROL = 163
LMENU = 164
RMENU = 165
BROWSER_BACK = 166
BROWSER_FORWARD = 167
BROWSER_REFRESH = 168
BROWSER_STOP = 169
BROWSER_SEARCH = 170
BROWSER_FAVORITES = 171
BROWSER_HOME = 172
VOLUME_MUTE = 173
VOLUME_DOWN = 174
VOLUME_UP = 175
MEDIA_NEXT_TRACK = 176
MEDIA_PREV_TRACK = 177
MEDIA_STOP = 178
MEDIA_PLAY_PAUSE = 179
LAUNCH_MAIL = 180
LAUNCH_MEDIA_SELECT = 181
LAUNCH_APP1 = 182
LAUNCH_APP2 = 183
OEM_1 = 186
OEM_PLUS = 187
OEM_COMMA = 188
OEM_MINUS = 189
OEM_PERIOD = 190
OEM_2 = 191
OEM_3 = 192
OEM_4 = 219
OEM_5 = 220
OEM_6 = 221
OEM_7 = 222
OEM_8 = 223
OEM_102 = 226
PROCESSKEY = 229
PACKET = 231
ATTN = 246
CRSEL = 247
EXSEL = 248
EREOF = 249
PLAY = 250
ZOOM = 251
NONAME = 252
PA1 = 253
OEM_CLEAR = 254


const.MonsterBits

 Values:
Active = 0x400 ?inside the active radius?
ShowOnMap = 0x8000 monster was once seen by party
Invisible = 0x10000
NoFlee = 0x20000
Hostile = 0x80000
OnAlertMap = 0x100000
TreasureGenerated = 0x800000 treasure is in Items[0] and Items[1], gold is in Items[3]
ShowAsHostile = 0x1000000 show as hostile on map
IsObeliskChest = 0x2000000 [MM8]


const.MonsterBonus

 Values:
Curse = 1
Weak = 2
Asleep = 3
Drunk = 4
Insane = 5
Poison1 = 6
Poison2 = 7
Poison3 = 8
Disease1 = 9
Disease2 = 10
Disease3 = 11
Paralyze = 12
Uncon = 13
Dead = 14
Stone = 15
Errad = 16
Brkitem = 17
Brkarmor = 18
Brkweapon = 19
Steal = 20
Age = 21
Drainsp = 22
Afraid = 23


const.MonsterBuff

 Values:
Null = 0
Charm = 1
Summoned = 2 [MM7+]
Curse = 2 [MM6]
ShrinkingRay = 3
Fear = 4
Stoned = 5
Paralyze = 6
Slow = 7
ArmorHalved [MM7+]
Berserk [MM7+]
MassDistortion [MM7+]
Fate [MM7+]
Enslave [MM7+]
DayOfProtection [MM7+]
HourOfPower [MM7+]
Shield [MM7+]
StoneSkin [MM7+]
Bless [MM7+]
Heroism [MM7+]
Haste [MM7+]
PainReflection [MM7+]
Hammerhands [MM7+]
MeleeOnly = 22 [MM8] (part of Blind and Dark Grasp)
DamageHalved = 23 [MM8]
Wander = 24 [MM8] monster wanders aimlessly (part of Blind)
Mistform = 25 [MM8]
Feeblemind = 8 [MM6]


const.MonsterKind

[MM7+]

 Values:
Undead = 1
Demon = 2 [MM7]
Dragon
Elf = 4 [MM7]
Swimmer
Immobile
Peasant = 5 [MM8]
Titan = 7 [MM7]
NoArena
Ogre = 7 [MM8]
Elemental = 8 [MM8]


const.MonsterPref

 Values:
Necro = 0x1 [MM8]
Knight
Paladin = 0x2 [MM6, MM7]
Archer = 0x4 [MM6, MM7]
Druid = 0x8 [MM6, MM7]
Cleric
Troll = 0x8 [MM8]
Minotaur = 0x10 [MM8]
DarkElf = 0x20 [MM8]
Vampire = 0x40 [MM8]
Dragon = 0x80 [MM8]
Sorcerer = 0x20 [MM6, MM7]
Ranger = 0x40 [MM7]
Thief = 0x80 [MM7]
Monk = 0x100 [MM7]
Male
Female
Human = 0x800 [MM7]
Elf = 0x1000 [MM7]
Dwarf = 0x2000 [MM7]
Goblin = 0x4000 [MM7]


const.NPCProfession

[MM6, MM7]

 Values:
Smith = 1
Armorer = 2
Alchemist = 3
Scholar = 4
Guide = 5
Tracker = 6
Pathfinder = 7
Sailor = 8
Navigator = 9
Healer = 10
ExpertHealer = 11
MasterHealer = 12
Teacher = 13
Instructor = 14
ArmsMaster = 15
WeaponsMaster = 16
Apprentice = 17
Mystic = 18
SpellMaster = 19
Trader = 20
Merchant = 21
Scout = 22
Herbalist = 23 [MM7]
Apothecary = 24 [MM7]
Counselor = 23 [MM6]
Barrister = 24 [MM6]
Tinker = 25
Locksmith = 26
Fool = 27
ChimneySweep = 28
Porter = 29
QuarterMaster = 30
Factor = 31
Banker = 32
Cook = 33
Chef = 34
Horseman = 35
Bard = 36
Enchanter = 37
Cartographer = 38
WindMaster = 39
WaterMaster = 40
GateMaster = 41
Chaplain = 42 [MM7]
Acolyte
Piper = 43
Explorer = 44
Pirate = 45
Squire = 46
Psychic = 47
Gypsy = 48
Diplomat = 49 [MM7]
Negotiator = 49 [MM6]
Duper = 50
Burglar = 51
FallenWizard = 52 [MM7]
Initiate = 54 [MM7]
Prelate = 55 [MM7]
Monk = 56 [MM7]
Sage = 57 [MM7]
Peasant = 52 [MM6]
Serf = 53 [MM6]
Tailor = 54 [MM6]
Laborer = 55 [MM6]
Farmer = 56 [MM6]
Cooper = 57 [MM6]
Potter = 58 [MM6]
Weaver = 59 [MM6]
Cobbler = 60 [MM6]
DitchDigger = 61 [MM6]
Miller = 62 [MM6]
Carpenter = 63 [MM6]
StoneCutter = 64 [MM6]
Jester = 65 [MM6]
Trapper = 66 [MM6]
Beggar = 67 [MM6]
Rustler = 68 [MM6]
Hunter
Scribe = 70 [MM6]
Missionary = 71 [MM6]
Clerk = 72 [MM6]
Guard = 73 [MM6]
FollowerofBaa = 74 [MM6]
Noble = 75 [MM6]
Gambler = 76 [MM6]
Child = 77 [MM6]


const.ObjectRefKind

 Values:
Nothing = 0
Door = 1
Object = 2
Monster = 3
Party = 4 Index is player index (1-4 or 0 for whole party ???)
Sprite = 5
Facet = 6 outdoors Index = ModelId*64 + FaceId
Light = 7


const.PartyBuff

 Values:
AirResistance = 0 [MM7+]
BodyResistance = 1 [MM7+]
DayOfGods = 2 [MM7+]
DetectLife = 3 [MM7+]
EarthResistance = 4 [MM7+]
FireResistance
ColdResistance = 1 [MM6]
ElecResistance = 2 [MM6]
MagicResistance = 3 [MM6]
PoisonResistance = 4 [MM6]
FeatherFall = 5
WaterWalk
Fly = 7
Haste = 8 [MM7+]
Heroism = 9 [MM7+]
Immolation = 10 [MM7+]
Invisibility = 11 [MM7+]
MindResistance = 12 [MM7+]
ProtectionFromMagic = 13 [MM7+]
Shield = 14 [MM7+]
Stoneskin = 15 [MM7+]
GuardianAngel = 8 [MM6]
WizardEye
TorchLight
WaterResistance = 17 [MM7+]


const.PlayerBuff

 Values:
AirResistance = 0 [MM7+]
Bless
BodyResistance = 2 [MM7+]
EarthResistance = 3 [MM7+]
Fate = 4 [MM7+]
FireResistance = 5 [MM7+]
Hammerhands = 6 [MM7+]
Heroism
Haste
MindResistance = 9 [MM7+]
PainReflection = 10 [MM7+]
Preservation = 11 [MM7+]
Regeneration = 12 [MM7+]
Shield
Stoneskin
TempLuck
TempIntellect
TempPersonality
TempAccuracy
TempEndurance = 16 [MM7+]
TempSpeed
TempMight
WaterResistance = 22 [MM7+]
WaterBreathing = 23 [MM7+]
Glamour = 24 [MM8]
Levitate = 25 [MM8]
Misform = 26 [MM8]
TempEndurancy = 11 [MM6]


const.Race

[MM7]

 Values:
Human = 0
Elf = 1
Goblin = 2
Dwarf = 3


const.Screens

 Values:
Game = 0
Manu = 1
Controls = 2
Info = 3 quests, map, autonotes
NPC = 4
Rest = 5
Query = 6 like with hotkeys in Chinese debug MM6
Inventory = 7
SpellBook = 8
NewGameBreefing = 9
Chest = 10
SaveGame = 11
LoadGame = 12
House = 13
MainManu = 16 or movie
WalkToMap = 17
MapEntrance = 18 or Question screen
SimpleMessage = 19
CreateParty = 21
EscMessage = 22
KeyConfig = 26
VideoOptions = 28
QuickReference = 104


const.Season

 Values:
Automn = 0
Summer = 1
Fall = 2
Winter = 3


const.Skills

 Values:
Staff = 0
Sword = 1
Dagger = 2
Axe = 3
Spear = 4
Bow = 5
Mace = 6
Blaster = 7
Shield = 8
Leather = 9
Chain = 10
Plate = 11
Fire = 12
Air = 13
Water = 14
Earth = 15
Spirit = 16
Mind = 17
Body = 18
Light = 19
Dark = 20
DarkElfAbility = 21 [MM8]
VampireAbility = 22 [MM8]
DragonAbility = 23 [MM8]
IdentifyItem
Merchant
Repair
Bodybuilding
Meditation
Perception
Regeneration = 30 [MM8]
Diplomacy = 27 [MM6, MM7]
Thievery = 28 [MM6, MM7]
DisarmTraps
Dodging [MM7+]
Unarmed [MM7+]
IdentifyMonster [MM7+]
Armsmaster [MM7+]
Stealing [MM7+]
Alchemy [MM7+]
Learning


const.SpriteBits

 Values:
TriggerByTouch = 1 triggered when a player comes into TriggerRadius
TriggerByMonster = 2 triggered when a monster comes into TriggerRadius
TriggerByObject = 4 triggered when an object gets into TriggerRadius
ShowOnMap = 8
IsChest = 16
Invisible = 32
IsObeliskChest = 64


const.Stats

 Values:
Might = 0
Intellect = 1
Personality = 2
Endurance = 3
Accuracy = 4
Speed = 5
Luck = 6
HP = 7
HitPoints = 7
SP = 8
SpellPoints = 8
ArmorClass = 9
FireResistance = 10
AirResistance = 11 [MM7+]
WaterResistance = 12 [MM7+]
EarthResistance = 13 [MM7+]
MindResistance = 14 [MM7+]
BodyResistance = 15 [MM7+]
Alchemy = 16 [MM7+]
Stealing = 17 [MM7+]
DisarmTraps = 18 [MM7+]
IdentifyItem = 19 [MM7+]
IdentifyMonster = 20 [MM7+]
Armsmaster = 21 [MM7+]
Dodging = 22 [MM7+]
Unarmed = 23 [MM7+]
ElecResistance = 11 [MM6]
ColdResistance = 12 [MM6]
PoisonResistance = 13 [MM6]
Level
MeleeAttack
MeleeDamageBase
MeleeDamageMin
MeleeDamageMax
RangedAttack
RangedDamageBase
RangedDamageMin
RangedDamageMax
SpiritResistance = 33 [MM7+]
FireMagic = 34 [MM7+]
AirMagic = 35 [MM7+]
WaterMagic = 36 [MM7+]
EarthMagic = 37 [MM7+]
SpiritMagic = 38 [MM7+]
MindMagic = 39 [MM7+]
BodyMagic = 40 [MM7+]
LightMagic = 41 [MM7+]
DarkMagic = 42 [MM7+]
Meditation = 43 [MM7+]
Bow = 44 [MM7+]
Shield = 45 [MM7+]
Learning = 46 [MM7+]
DarkElf = 47 [MM8]
Vampire = 48 [MM8]
Dragon = 49 [MM8]
MagicResistance = 23 [MM6]


evt.Players

 Values:
0 = 0
1 = 1
2 = 2
3 = 3
4 = 4 [MM8]
Current
current
All = 5
all = 5
Random = 6
random = 6


evt.VarNum

 Values:
SexIs = 1
ClassIs = 2
HP = 3
HasFullHP = 4
SP = 5
HasFullSP = 6
AC = 7
ArmorClass = 7
ACBonus = 8
ArmorClassBonus = 8
BaseLevel = 9
LevelBonus = 10
AgeBonus = 11
Awards = 12
Exp = 13
Experience = 13
QBits = 16
Inventory = 17
HourIs = 18
DayOfYearIs = 19
DayOfWeekIs = 20
Gold = 21
GoldAddRandom = 22
Food = 23
FoodAddRandom = 24
MightBonus = 25
IntellectBonus = 26
PersonalityBonus = 27
EnduranceBonus = 28
SpeedBonus = 29
AccuracyBonus = 30
LuckBonus = 31
BaseMight = 32
BaseIntellect = 33
BasePersonality = 34
BaseEndurance = 35
BaseSpeed = 36
BaseAccuracy = 37
BaseLuck = 38
CurrentMight = 39
CurrentIntellect = 40
CurrentPersonality = 41
CurrentEndurance = 42
CurrentSpeed = 43
CurrentAccuracy = 44
CurrentLuck = 45
FireResistance = 46
AirResistance = 47 [MM7+]
WaterResistance = 48 [MM7+]
EarthResistance = 49 [MM7+]
SpiritResistance = 50 [MM7+]
MindResistance = 51 [MM7+]
BodyResistance = 52 [MM7+]
ElecResistance = 47 [MM6]
ColdResistance = 48 [MM6]
PoisonResistance = 49 [MM6]
MagicResistance = 50 [MM6]
FireResBonus
AirResBonus = 58 [MM7+]
WaterResBonus = 59 [MM7+]
EarthResBonus = 60 [MM7+]
SpiritResBonus = 61 [MM7+]
MindResBonus = 62 [MM7+]
BodyResBonus = 63 [MM7+]
ElecResBonus = 52 [MM6]
ColdResBonus = 53 [MM6]
PoisonResBonus = 54 [MM6]
MagicResBonus = 55 [MM6]
StaffSkill
SwordSkill
DaggerSkill
AxeSkill
SpearSkill
BowSkill
MaceSkill
BlasterSkill
ShieldSkill
LeatherSkill
ChainSkill
PlateSkill
FireSkill
AirSkill
WaterSkill
EarthSkill
SpiritSkill
MindSkill
BodySkill
LightSkill
DarkSkill
DarkElfAbilitySkill = 89 [MM8]
VampireAbilitySkill = 90 [MM8]
DragonAbilitySkill = 91 [MM8]
IdentifyItemSkill
MerchantSkill
RepairSkill
BodybuildingSkill
MeditationSkill
PerceptionSkill
RegenerationSkill = 98 [MM8]
DiplomacySkill [MM6, MM7]
ThieverySkill [MM6, MM7]
DisarmTrapsSkill
DodgingSkill [MM7+]
UnarmedSkill [MM7+]
IdentifyMonsterSkill [MM7+]
ArmsmasterSkill [MM7+]
StealingSkill [MM7+]
AlchemySkill [MM7+]
LearningSkill
Cursed
Weak
Asleep
Afraid
Drunk
Insane
PoisonedGreen
DiseasedGreen
PoisonedYellow
DiseasedYellow
PoisonedRed
DiseasedRed
Paralysed
Unconscious
Dead
Stoned
Eradicated
MainCondition
MapVar0
MapVar1
MapVar2
MapVar3
MapVar4
MapVar5
MapVar6
MapVar7
MapVar8
MapVar9
MapVar10
MapVar11
MapVar12
MapVar13
MapVar14
MapVar15
MapVar16
MapVar17
MapVar18
MapVar19
MapVar20
MapVar21
MapVar22
MapVar23
MapVar24
MapVar25
MapVar26
MapVar27
MapVar28
MapVar29
MapVar30
MapVar31
MapVar32
MapVar33
MapVar34
MapVar35
MapVar36
MapVar37
MapVar38
MapVar39
MapVar40
MapVar41
MapVar42
MapVar43
MapVar44
MapVar45
MapVar46
MapVar47
MapVar48
MapVar49
MapVar50
MapVar51
MapVar52
MapVar53
MapVar54
MapVar55
MapVar56
MapVar57
MapVar58
MapVar59
MapVar60
MapVar61
MapVar62
MapVar63
MapVar64
MapVar65
MapVar66
MapVar67
MapVar68
MapVar69
MapVar70
MapVar71
MapVar72
MapVar73
MapVar74
MapVar75
MapVar76
MapVar77
MapVar78
MapVar79
MapVar80
MapVar81
MapVar82
MapVar83
MapVar84
MapVar85
MapVar86
MapVar87
MapVar88
MapVar89
MapVar90
MapVar91
MapVar92
MapVar93
MapVar94
MapVar95
MapVar96
MapVar97
MapVar98
MapVar99
AutonotesBits
IsMightMoreThanBase
IsIntellectMoreThanBase
IsPersonalityMoreThanBase
IsEnduranceMoreThanBase
IsSpeedMoreThanBase
IsAccuracyMoreThanBase
IsLuckMoreThanBase
PlayerBits
NPCs [MM6, MM7]
ReputationIs
Flying
HasNPCProfession
TotalCircusPrize
SkillPoints
MonthIs
Counter1 [MM7+]
Counter2 [MM7+]
Counter3 [MM7+]
Counter4 [MM7+]
Counter5 [MM7+]
Counter6 [MM7+]
Counter7 [MM7+]
Counter8 [MM7+]
Counter9 [MM7+]
Counter10 [MM7+]
Reputation [MM7+]
History1 [MM7+]
History2 [MM7+]
History3 [MM7+]
History4 [MM7+]
History5 [MM7+]
History6 [MM7+]
History7 [MM7+]
History8 [MM7+]
History9 [MM7+]
History10 [MM7+]
History11 [MM7+]
History12 [MM7+]
History13 [MM7+]
History14 [MM7+]
History15 [MM7+]
History16 [MM7+]
History17 [MM7+]
History18 [MM7+]
History19 [MM7+]
History20 [MM7+]
History21 [MM7+]
History22 [MM7+]
History23 [MM7+]
History24 [MM7+]
History25 [MM7+]
History26 [MM7+]
History27 [MM7+]
History28 [MM7+]
History29 [MM7+]
MapAlert [MM7+]
BankGold [MM7+]
Deaths [MM7+]
MontersHunted [MM7+]
PrisonTerms [MM7+]
ArenaWinsPage [MM7+]
ArenaWinsSquire [MM7+]
ArenaWinsKnight [MM7+]
ArenaWinsLord [MM7+]
Invisible [MM7+]
IsWearingItem [MM7+]
Players = 318 [MM8]
BaseStats[]
CurrentStats[]
History[] [MM7+]
MapVars[]
Skills[]