MMExtension v2.3 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.
Map scripts can have accompanying global scripts next to them: oute3.global.lua and some_name.oute3.global.lua respectively. These scripts behave as the ones in Global folder, but are loaded after them and share local autonotes with their respective map script.
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. Get 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

Note: You can't turn a decompiled script back into EVT file, even if it's in text form. In case you do need to edit raw EVT files, you can use my 010Editor Templates.

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.",
Award = "Brought a sword to Frederick Talimere",
}

-- 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.",
Award = "Brought a sword to a tavern-dwelling lizard",
},
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 is an expert in these.",
Undone = "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!",
Award = "Showed a stone to Frederick Talimere",
}

-- 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 = |t| Game.CurrentScreen ~= const.Screens.House, -- only show if NPC was met on the street
}
.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.",
Award = "Killed all da Pirates on Dagger Wound Islands",
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.",
Award = "Conducted a massacre in the Abandoned Temple",
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.

Autonotes

To avoid hassle with autonote indexes and autonote count limit, use Autonote and AddAutonote functions to deal with your autonotes.

Example:
Maps\out01.global.lua:
Autonote('hi', 1, 'Welcome to out01!')
Maps\out01.lua:
local TXT = Localize{
AutonoteMessage = "Check Auto Notes, it's extremely important!",
}
if not CheckAutonote'hi' then -- just to demonstrate use of CheckLocalAutonote
Game.ShowStatusText(TXT.AutonoteMessage)
end
AddAutonote'hi'

Autonotes added this way are automatically made localizeable. By default they are local to the script to avoid naming conflicts. For autonotes shared by multiple scripts use ":" at the beginning of their names (e.g. ":hi").

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.

Special Codes in Texts

In any text you can use special codes inserted with StrLeft, StrRight and StrColor functions.
In various NPC messages and History.txt file you can also use these codes:
CodeMeaning
%01 NPC name
%02 Current player name
%03 "his"/"her" (depending on NPC sex)
%04 Bribe cost
%05 "day"/"evening"/"morning"
%06 "lady"/"sir" (depending on sex of current player)
%07 "Lady"/"Sir" (depending on sex of current player)
%08 Random achieved award from a hardcoded list
%09 Same as %03
%10 "Lady"/"Lord" (depending on sex of current player)
%11 Reputation category of the party
%12 Reputation category required by the NPC
%13 Any name starting with the same letter as that of current player
%14 "sister"/"brother" (depending on NPC sex)
%15 "daughter"
%16 Same as %14
%17 Gold percentage an NPC takes
%23 Map name
%24 Item name (in yellow color)
%25 Standard buy/sell/repair cost
%27 Actual buy/sell/repair cost with regards to Merchant skill
%28 Shop owner title
%29 Identification price
MM7, MM8:
%30 History entry date
%31 Player 1 name
%51 – %70 Special date
MM7:
%32 Player 2 name
%33 Player 3 name
%34 Player 4 name
MM8:
%32 "his"/"her" (depending on player 1 sex)
%33 "he"/"she" (depending on player 1 sex)
%34 "him"/"her" (depending on player 1 sex)

More on Data Tables

Having the Data\Tables folder is great for development of a mod, but simply distributing it with a big mod may present challenges for subsequent creation of smaller mods for it, because they'd be overwritten by any update of the big mod.
First, I'd recommend setting up reading tables that don't correspond to *.bin files from LOD archive of your mod if it's a big one. This will allow other mods or power users to override the table more safely. Here's an example (for Scripts\General):
table.copy({
['Chest'] = 'Chest.txt',
['Class HP SP'] = 'ClsHPSP.txt',
['Class Skills'] = 'ClsSkill.txt',
['Class Starting Skills'] = 'ClsSkilB.txt',
['Class Starting Stats'] = 'ClsStats.txt',
['House Movies'] = 'HouseMov.txt',
['Monster Kinds'] = 'MonKind.txt',
['Spells2'] = 'Spells2.txt',
['Town Portal'] = 'TownPort.txt',
['Transport Index'] = 'TripIdx.txt',
['Transport Locations'] = 'TripLoc.txt',
['Shops'] = 'Shops.txt',
['Faces'] = 'Faces.txt',
['Face Animations'] = 'FaceAnim.txt',
}, DataTables.Files, true)
-- DataTables.LazyMode = true -- see below for an explanation
You can also disable any data table by setting it to an empty string here.
Second, for tables that generate *.bin files there are 2 ways to go:
  • Distributing Data\Tables folder with them with your mod. Including DataFiles with corresponding *.bin files is also a good practice. This will lead to the discussed problem for smaller mods, but you won't have to make an installer.
  • Placing generated *.bin files into a LOD archive of your mod and setting DataTables.LazyMode = true, which makes it so that tables can still be overridden with Data\Tables, but they aren't automatically generated (calling UpdateDataTables() would generate them). You will also need to move or delete preexisting Data\Tables and DataFiles on first installation of the mod, because files there will override those of your mod.




  • 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

    Skill Bonuses

    Making GM Dagger do +2 damage/skill instead of +1:
    function events.CalcStatBonusBySkills(t)
    if t.Result ~= 0 and t.Stat == const.Stats.MeleeDamageBase then -- t.Result ~= 0 is for speedup
    local sk, mas = SplitSkill(t.Player.Skills[const.Skills.Dagger])
    if mas >= const.GM then
    local it = t.Player:GetActiveItem(const.ItemSlot.MainHand)
    if it and it:T().Skill == const.Skills.Dagger then
    t.Result = t.Result + sk
    end
    end
    end
    end

    Spells Damage

    Change damage of spell 2 – Flame Arrow. You can also make damage depend on t.Mastery (skill 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 for barrels 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()

    See current house (2DEvent) and NPC indeces (run it from console):
    Game.GetCurrentHouse(), GetCurrentNPC()

    Q: How to change the home position after the death of the team on current map?
    A: Specify desired coordinates in the call to XYZ and set desired 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:
    function Keys.F1(t)
    Message("F1 pressed")
    end
    Method 2:
    function events.KeyDown(t)
    if t.Key == const.Keys.F1 then
    Message("F1 pressed")
    end
    end
    Obsolete method provided for backward compatibility: (This is NOT the same as setting Keys.F1)
    Keys[const.Keys.F1] = function()
    Message("F1 pressed")
    end
    This method may ignore quick key presses.



    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 the 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

    To make your script compatible with all MM versions, instead of calling this function you can call SummonItem to create an item and Game.SummonObjects to create an object.

     Parameters:
    Item [MM8] Item index. Index over 1000 means random item of the same kind as Item % 1000 of strength Item div 1000. For backward compatibility, this parameter can also be called Type.
    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 directly.
    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 Level requirement and that Mastery exactly matches that of the player (Novice matches any mastery). Was supposed to include "Double effect" enchantments and NPC bonuses, but doesn't.

     Parameters:
    Skill
    Mastery
    Level

    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.CanPlayerAct

    [MM8]

     Parameters:
    Id from Roster.txt

    evt.RefundChestArtifacts

    To be added in 2.5.6 or 2.6 of the patches. Removes all artifacts randomly generated in the chest from Party.ArtifactsFound.

     Parameters:
    Id



    Events


    Structs\After\ Spells.lua

     Events:

    MonsterCastSpell

    {
    Action
    CallDefault
    Direction
    Handled
    Monster
    MonsterIndex
    ObjectType
    Skill [MM7+]
    Sound
    Spell
    }
    Can be used to change how a spell works when cast by a monster.
    Sound and ObjectType aren't assigned initially, you can set them to change what sound the spell makes and what projectiles it has.
    CallDefault(FakeSpell, FakeSkill) would use logic from FakeSpell with FakeSkill, but change sound and any created projectiles to match what you've defined in the table.
    Example:
    -- allow Poison Spray to be cast by monsters
    events.MonsterCastSpell = |t| if t.Spell == 24 then
    local sk, mas = SplitSkill(t.Skill)
    if mas >= const.Expert then
    t.CallDefault(15, JoinSkill(sk, mas - 1)) -- use Sparks as a template
    else
    t.CallDefault(2) -- use Fire Bolt as a template
    end
    end

    EventCastSpell

    {
    CallDefault
    FromX
    FromY
    FromZ
    Handled
    Mastery
    ObjectType
    Skill
    Sound
    Spell
    ToX
    ToY
    ToZ
    }
    Can be used to change how a spell works when cast by evt.CastSpell.
    Sound and ObjectType aren't assigned initially, you can set them to change what sound the spell makes and what projectiles it has.
    CallDefault(FakeSpell, FakeMastery, FakeSkill, x1, y1, z1, x2, y2, z2) would use logic from FakeSpell with FakeMastery and FakeSkill, but change sound and any created projectiles to match what you've defined in the table. Coordinates can also be changed.
    Complex example:
    -- Enables Paralyze spell to be used by monsters and evt.CastSpell
    -- You would also need to add the projectiles to ObjList.txt and SFT.txt in Data\Tables\
    local spPara = const.Spells.Paralyze
    local objPara = Game.SpellObjId[spPara]

    local handler = |t| if t.Spell == spPara then
    t.CallDefault(2) -- Fire Bolt, because it simply plays a sound and creates a projectile
    end
    events.MonsterCastSpell = handler
    events.EventCastSpell = handler

    events.ReadMonsterSpell = |t| if t.Name == "paralyze" then
    t.Result = spPara
    end

    events.PlayerAttacked = |t| if not t.Handled then
    local o = t.Attacker.Object
    if o and o.Type == objPara then
    t.Handled = true
    t.Player:DoBadThing(const.MonsterBonus.Paralyze, t.Attacker.Monster or Map.Monsters[0])
    end
    end

    events.MonsterAttacked = |t| if not t.Handled then
    local o, mon = t.Attacker.Object, t.Monster
    if o and o.Type == objPara then
    t.Handled = true
    if mon:CalcHitByEffect(Game.SpellsTxt[spPara].DamageType) then
    mon.CurrentActionLength = 128
    mon.AIState = 0
    mon.SpeedX = 0
    mon.SpeedY = 0
    mon.SpeedZ = 0
    mon:UpdateGraphicState()
    mon.SpellBuffs[const.MonsterBuff.Paralyze]:Set(Game.Time + 3*const.Minute*o.SpellSkill, o.SpellLevel)
    mon:ShowSpellEffect()
    end
    end
    end

    ReadMonsterSpell

    {word1, word2, ...;
    Name
    Result
    }
    If spell name is "Hour of Power", the table passed to event would be {"hour", "of", "power", Name = "hour of power"}, all in lower case.
    Example:
    -- allow Poison Spray to be read from Monsters.txt
    events.ReadMonsterSpell = |t| if t.Name == "poison spray" then
    t.Result = 24
    end



    Core\ events.lua

     Events:

    CalcSpellDamage

    {
    HP
    HitPoints
    Mastery
    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.

    DeathMap

    {
    Name
    Set
    }

    NewGameMap

    {
    AutoFallStart
    Set
    }
    Set(x, y, z, direction, lookAngle, speedZ) function sets both party position (saved in autosave) and map transition (used on start immediately).

    NewGameDefaultParty

    ()

    NewGameClearParty

    ()

    LoadedRosterTxt

    ()
    Loaded roster.txt and pcnames.txt

    GameInitialized0

    ()
    loaded icons.lod, events.lod[MM7], language LODs[MM8]; about to start loading global.txt

    GameInitialized1

    ()
    loaded all archives except games.lod, loaded global.txt and .bin data

    GameInitialized2

    ()
    loaded .txt data, global.evt and all archives, intro shown, various bitmaps, sprites and sounds loaded

    CanSaveGame

    {
    IsArena
    SaveKind
    }
    SaveKind: 0 – normal, 1 – autosave, 2 – quick save
    If IsArena is true, the "No saving on the Arena" message is displayed

    CanCastLloyd

    ()

    IsUnderwater

    {
    Map
    Result
    }
    [MM7+]

    FogRange

    ()

    PopulateQuestLog

    ()
    Use this event to add quest indexes to Game.DialogLogic.List or rearrange them

    PopulateAutonotesList

    {
    Category
    }
    Use this event to add autonote indexes to Game.DialogLogic.List or rearrange them

    PopulateAwardsList

    {
    NoShuffle
    Player
    PlayerIndex
    }
    Use this event to add award indexes to Game.DialogLogic.List or rearrange them. Awards would later be arranged into groups of different colors. If NoShuffle is set to true, their order within groups would be preserved, otherwise default game code will sort them in an unpredictable manner.

    MonsterInfoPictureChanged

    (MonId)
    Called when monster kind in monster info dialog changes. Game.DialogLogic.MonsterInfoMonster holds the monster prototype being displayed. This is the event you can use to change Game.PatchOptions.MonSpritesSizeMul.

    WindowMessage

    {
    Handled
    LParam
    Msg
    Result
    WParam
    Window
    }

    KeyDown

    {
    Alt
    ExtendedKey
    Handled
    Key
    WasPressed
    }

    KeyUp

    {
    Alt
    ExtendedKey
    Handled
    Key
    WasPressed
    }

    PostRender

    ()

    Action

    {
    Action
    Handled
    Param
    Param2
    }

    MenuAction

    {
    Action
    Handled
    Param
    Param2
    }

    ExitMapAction

    {
    Action
    }

    KeysFilter

    {
    Key
    On
    Result
    }

    BeforeSaveGame

    ()

    BeforeNewGameAutosave

    ()

    AfterNewGameAutosave

    ()

    AfterSaveGame

    ()

    SkyBitmap

    {
    FirstVisit
    Result
    }

    LoadSavedMap

    {
    Data = Raw ddm or dlv data
    FacetsCount = [MM7+] Total numuber of facets on the map
    IsIndoor
    IsOutdoor
    }
    You can do a number of things here:
    1. Set Map.LastRefillDay to 0 to force a refill.
    2. In MM7+ you could handle games saved in an older version of your mod. The game checks Map.SanitySpritesCount against Map.Sprites.Count, Map.SanityFacetsCount against FacetsCount, and on outdoor maps Map.SanityModelsCount against Map.Models.Count. If all sanity fields are non-zero and either of them doesn't match the real count, the game forcibly refills the map. You can do a similar check, and either change Data (use mem.free and mem.malloc if needed) or backup monsters, objects, chests and visible map data and restore them in CancelLoadingMapScripts event (that's the first of events that fires once the map is loaded). Not an easy task, but it will provide saves compatibility when signinficant changes to maps happen.
    Important: Map.Name at this point is changed from "map.odm"/"map.blv" to "map.ddm"/"map.dlv".
    Another note: Map.SanityDoorDataSize was added in MMExtension. At this point you can check it against Map.IndoorHeader.DoorDataSize, later on DoorDataSize gets replaced with SanityDoorDataSize if the latter is non-zero.

    PlayMapTrack

    {
    MapIndex
    Track
    }

    ShowMovie

    {
    Allow
    CallDefault = function()
    DoubleSize
    ExitCurrentScreen
    Name
    Y
    }

    PlaySound

    {
    Allow
    CallDefault = function()
    Loops
    ObjRef
    Sound
    Speed
    UnkParam
    Volume
    X
    Y
    }

    FaceAnimation

    {
    Allow
    Animation
    CallDefault = function()
    Face
    ForceSound
    Player
    PlayerIndex
    Sound
    SoundCount
    SoundOffset
    }

    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. The game does the same, but only takes one instance of each artifact into consideration.

    SetMagicBonus does the same to MagicBonus.

    CalcStatBonusByMagic

    {
    Player
    PlayerIndex
    Result
    Stat
    }

    CalcStatBonusBySkills

    {
    Player
    PlayerIndex
    Result
    Stat
    }

    GetSkill

    {
    Player
    PlayerIndex
    Result
    Skill
    }
    [MM7+]

    GetAttackDelay

    {
    Player
    PlayerIndex
    Ranged
    Result
    }

    CalcDamageToPlayer

    {
    Damage
    DamageKind
    Player
    PlayerIndex
    Result
    }

    GetMerchantTotalSkill

    {
    Player
    PlayerIndex
    Result
    }

    GetDisarmTrapTotalSkill

    {
    Player
    PlayerIndex
    Result
    }

    GetDiplomacyTotalSkill

    {
    Player
    PlayerIndex
    Result
    }
    [MM6]

    GetPerceptionTotalSkill

    {
    Player
    PlayerIndex
    Result
    }
    [MM7+]

    GetLearningTotalSkill

    {
    Player
    PlayerIndex
    Result
    }
    [MM7+]

    DoBadThingToPlayer

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

    GetStatisticEffect

    {
    Result
    Value
    }

    UseMouseItem

    {
    ActivePlayer
    ActivePlayerIndex
    Allow
    CallDefault = function()
    IsPortraitClick
    Player
    PlayerSlot
    }

    CanLearnSpell

    {
    NeedMastery
    Player
    PlayerIndex
    Spell
    }

    Regeneration

    {
    HP
    Player
    PlayerIndex
    SP
    }
    HP and SP don't include regeneration values assigned by the game, but setting them takes care of conditions
    !k{Player :structs.Player}

    ModifyItemDamage

    {
    Damage
    Item
    MonsterId
    Player
    PlayerIndex
    Result
    Slot
    }

    GenerateItem

    {
    AlwaysEnchant
    Handled
    Item
    Kind
    Strength
    }

    ItemGenerated

    {
    AlwaysEnchant
    Handled
    Item
    Kind
    Strength
    }

    MonsterKilled

    (mon, monIndex, defaultHandler)

    MonsterKillExp

    {
    Exp
    Handled
    Monster
    MonsterIndex
    }

    ItemAdditionalDamage

    {
    DamageKind
    Item
    Result
    Vampiric
    }
    [MM7+]

    CalcDamageToMonster

    {
    Damage
    DamageKind
    Monster
    MonsterIndex
    Result
    }

    PickCorpse

    {
    Allow
    CallDefault = function()
    Monster
    MonsterIndex
    }

    CastTelepathy

    {
    Allow
    CallDefault = function()
    Monster
    MonsterIndex
    }
    [MM7+]

    CanMonsterCastSpell

    {
    Allow
    Distance [MM8]
    Monster
    MonsterIndex
    Spell
    }
    [MM7+]

    MonsterChooseAction

    {
    Action
    CallDefault = function()
    Distance [MM8]
    Monster
    MonsterIndex
    }
    Action starts uninitialized. Each time you call CallDefault, it generates new result, assigns it to Action and returns the value.

    MonsterAttacked

    ({
    Attacker = table returned by WhoHitMonster
    Handled
    Monster
    MonsterIndex
    }, attacker)
    Called when a player or a projectile tries to hit a monster. Can be used to completely replace what happens.
    Doesn't get triggered when using Armageddon or Finger of Death.

    AfterMonsterAttacked

    ({
    Attacker = table returned by WhoHitMonster
    Handled = carried over from MonsterAttacked event
    Monster
    MonsterIndex
    }, attacker)

    PlayerAttacked

    ({
    Attacker = table returned by WhoHitPlayer
    Handled
    Player
    PlayerSlot
    }, attacker)
    Called when a monster or a projectile tries to hit a player. Can be used to completely replace what happens.
    Doesn't get triggered when using Armageddon.

    AfterPlayerAttacked

    ({
    Attacker = table returned by WhoHitPlayer
    Handled = carried over from PlayerAttacked event
    Player
    PlayerSlot
    }, attacker)


    Core\ evt.lua

     Events:

    LeaveMap

    ()

    LeaveGame

    ()

    BeforeLoadMap

    (WasInGame, WasLoaded)

    CancelLoadingMapScripts

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

    BeforeLoadMapScripts

    (WasInGame)

    LoadMapScripts

    (WasInGame)
    Use this event instead of LoadMap in Global and General scripts

    LoadMap

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

    AfterLoadMap

    (WasInGame)

    GetEventHint

    (evtId)

    GetMazeInfo

    ()

    EvtMap

    (evtId, seq)

    EvtGlobal

    (evtId, seq)


    Core\ main.lua

     Events:

    StructsLoaded

    ()

    ScriptsLoaded

    ()


    Core\ npc.lua

     Events:

    EnterAnyNPC

    ({
    Index
    Kind
    NPC
    }, npc)
    Happens before events.EnterNPC. Kind ("NPC", "HiredNPC", "StreetNPC") defines the array NPC belongs to and Index is index in that array.

    EnterNPC

    (Index)
    Only called for NPCs from Game.NPC array, not for street or hired NPCs

    ShowNPCTopics

    (Index)
    NPC topics are about to be shown and you can update them here

    ShowHiredNPCTopics

    (Index, RealNPC)
    Happens only in MM6 when you talk to a hired NPC.
    Index is the index in Party.HiredNPC array.
    RealNPC is the index of the prototype NPC in Game.NPC array or nil.

    DrawNPCGreeting

    {
    NPC
    Seen
    Text
    }

    SpeakWithMonster

    {
    Monster
    MonsterIndex
    Result
    }
    [MM7+] Called when you speak with a guard or any other monster with a generic message from NPCGroup.txt. Assign Result a string to override default monster group message. Assign an empty string to show no message. Initially Result is nil.

    CanExitNPC

    {
    Allow
    Must
    NPC
    }
    If Must is true, the handler can still set Allow to false, but can't fully cancel the exit. After CanExitNPC cancels it 100 times, the exit will happen unconditionally.

    CanExitStreetNPC

    {
    Allow
    Index
    Kind
    Must
    NPC
    }

    CanExitHiredNPC

    {
    Allow
    Index
    Kind
    Must
    NPC
    RealNPC
    }
    RealNPC is the index of the prototype NPC in Game.NPC array or nil.

    ExitNPC

    (CurrentNPC)

    ExitAnyNPC

    {
    Index
    Kind
    NPC
    }

    ExitHouseScreen

    (Game.HouseScreen)

    CanTeachSkillMastery

    {
    Allow
    Cost
    Mastery
    Skill
    Text
    }

    CanTempleHealPlayer

    {
    House
    Player
    PlayerIndex
    Result
    }

    GetShopItemTreatment

    {
    Action
    House
    HouseType
    Item
    Player
    PlayerIndex
    Result
    }
    Action: "buy", "sell", "identify", "repair"
    Result: 0-based option from merchant.txt
    GetDefault(HouseType, House, Item, Action, Player) function lets you get item treatment by another shop type (all parameters are optional)

    CanShopOperateOnItem

    {
    Action
    House
    HouseType
    Item
    Result
    }
    Action: "buy", "sell", "identify", "repair"
    GetDefault(House, Item) function lets you get item treatment by another shop type (all parameters are optional)

    ShopItemsGenerated

    {
    House
    HouseType
    }

    GuildItemsGenerated

    {
    House
    HouseType
    }
    Note that you'll have to update Game.GuildItemIconPtr if you change items in this event (see an example there).

    HouseMovieFrame

    {
    House
    }

    ArcomageSetup

    (arcomage, house)

    ArcomageText

    {
    House
    Result
    }
    Lets you modify Victory Conditions text.
    Result is not pre-initialized. Instead, you need to call GetDefault function to get the default string.

    ArcomageWin

    (house)

    NewBountyHunt

    {
    House
    Index
    Result
    }
    Assign Result to specify the target monster for the hunt

    BountyHuntDone

    {
    Gold
    House
    Index
    }
    If you modify Gold here, it wouldn't be in line with the promised sum, but you may introduce other rewards for example

    SetMapNoNPC

    ()
    [MM7] Use this event if you need to set Map.NoNPC

    PopulateNPCDialog

    ({
    DlgKind
    Index
    Kind
    NPC
    Result
    }, npc)
    Change topics of an NPC dialog. Result is an array of NPC commands from const.HouseScreens. Names from const.HouseScreens as text are also allowed. You can also add a table with extra parameters, see the example below. Kind ("NPC", "HiredNPC", "StreetNPC") defines the array NPC belongs to and Index is index in that array.
    The following DlgKind values are possible:
    "Main" – Regular NPC conversation. In MM6 this is also the Dismiss conversation with a hired NPC.
    "StreetNPC" – Conversation with a street NPC that you can hire. In MM7 this is also the Dismiss conversation with a hired NPC. In MM6 it ratains items you add to beg/threat/bribe menu.
    "LackFame" – Not enough fame to communicate with a street NPC. Unused.
    "BegThreatBribe" – Beg/Threat/Bribe menu in MM6.
    "ThreatBribe" – Beg/Threat/Bribe menu, but "Beg" option won't do anything, because you've already begged the NPC before.
    "JoinMenu" – Join party menu in MM6, MM7.
    "JoinRoster" – Join party menu in MM8.
    "TeachSkill" – Expert/Master/GM teaching.
    "JoinGuild" – Join a guild.
    "BountyHuntNPC" – Bounty Hunt NPC topic. Only utilized by MM6.
    "ArenaMenu" – Any Arena menu.
    "SeerPilgrimage" – Pilgrimage in MM6.

    AfterPopulateNPCDialog

    ({
    DlgKind
    ExtraParams
    Index
    Kind
    NPC
    Result
    }, npc)

    PopulateHouseDialog

    {
    House
    PicType
    Result
    }
    Change topics in the main dialog menu in a house, unless isn't an NPC conversation. Unfortunately, the captions displayed won't change as they are hard-coded in various places. Result is an array of topic numbers from const.HouseScreens. Names from const.HouseScreens as text are also supported.
    Example:
    events.PopulateHouseDialog = |t| if t.PicType == const.HouseType.Training then
    t.Result = {"Train"} -- disable learning skills at training halls
    end

    PopulateArcomageDialog

    {
    House
    PicType
    Result
    }

    PopulateDisplayInventoryDialog

    {
    House
    PicType
    Result
    }

    AfterPopulateHouseDialog

    {
    ExtraParams
    House
    PicType
    Result
    }
    There are also similar AfterPopulateArcomageDialog and AfterPopulateDisplayInventoryDialog events

    PopulateLearnSkillsDialog

    {
    House
    PicType
    Result
    }
    [MM7+] Change skills in Learn Skills dialog. Result is an array of skill numbers. Skill names from const.Skills are also allowed.
    Example:
    events.PopulateLearnSkillsDialog = |t| if t.PicType == const.HouseType.Tavern then
    t.Result[#t.Result + 1] = "Blaster" -- devs apperently forgot to make taverns teach you Blaster skill
    end

    AfterPopulateLearnSkillsDialog

    {
    House
    PicType
    }

    BeforeDrawDialogs

    ()

    BeforeDrawDialog

    {
    Dialog
    DlgID
    DrawnCount
    Index
    }
    Called when a dialog is just about to be drawn. Index goes from 1 to Game.Dialogs.Count and you can change if you have to.

    DrawDialog

    {
    Dialog
    DlgID
    DrawnCount
    Index
    }
    Note that some dialogs get destroyed once they are drawn. When that happens, Dialog is nil.

    AfterDrawDialog

    {
    Dialog
    DlgID
    DrawnCount
    Index
    }

    AfterDrawDialogs

    (DrawnCount)
    Called after drawing dialogs

    AfterDrawNoDialogs

    (0)
    Called in place of drawing dialogs when no dialog is active. The reason it's separated from AfterDrawDialogs event is to improve performance, because this event would usually stay unused.

    NewDialog

    (dlg, id)
    This function is called once a new dialog finishes creation. Note that in case of house dialogs, they internally create an extra dialog with DlgID = 1 for dialog topics, this leads to NewDialog event getting triggered for that extra dialog before the one for the base dialog, however both dialogs are already created and added to Game.Dialogs when either event fires.

    BeforeDestroyDialog

    (dlg, id)

    DestroyDialog

    (dlg, id)

    AfterDestroyDialog

    (dlg, id)

    BeforeShowOODialog

    {
    ClassPtr = This lets you know what dialog is being created even if DialogPtr got changed by the event
    DialogPtr
    Param
    }

    AfterShowOODialog

    {
    ClassPtr = This lets you know what dialog is being created even if DialogPtr got changed by the event
    DialogPtr
    Param
    Result
    }

    CloseOODialog

    {
    DialogPtr
    }

    DrawProgressBar

    ()

    HideProgressBar

    ()


    Core\ timers.lua

     Events:

    Tick

    ()


    Modules\ Faces.lua

     Events:

    BeforeUpdateFaces

    (JustRead)
    Triggered when "Faces.txt" is read or when Update is called.

    AfterUpdateFaces

    (JustRead)
    Triggered after the changes to Faces were applied.


    Modules\ PaperDoll.lua

     Events:

    ReloadPaperDollGraphics

    ()
    When corresponding ReloadPaperDollGraphics function is called

    PaperDollHiddenPieces

    ({
    arm1 = 1st arm when holding a weapon
    arm1f = 1st arm without a weapon
    arm2 = 2nd arm without 2-handed weapon
    arm2b = 2nd arm without 2-handed weapon, drawn behind armor
    arm2f = 2nd arm when not holding anything
    arm2fb = 2nd arm when not holding anything, drawn behind armor
    arm2h = 2nd arm for 2-handed weapon
    arm2hb = 2nd arm for 2-handed weapon, drawn behind armor
    evil = evil path interface in MM7
    game = in game (for BackDoll in MM8)
    good = good path interface in MM7
    hand1 = 1st hand when holding a weapon
    hand1a = 1st hand (always drawn)
    hand1f = 1st hand when not holding a weapon
    hand2 = 2nd hand for dual-wielding
    hand2f = 2nd hand when not holding anything
    hand2h = 2nd hand for 2-handed weapon
    menu = in new game menu (for BackDoll in MM8)
    neutral = neutral interface
    noring = rings menu closed
    ring = rings menu open
    shield = drawn when holding a shield
    }, player, InMenu, DrawOffsetX, DrawOffsetY)
    Here I've described pieces that PaperDoll module handles automatically. You can define when your own pieces are drawn through PaperDollDrawOrder array and hide them conditionally here.
    InMenu is true if it's a new game menu in MM8, in which case DrawOffsetX and DrawOffsetY are non-zero.

    PaperDollGetItems

    (t, player, InMenu, DrawOffsetX, DrawOffsetY)
    Lets you modify weared items, such as add new weared item slots. E.g. setting t.My = 1 would draw pl.Items[1]. Setting t.My = true would make ":My" drawn the same way ":Player" is drawn. You'll also need to add "My" to PaperDollDrawOrder.
    InMenu is true if it's a new game menu in MM8, in which case DrawOffsetX and DrawOffsetY are non-zero.

    PaperDollBeforeDoll

    (player, InMenu, DrawOffsetX, DrawOffsetY)
    Called before the paper doll is drawn after drawing the background.
    InMenu is true if it's a new game menu in MM8, in which case DrawOffsetX and DrawOffsetY are non-zero.

    PaperDollAfterDoll

    (player, InMenu, DrawOffsetX, DrawOffsetY)
    Called after the paper doll is drawn before drawing UI elements.
    InMenu is true if it's a new game menu in MM8, in which case DrawOffsetX and DrawOffsetY are non-zero.

    PaperDollAfterDraw

    (player, InMenu, DrawOffsetX, DrawOffsetY)
    Called after the paper doll is drawn.
    InMenu is true if it's a new game menu in MM8, in which case DrawOffsetX and DrawOffsetY are non-zero.



    General Functions


    Structs\After\ 00 Mem Functions.lua

     Functions:
    mem.ChangeGameArray
    (name, p, count, lenP, stru)
    mem.ExtendGameStructure
    (t)
    mem.ExtendAndSaveGameStructure
    {...;
    CustomOnce
    }
    mem.ExtendBitsArray
    {...;
    CountRefs
    Custom
    CustomOnce
    LimCountRefs
    Limit
    NoSave
    }


    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\ Dialogs.lua

     Functions:
    CustomDialog
    {...;
    CustomDialog
    DlgID
    Height
    Left
    Param
    StrParam
    Top
    Width
    }


    Structs\After\ Draw.lua

     Functions:
    DrawScreenEffectD3D
    (BitmapIndex, u, v, du, dv, x1, y1, x2, y2, cl, cl2, cl3, cl4)


    Structs\After\ Functions.lua

     Functions:
    SplitSkill
    (val)
    JoinSkill
    (skill, mastery)
    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

    ClearConsoleEvents
    ()
    Message
    (text, KeepSound, global)
    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
    SuppressSound
    (on)
    ExitScreen
    (process)
    Simulates Esc press
    ReloadHouse
    (id)
    Rebuilds house dialog, e.g. after you've moved an NPC to or from this house.
    Can seemlessly transition between different houses if id is specified.
    Simply closes the house if id is '-1'.
    SwitchHouseMovie
    (s, loop)
    Exits currently playing movie and loads the specified one
    DrawSimpleMessage
    ()
    Draw simple message in screens where it isn't normally supposed to be
    HouseMessage
    (text)
    show a message in houses in screens that don't normally support it
    AddGoldExp
    (gold, exp)
    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
    RGB
    (r, g, b)
    else
    end
    end
    StrLeft
    (v)
    StrRight
    (v)
    StrColor
    (r, g, b, s)
    PcxCache
    (EnglishD)
    Example – loading:
    local t = PcxCache(true)
    local win = t["winBG.PCX"]
    local lose = t["LOSEBG.PCX"]

    Drawing:
    Screen.DrawPcx(0, 0, win)

    Clearing cache deletes all loaded images:
    t("Clear")

    You can also reload all images, say, if you conditionally load a LOD with an inteface skin (all obtained addresses stay the same):
    t("Reload")

    Pass file name as second argument when invoking "Clear" or "Reload" to handle a specific file only.
    IconCache
    ()
    Same as PcxCache, but for in-place icons, which means loaded icons aren't stored in Game.IconsLod.Bitmaps, but instead stored in the cache until it's cleared
    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
    }
    Warning: In MM7+ sprite bits are stored in the save game. Thus, adding sprites would cause mismatch between Map.SanitySpritesCount and Map.Sprites.Count next time the game is loaded (see LoadSavedMap event for more info on that).
    If you do decide to use this function in a live MM7+ game, I recommend setting Map.Sprites.Count to normal amount in BeforeSaveGame event and restoring current amount in AfterSaveGame.
    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
    GenerateLocalization_BakFiles
    Set it to false in a General script to turn off *.bak files creation when generating localization
    GameLocalizationIgnore
    List of table names in Game structure that shouldn't be included in localization by GenerateGameLocalization
    GameLocalizationSchema
    Defines which files contain which names of Game structure tables and more (see in code)
    QuestNPC
    vars.Quests
    [name]
    Quest states: nil, "Given", "Done" or a custom state.
    vars.QuestAwards
    [name]
    vars.QuestAutonotes
    [name]

     Functions:
    LocalizeAll
    (t, over)
    See Localization.
    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)
    See Localization.
    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)
    Generates localization file for quests created with functions from this file.
    GenerateLocalization
    (IsLua, IncludeQuests)
    Generates localization files for scripts that call Localize or LocalizeAll functions.
    Pass IsLua = true to generate *.lua files instead of *.txt tables. Whichever is more convenient for you.
    Unless IncludeQuests is false, localization for quests is also generated.
    GenerateGameLocalization
    ()
    Generates localization files for various game data found in TXT files. Returns(in text form) the list of files not included in the generated localization.
    ShowQuestEffect
    (flash_book, operation)
    Plays sound and shows visual effect on current character's face.
    If flash_book is true, the quest book will start flashing.
    ShowAwardEffect
    (exclude, operation)
    Plays sound and shows visual effect on all characters' faces.
    exclude can be a function(player, slot) that returns true if the character should be excluded from the effect.
    ShowAutonoteEffect
    (category, just_sound, operation)
    Plays sound and shows visual effect on current character's face
    AutoQuest
    (t, text)
    t can be a function(t), which returns true if quest should be visible in the quest log
    AutoAward
    (t, text, sort)
    t can be a function(t, player_index, player), which returns true if award should be visible on the Awards page
    AutoAutonote
    (t, text, category)
    t can be a function(t), which returns true if autonote should be visible
    GetLocalName
    (name, lev)
    Autonote
    (name, cat, text)
    Creates a named autonote. To operate on global named autonotes, use ":" at the beginning of its name.
    AddAutonote
    (name, force)
    Adds a named autonote to Auto Notes. force = true makes it emit the sound even if autonote is already added
    CheckAutonote
    (name)
    Returns true if named autonote was added to Auto Notes
    FindAutonote
    (name, must)
    UpdateNPCQuests
    ()
    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 "".
    QuestBranchScreen
    (branch)
    Switches dialog branch to branch, but returns to current branch upon pressing Esc.
    ExitQuestBranch
    (all)
    Exits current branch opened with QuestBranchScreen. If no branch screens are left open, simulates Esc press to exit the dialog.
    GetQuestBranchStack
    ()
    Returns a table with branch names stored by QuestBranchScreen function (on each call it adds previous branch to the end of this table).
    Quest
    {name;
    AddAutonote
    AddAward
    AddQuestBit
    After
    Award
    AwardIndex
    Awards
    BaseName
    Branch
    CanAddAutonote
    CheckDone
    CheckGive
    Done
    DoneState
    Event
    Execute
    Exp
    Experience
    FirstStdTopic
    GetGreeting
    GetTopic
    Give
    GivenItem
    GivenState
    Gold
    IsAwarded
    IsGiven
    KeepQuestItem
    NPC
    Name
    NeverDone
    NeverGiven
    Quest
    QuestGold
    QuestIndex
    QuestItem
    RewardItem
    SetTexts
    Slot
    StdTopic
    StdTopicDone
    StdTopicGiven
    StoreAwards
    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
    QCheck
    (name, state)
    Mostly for backward compatibility.
    A function to show a topic only when the name quest is in state state.
    name defaults to current quest name.
    Examples:
    QCheck('MyQuest') = || vars.Quests.MyQuest == nil
    QCheck('MyQuest', 'Done') = || vars.Quests.MyQuest == 'Done'
    QCheck() = |t| vars.Quests[t.BaseName] == nil
    QCheck(nil, 'Done') = |t| vars.Quests[t.BaseName] == 'Done'


    Structs\After\ Spells.lua

     Functions:
    BeginGrabObjects
    ()
    Starts recording all spawned objects. You can call it prior to calling evt.SummonObject or Game.SummonObjects and then call GrabObjects afterwards to get all created objects.
    GrabObjects
    ()
    Returns all (up to 1000) objects spawned since last call to BeginGrabObjects


    Structs\After\ Text Tables.lua

     Functions:
    ParseTextTable
    (s, r, SkipEmpty, AssignTables)
    LoadTextTable
    (s, r, SkipEmpty, AssignTables)
    ParseBasicTextTable
    (s, SkipLinesCount, StartingIndex)
    LoadBasicTextTable
    (s, SkipLinesCount, StartingIndex)
    WriteBasicTextTable
    (t, fname)
    ParseNumbersTextTable
    (s, StartingLinesCount)
    LoadNumbersTextTable
    (s, StartingLinesCount)
    ParseNamedColTable
    (s)
    LoadNamedColTable
    (s)
    WriteNamedColTable
    (t, fname)
    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
    table.join
    (t, t1)
    Adds t1 array to the end of t
    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, IgnoreErrors)
    Loads a file as a string
    string.print
    (...)
    returns the string that print function would normally print out
    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, IgnoreCase)
    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

     Variables:
    mem.i1[p], mem.i2[p], mem.i4[p], mem.i8[p] Read/write signed integer at address p. Can also be called to convert a number to specified format.
    For example, for a function that returns a signed byte:
    return mem.i1(mem.call(func, 0))

    This would treat function call result as a signed byte, ignoring 3 higher-order bytes.
    mem.u1[p], mem.u2[p], mem.u4[p], mem.u8[p] Read/write unsigned integer at address p. Can also be called to convert a number to specified format.
    mem.r4[p], mem.r8[p], mem.r10[p] Read/write a floating-point number at address p

     Functions:
    mem.string(p, size, ReadNull) mem.string(p) – read null-terminated string
    mem.string(p, size) – read null-terminated string no bigger than size bytes
    mem.string(p, size, true) – read size bytes as string
    mem.call(p, cc, ...) p is the function address,
    cc is the number of parameters passed through registers: 0 – __stdcall or __cdecl, 1 – __thiscall, 2 – __fastcall, 3 – 3rd parameter in eax (eventhough the game doesn't use it),
    ... are the parameters.
    Another way to call: mem.call{p = 0x441EFD, cc = 0, ...}
    mem.IgnoreProtection(on) Pass true to be able to modify code with mem.i4 and such, pass false after you've finished.
    mem.prot(on) Same as above.
    mem.malloc(size) Allocate memory with the malloc function of the game. Shouldn't be called before the game starts initializing, it may cause slowness, because the allocator isn't yet initilized. Instead call mem.allocMM or mem.StaticAlloc.
    mem.alloc(size) Same as above.
    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.cmp(ptr1, ptr2, n)
    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) Returns n, short, long.
    n is the number of bytes occupied by instructions at address p. n is 5 or more, because placing a hook requires 5 bytes.
    short is true if the code contains a short jump leading outside of it.
    long is true if the code contains a near jump or call to a relative address.
    mem.GetInstructionSize(p) Returns n, short, long.
    n is the number of bytes occupied by the instruction at address p.
    short is true if the instruction is a short jump and it doesn't lead to itself.
    long is true if the instruction is a near jump or call to a relative address.
    mem.findcode(p, s, p2) Takes a string to search for. Only checks for a match at the start of a new instruction.
    mem.findcall(p, fptr, p2) Finds a call to fpts starting at p and stopping at p2 (optional). If fptr isn't specified, searches for any call instruction.
    mem.enumcalls(p1, p2, fptr) Enumerates all calls to fptr. If fptr isn't specified, enumerates all function calls.
    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, DuplicateHooks) Copies standard code into a memory block and then writes a jump back into the function
    (the copied code must not contain short jumps that lead outside of it)
    MemPtr can optionally specify a pre-allocated memory address.
    If DuplicateHooks is true, Lua hooks are kept in both new and old code, otherwise they're moved to the new location.
    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.asm(code) Compiles Asm code and returns resulting binary as string
    mem.asmhook(p, code, size) Like autohook, but takes an Asm code string as parameter.
    Example (from MM7):
    mem.asmhook(0x441D4C, [[
    cmp dword [0xE31AF0], 0
    jnz absolute 0x441D51
    ]])

    Original Asm code:
    .text:00441D4C call sub_4C2E6C
    .text:00441D51 mov ecx, offset unk_511768

    Resulting Asm code:
    .text:00441D4C jmp @p
    .text:00441D51 mov ecx, offset unk_511768

    @p:
    cmp dword [0xE31AF0], 0
    jnz 0x441D51
    call sub_4C2E6C
    jmp 0x441D51

    mem.asmhook2(p, code, size) Like autohook2, but takes an Asm code string as parameter
    Example (from MM6):
    local p = mem.asmhook2(0x43C8E3, [[
    mov [edi], esi
    ]])

    Original Asm code:
    .text:0043C8E3 mov edi, offset CurrentEvtLines
    .text:0043C8E8 rep movsd

    Resulting Asm code:
    .text:0043C8E3 jmp @p
    .text:0043C8E8 rep movsd

    @p:
    mov edi, offset CurrentEvtLines
    mov [edi], esi
    jmp 0x43C8E8

    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)
    Function f is as follows: f(d, def, params...)
    Here d is HookData object, def is the default function defined as def(params...) and params... are the parameters.
    mem.hookcall(p, nreg, nstack, f) Replaces an existing CALL instruction and uses the same protocol as hookfunction
    mem.luaproc(f, nreg, nstack) Creates a Lua callback (because any use of FFI for function calls leads to random bugs)
    mem.nop(p, n) Writes n NOPs. If n is omitted, replaces a single instruction at the given address with 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, detectClones, limit)
    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.
    RespectMonsterExp
    Set it to true to take experience from map monster structure rather than from monsters.txt based on monster Id.
    In MM8 only Armageddon uses monster XP from monsters.txt, other ways of killing monsters use experience value from monster structure.

     Functions:
    HookManager
    (ref)
    Allows switching all hooks installed by it on/off. ref table is used for substitutions in Asm code: "%key%" is replaced with ref[key], "%%" is replaced with "%". All hook functions are supported, but memory-editing arrays are supported through set function.
    Example 1 – substitution:
    local ArtifactBonus = mem.StaticAlloc(8)
    HookManager{
    buf = ArtifactBonus,
    }.asmhook2(0x48F60A, [[
    mov [%buf%], eax
    mov [%buf%+4], ecx
    ]])

    Example 2 – on/off:
    local hooks
    function ArcomageRequireDeck(on)
    if hooks then
    hooks.Switch(not on)
    elseif not on then
    hooks = HookManager()
    hooks.nop(0x4B3A06) -- no arcomage deck requirement
    hooks.nop(0x4B8A31) -- no arcomage deck requirement
    end
    end

    Example 3 – editing memory:
    local hooks = HookManager()
    hooks.set('i4', 0x469BBE+1, 0x10000) -- instead of mem.prot(true); mem.i4[0x469BBE+1] = 0x10000; mem.prot(false)
    hooks.set('u2', 0x472FB7, 0x9090) -- instead of mem.prot(true); mem.u2[0x472FB7] = 0x9090; mem.prot(false)
    hooks.asmpatch(0x472F5E, "add eax, ecx", 2)
    DisableVFlipFix = |on| hooks.Switch(not on)

    P.S. Don't try to run the code of these examples, they are for illustration.
    CallDefaultWindowProc
    (Msg, WParam, LParam)
    EnableLuaDataCompression
    (on)
    FixVFlip
    ()
    [MM6] Turns off texture flip on horizontal outdoor surfaces. Note that the editor accounts for vertical flip, so you probably shouldn't ever call this function.
    EnableMonstersCastingAnimation
    (on)
    [MM7+] Makes monsters play their regular attack animation rather then idle animation when casting damage spells if on is true.
    IsAttackOnPlayer
    ()
    As first value returns true if the target of attack currently being handled is a player, false if it's a monster
    As second value returns attack information structure as returned by WhoHitMonster and WhoHitPlayer functions
    WhoHitMonster
    ()
    If a monster is being attacked, returns t, TargetMonsterIndex.
    t.Player and either t.PlayerSlot[MM6-7] or t.PlayerIndex[MM8] are set if monster is attacked by the party.
    t.Monster, t.MonsterIndex and t.MonsterAction fields are set if monster is attacked by another monster.
    t.Object and t.ObjectIndex are set if monster is hit by a missile.
    t.Spell, t.SpellSkill and t.SpellMastery are set if a spell is being used.
    Note that t.Object can be set at the same time as t.Monster or t.Player.
    WhoHitPlayer
    ()
    If a player is being attacked, returns t, PlayerSlot.
    t.Monster, t.MonsterIndex and t.MonsterAction fields are set if player is attacked by a monster.
    t.Object and t.ObjectIndex are set if player is hit by a missile.
    t.Spell, t.SpellSkill and t.SpellMastery are set if a spell is being used.
    Note that t.Object and t.Monster can be set at the same time if the projectile was fired by a monster.


    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\ evtdeco.lua

     Functions:
    evt.Decompile
    (fileName, funcMode, outFile, asTxt)


    Core\ main.lua

     Variables:
    mem.EditPChar
    Editable PChar
    mem.ConstPChar
    Editable write-protected PChar

     Functions:
    mem.allocMM
    (size)
    Calls allocation function that MM uses for most of things. Note that my patch intersects these calls and uses Delphi memory manager to do the allocation.
    mem.freeMM
    (p)
    Free memory allocated by mem.allocMM.
    mem.reallocMM
    (p, OldSize, NewSize, NoFree)
    Resizes memory, reallocating as necessary, preserving content. Returns new (or the same if no reallocation occured) address.
    If NoFree is true, the memory at p isn't freed. This is useful for extending static arrays of the game.
    p can be a sctrucure, in which case its '?ptr' field is modified automatically.
    mem.resizeArrayMM
    (t, n)
    Resizes an array allocated with mem.allocMM function. n is the new count.
    MessageBox
    (text, caption, typ)
    typ can be a numeric value that MessageBox WinAPI function accepts or one of predefined strings: "error" (OK), "warning" (OK), "warn" (OK/Cancel), "confirm" (OK/Cancel), "confirmsnd" (OK/Cancel). Returns a number returned by the WinAPI funciton: 1 – OK, 2 – Cancel.
    debug.Message
    (...)
    Shows debug console. Message includes file name and line number, and than each argument is added to the message as a new line of text.
    debug.ErrorMessage
    (msg)
    ErrorMessage
    (msg)
    AddScriptsPath
    (s)
    ReloadLocalization
    ()


    Core\ npc.lua

     Functions:
    FindHiredNPC
    (NPC)
    Finds the prototype NPC in Game.NPC array for the supplied hired NPC. Returns nil if it's a street NPC.
    HireAllPeasants
    (on)
    [MM7] Normally first level of each peasant kind just talls you some news and can't be hired. Pass on = true to this function to make all peasants hireable.
    Pass on = nil to obtain current state of it.
    GetCurrentNPC
    ()
    Returns NPC index
    GetCurrentAnyNPC
    ()
    Returns NPC, Index, Kind
    ArcomageRequireDeck
    (on)
    [MM7] Pass false to remove the deck requirement.
    Pass on = nil to obtain current state of it.
    TrainPerWeek
    (n)
    [MM7+] Set number of levels the party can train per training session. 0 means any number of levels, as in MM6. 1 is MM7+ default. If n isn't specified, returns current setting.
    SkillToHouseTopic
    (i)
    HouseTopicToSkill
    (i)


    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 each time a week passes:
    RefillTimer(RefillWell, const.Week)


    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 1 (recommended):
    function Keys.F2(t)
    Message("F2 pressed")
    end

    Example 2 (not recommended):
    Keys[const.Keys.F2] = function()
    Message("F2 pressed")
    end

    These examples are actually handled differently. The first one is equivalent to using events.KeyDown and checking t.Key.
    The second is mostly for backward compatibility. Instead of relying on messages, it checks key state on every frame and calls the function if the key was pressed. It may miss a very short key press.

     Functions:
    timeGetTime
    ()
    Returns time since Windows has started in milliseconds
    Timer
    (f, Period = const.Minute, [Start,] [PastAware,] [Exact])
    f = function(TriggerTime, Period, LastTick, Tick):
    Function to call when the timer is triggered.
    Start defaults to Game.Time + Period if not specified (unless PastAware = true, in which case it deafults to Game.Time).
    PastAware = remember last visit time and fire right away if timer condition was met in the period of your absence.
    Defaults to true if Start is specified and false otherwise.
    Possible Exact values:
    false: re-fires after at least 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, NoYield)
    Sleep2
    (f, time, realtime, screens)
    RemoveTimer
    (f)
    You can remove the timer being executed by calling this function without a parameter
    Keys.IsPressed
    (key)
    String representations of const.Keys are also supported, e.g. Keys.IsPressed"SHIFT"
    Keys.IsToggled
    (key)
    String representations of const.Keys are also supported, e.g. Keys.IsToggled"CAPSLOCK"


    Modules\ Faces.lua

    Together with PaperDoll.lua can be used to create new character portraits and voices, or add them from other games. Unlike PaperDoll.lua, everything here is 0-based. If included, creates and/or loads "Faces.txt" and "Face Animations.txt" data tables.

    Including the module:
    local P = require"Faces"


    You can add extra columns into "Faces.txt":
    AllowVoice[MM7+] Enable/disable selecting voice on start (if not specified, the value of Allow is used).
    Voice[MM7+] Use specified default voice instead of the one with the same number as the face.
    Expressions – Expressions list to use. Default is "Expressions". Use if you combine MM6 faces with faces from other games.
    Sounds – Sounds list to use. Default is "Sounds". Use if you combine MM6 voices with faces from other games.
    SoundsOffset – This value will be added to the sound id (the one being searched in dsounds.bin). You will need this if you add voices from all 3 games.

    Note that AllowVoice, Female, Sounds and sound counts are properties of voice, the rest are properties of face. If you leave any field empty, the default value would be used.

    You can add extra columns into "Face Animations.txt". If their names are valid identifiers, thay would be read as lists. E.g. imagine you've added MM6 characters into another game – then you can add "Expressions6" and "Sounds6" columns there and set Expressions and Sounds columns for these characters to "Expressions6" and "Sounds6" respectively. You would however also need to join PFT.txt files and replace indexes in expressions lists accordingly.

    The way animations work: random expression is picked from the list in "Expressions" column of "Face Animations.txt" (or "Expressions6" column in the above example). This number is looked up in PFT.txt and the animation is played. Expression 21 is special – it shows the character speaking the voice line as long as it lasts.
    When it comes to voice, sound index is picked at random from the "Sounds" column list (or "Sounds7" in the above example), then sounds count for the voice is looked up and one of the variations of the sound is played. Up to 2 variations are supported.

     Variables:
    P.ExtraFields
    You can define you own functions to read extra fields from Faces.txt
    P.Faces
    P.FaceAnimations

     Functions:
    P.Update
    ()
    Call it if you change Faces table manually. Triggers UpdateFaces event.


    Modules\ KeepLogs.lua

     Functions:
    ViewLog
    (n)
    Shows contents of console log from previous run of the game.
    n is the log index or 0 to show current output log.


    Modules\ PaperDoll.lua

    To use, first place the PaperDol.txt file from here corresponding to your game of choice into DataFiles folder (create it right next to Data folder of the game if it doesn't exist). Modify it as needed. You'll later distribute this file inside a LOD achive of your mod.

    Including the module:
    require"PaperDoll"


    How it works:
    PaperDollDrawOrder defines the order in which pieces of body and clothing are drawn. PaperDollHiddenPieces event can be used to change which pieces would be drawn. PaperDol.txt can specify custom graphics and coordinates for any piece. Lines further in the table take precedence. If Doll includes current player, Piece matches piece being drawn and ItemPicture matches picture of the item being drawn (or ":Player" for a piece of player body), specified Image, X and Y values are used.
    A special case is when you specify item slot as ItemPicture, e.g. ":Armor". In this case X and Y act as offsets added to whatever coordinates are specified for the item in Armor slot. If you specify Mul for a slot, coordinates of the item are multiplied by it. It can also contain 4 values "a1,a2,a3,a4" that work this way: x = a1*X + a2*Y; y = a3*X + a4*Y. Setting Mul to "0,-1,1,0" or similar 90 degree rotation matrices would cause the item to be drawn rotated in MM8.

    Coordinates are given relative to the following point:
    MM6 and MM7 – (481, 0), MM8 – (467, 23).
    You can change it by modifying Game.DialogLogic.PaperDollPositionX and Game.DialogLogic.PaperDollPositionY, but changing it only affects paper doll position and not BACKDOLL or interface above paper doll.

    Options for ItemPicture values:
    item1 Override "item1" graphics
    :Player Override piece of the body
    :ExtraHand.item1 Override "item1" graphics if equipped in the second hand
    :Player:if:Armor Override piece of the body if any Armor is equipped
    :Player:if.item1 Override piece of the body if "item1" is equipped
    :Player:if:Armor.item1 Override piece of the body if "item1" is equipped as Armor
    :Belt:if:Armor.item1 Override any belt if "item1" if equipped as Armor
    :Belt.item2:if:Armor Override "item2" equipped as Belt if anything is equipped as Armor
    :Belt.item2:if.item1 Override "item2" equipped as Belt if "item1" is equipped
    :Belt.item2:if:Armor.item1 Override "item2" equipped as Belt if "item1" is equipped as Armor

    "insert" command:
    ItemPicture may start with ":insert" in order to insert a new piece to draw into PaperDollDrawOrder. It's an alternative to doing that in Lua code. TODO: I'll describe it some other day.

     Variables:
    PaperDollCategories
    Maps category name to a function(i) that returns true if player face number i belongs to the category. Use PaperDollAddBodies or PaperDollAddRace to populate in a custom way.
    PaperDollMainPieces
    Specifies which pieces inherit item graphics by default. For slots not specified here piece with empty name is the main one.
    Default:
    {ExtraHand = {hand2 = true, shield = true}, Gauntlets = {ring = true}, Amulet = {ring = true}, Ring1 = {ring = true}, Ring2 = {ring = true}, Ring3 = {ring = true}, Ring4 = {ring = true}, Ring5 = {ring = true}, Ring6 = {ring = true}}
    PaperDollBaseRace
    [MM7] Races that share the "Base" paper doll. Default:
    {[const.Race.Human] = true, [const.Race.Goblin] = true, [const.Race.Elf] = true}
    After altering it, call this command:
    PaperDollAddRace('Base', PaperDollBaseRace)
    PaperDollSpecialBodies
    After altering it, call PaperDollAddBodies. Here are default MM8 values:
    {[20] = 'Minotaur', [21] = 'Minotaur', [22] = 'Troll', [23] = 'Troll', [24] = 'Dragon', [25] = 'Dragon'}
    PaperDollTwoHandedSpear
    If set to true (default in MM6 and MM7), spears are treated as two-handed weapons when used without a second weapon. Gets initialized according to game version.
    PaperDollDrawOrder
    List of things to draw in the form of "Slot.Piece.DrawStyle" (or "Slot.Piece", or "Slot").
    Slot is either one of the wearable item slots (e.g. "Bow") or a pseudo-slot like "Player".
    Piece defines what element of that item gets drawn.
    DrawStyle can be set to "opaque" for opaque bitmaps ("red" and "green" are also supported) or "rect" to have the whole item rect count as item in regards to clicks.

    Default:
    {'BackDoll..opaque', 'BackDoll.menu.opaque', 'BackDoll.game.opaque',
    'BeginDoll', 'Bow', 'Cloak',
    'Armor.back', 'Belt.back',
    'Player', 'Player.arm1', 'Player.arm1f', 'Player.arm2b', 'Player.arm2hb', 'Player.arm2fb', 'Player.shield', 'Player.hair',
    'Armor.back2', 'Helm.back', 'Boots.back',
    'Armor', 'Boots',
    'Armor.front', 'Armor.arm1', 'Armor.arm1f',
    'Belt',
    'Player.arm2', 'Player.arm2h', 'Armor.arm2', 'Armor.arm2h', 'Player.arm2f',
    'Cloak.scarf', 'Player.scarf', 'Helm', 'Cloak.scarf2',
    'MainHand',
    'Player.hand1a', 'Player.hand1', 'Player.hand1f', 'Armor.hand1a', 'Armor.hand1', 'Armor.hand1f',
    'ExtraHand.hand2', 'ExtraHand.shield',
    'Player.hand2', 'Player.hand2f', 'Player.hand2h', 'Armor.hand2', 'Armor.hand2f', 'Armor.hand2h',
    'EndDoll', 'Magnify.noring',
    'BackHand.ring', 'Border.good', 'Border.evil', 'Border.neutral',
    'Ring1.ring.rect', 'Ring2.ring.rect', 'Ring3.ring.rect', 'Ring4.ring.rect', 'Ring5.ring.rect', 'Ring6.ring.rect', 'Amulet.ring.rect', 'Gauntlets.ring.rect',
    'Magnify.ring',
    }


    See PaperDollHiddenPieces event for conditions under which each piece is visible.

     Functions:
    PaperDollAddRace
    (name, races)
    PaperDollAddBodies
    (bodies)
    Defines doll categories for bodies array together with male and female variations of each.
    If bodies table isn't specified, uses PaperDollSpecialBodies table and defines the "Base" paper dolls as well.
    AddPaperDollGraphics
    (t)
    t can be a string following the "PaperDol.txt" convention or a table that's similar to the result of calling ParseNamedColTable for such file.
    Example – loading additional paper doll file for mods:
    events.ReloadPaperDollGraphics = || AddPaperDollGraphics(Game.LoadTextFileFromLod'PaperMod.txt')
    ReloadPaperDollGraphics
    ()
    Reloads "PaperDol.txt" and calls ReloadPaperDollGraphics event. Very handy while tweaking "PaperDol.txt"



    Structures


    Game

     Fields:
    Version (6 – 8)
    Arcomage [MM7+]
    Races [MM7]
    Classes
    ClassKinds
    Party
    Map
    Mouse
    Weather
    Screen
    PatchOptions
    CustomLods
    WindowHandle
    Windowed
    CurrentPlayer
    SkillRecoveryTimes[skill]
    MinMeleeRecoveryTime
    CurrentScreen :const.Screens
    CurrentCharScreen :const.CharScreens
    MainMenuCode -1 = in game, 0 = in main menu, 1 = show new game, 2 = show credits, 3 = show load menu, 4 = exit, 5 = loading game, 6 = in new game screen, 8 = in credits, 9 = load game, 10 = load level [MM7+]
    LoadingScreen
    DialogNPC
    NPCCommand
    HouseScreen
    HouseNPCSlot If Game.HouseOwnerPic isn't 0, the value of 1 refers to the shop keeper and higher value needs to be reduced by 1 before accessing .
    If Game.HouseExitMap isn't 0, last slot is occupied by map enter icon.
    HouseNPCSlotsCount
    HouseCost
    HouseAllowAction
    HouseActionInfo
    HouseTeachMastery
    HousePicType
    HouseOwnerPic
    HouseExitMap
    HouseNPCs[] If Game.HouseExitMap isn't 0, last slot is occupied by map enter pseudo-NPC.
    HouseItemsCount Number of interactive items of the dialog. Items count of the dialog object gets changed to this or 0 depending on selected player being concious.
    DialogsArray[]
    DialogIndexes[]
    Dialogs[] List of currently open dialogs, from lowest to topmost. Doesn't include object-oriented dialogs in MM8.
    Dialog at index 0 contains adventure interface that you see when no dialog is open. Even when you boot into the main menu, this dialog is present.
    CurrentNPCDialog
    CurrentHouseDialog
    InQuestionDialog [MM8]
    OODialogs [MM8]
    OODialogPtr [MM8] Same as Game.OODialogs.CurrentDialogPtr
    GuildJoinCost[]
    StatsNames[stat]
    StatsDescriptions[stat]
    SkillNames[skill]
    SkillDescriptions[skill]
    SkillDesNormal[skill]
    SkillDesExpert[skill]
    SkillDesMaster[skill]
    SkillDesGM[skill] [MM7+]
    ClassNames[class]
    ClassDescriptions[class]
    Actions[]
    ActionsNext[] [MM7+]
    ExitMapAction :const.ExitMapAction
    FlashHistoryBook [MM7]
    FlashAutonotesBook [MM7]
    FlashQuestBook [MM7]
    NeedRedraw
    StatusMessage
    StatusMessageBytes[]
    MouseOverStatusMessage
    MouseOverStatusMessageBytes[]
    StatusDisappearTime
    NeedUpdateStatusBar [MM7+]
    FoodGoldVisible [MM7] Set it to false to skip 1 draw call of drawing food and gold
    TextInputLimit
    TextInput
    TextInputBytes[]
    TextInputLength
    TextInputMode
    TextInputDialog
    EscMessageLastScreen
    EscMessageDialog
    NPCMessage Current message displayed in a dialog with some NPC
    StreetMessage Message displayed by Message, Question, evt.SimpleMessage and evt.Question when not talking to NPC.
    DelayedFaceAnimation.Delay
    DelayedFaceAnimation.Animation
    DelayedFaceAnimation.PlayerIndex
    ItemsTxt[]
    StdItemsTxt[]
    SpcItemsTxt[]
    ScrollTxt[]
    PotionTxt[][]
    PotNotesTxt[][] [MM7+]
    MonstersTxt[]
    PlaceMonTxt[] [MM7+]
    MapStats[]
    MapDoorSound[]
    MapFogChances[]
    FlyCeiling [MM6, MM7] 3000 in MM6, 4000 in MM7+, in MM8 it's configured per map (Map.OutdoorExtra.Ceiling)
    MoveToMap
    ProgressBar
    DialogLogic
    Lucida_fnt
    FontLucida
    Smallnum_fnt
    FontSmallnum
    Arrus_fnt
    FontArrus
    Create_fnt
    FontCreate
    Comic_fnt
    FontComic
    Book_fnt
    FontBook
    Book2_fnt
    FontBook2
    Cchar_fnt [MM6, MM7]
    FontCchar [MM6, MM7]
    Autonote_fnt
    FontAutonote
    Spell_fnt
    FontSpell
    TextBuffer
    TextBufferBytes[] Lets you get address of TextBuffer or access it byte by byte (note: traversing it like that is very slow)
    TextBuffer2
    TextBuffer2Bytes[] Lets you get address of TextBuffer2 or access it byte by byte (note: traversing it like that is very slow)
    WordWrappedText
    WordWrappedTextBytes[] Lets you get address of WordWrappedText or access it byte by byte (note: traversing it like that is very slow)
    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
    MaxBirthYear
    NeedRender Same as Party.NeedRender
    TurnBased
    TurnBasedPhase 1 = monsters move, 2 = combat, 3 = party walking
    TurnBasedDelays[]
    RedbookHandle
    MSSHandle
    BinkVideo [MM7+]
    DialogTopicsLimit [MM7+]
    SmackVideo
    EquipStat2ItemSlot[]
    MonsterClassSex[] [MM7] MonClass = (Id + 2):div(3)
    MonsterClassRace[] [MM7] MonClass = (Id + 2):div(3)
    MonsterSex[] [MM6]
    MonsterClassInfoY[]
    Paused Game logic is paused
    Paused2 Updates of 3D view are paused
    TimeDelta Time since last tick
    TimeDelta2 Time since last tick of updating 3D view
    PauseCount See Game.Pause and Game.Resume
    PauseCount2 See Game.Pause2 and Game.Resume2
    FrameCounter
    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.
    GuildAwards[]
    GuildItemIconPtr[slot] Loaded icons for current guild's items.
    Example:
    function events.GuildItemsGenerated(t)
    local a = Game.GuildItems[t.House][0] -- items array for this guild (for MM6 and MM7)
    a[0]:Randomize(5, const.ItemType.Book) -- put random powerful book into first slot
    a[0].Identified = true
    Game.GuildItemIconPtr[0] = Game.IconsLod:LoadBitmapPtr(a[0]:T().Picture)
    end

    ShopNextRefill[house]
    GuildNextRefill[house]
    ShopWeaponKinds[]
    ShopWeaponKindsSpecial[]
    ShopArmorKinds[][]
    ShopArmorKindsSpecial[][]
    ShopMagicLevels[]
    ShopMagicLevelsSpecial[]
    TrainingLevels[]
    GuildSpellLevels[]
    ShopAlchemistLevels[] [MM7+]
    ShopAlchemistLevelsSpecial[] [MM7+]
    ShopTheftExpireTime[] [MM7+]
    GeneralStoreItemKinds[] [MM6]
    GeneralStoreItemKindsSpecial[] [MM6] Yes, MM6 generates special items in general stores, but doesn't support buying them.
    ShopBackgroundByType[]
    ScanlineOffset[] [MM6, MM7]
    ObjectByPixel[y][x]
    ArmageddonTimeLeft maximum is 417
    ArmageddonSkill damage is 50 + skill
    OutdoorViewMul Acts as the opposite of FOV
    OutdoorViewDiv = math.floor(0x10000/Game.OutdoorViewMul)
    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[]
    NPCProfNames[]
    NPCNames[][] [MM6, MM7]
    NPCProfTxt[] [MM6, MM7]
    NPCNamesCount[] [MM6, MM7]
    StreetNPC[]
    Spells[]
    SpellsTxt[]
    SpellSounds[]
    SpellObjId[]
    TitleTrack
    TitleTrackOffset
    NarratorTrack [MM6]
    MissileSetup[]
    SummonElementalA [MM7+]
    SummonElementalB [MM7+]
    SummonElementalC [MM7+]
    QuestsTxt[]
    AwardsTxt[]
    AwardsSort[]
    AutonoteTxt[]
    AutonoteCategory[] [MM7+] 0 = potion
    1 = stat
    2 = obelisk
    3 = seer
    4 = misc
    5 = teacher
    AutonotesByCategory[][] [MM6]
    MerchantTxt[][]
    CtrlPressed
    RightButtonPressed
    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
    WinMapIndex Number represented as a string.
    [MM6] Index in games.lod
    [MM7+] Index in mapstats.txt
    GlobalEvtLines[]
    MapEvtLines[]
    SFTBin
    DecListBin[]
    PFTBin[]
    IFTBin[]
    TFTBin[]
    ChestBin[]
    OverlayBin[]
    ObjListBin[]
    MonListBin[]
    SoundsBin[]
    TileBin[]
    Tile2Bin[] [MM8]
    Tile3Bin[] [MM8]
    CurrentTileBin [MM8]
    ExitLevelCode 0 = in game, 2 = load other map, 8 = death
    SoundVolume
    PlayerFaces[]
    StandardFaceAnimations[]
    StandardPlayerSoundsCount[][]
    GamesLod
    IconsLod
    BitmapsLod
    SpritesLod
    SaveGameLod
    EnglishTLod [MM8]
    EnglishDLod [MM8]
    EventsLod [MM7]
    dist_mist
    IsD3D
    RendererD3D [MM7+]
    ModelClimbRequirement [MM7+] Minimum required Z coordinate of the normal to climb a building surface. MM6 default is 1 (any non-vertical surface), MM7+ default is 46378, which corresponds to Lua[[46378/0x10000 = 0.7]].
    RandSeed
    IsMovieLooped
    MovieKind 0 – No movie, 1 – Smack, 2 – Bink
    MonsterKinds[] [MM7+]

     Functions:
    ExitHouseScreen()
    OODialogProcessKey() [MM8]
    GetAdventureInnInfo() [MM8] Returns PlayerIndex, InInventory or nothing if Adventure Inn dialog isn't active.
    PlayerIndex is the index of currently selected player in Party.PlayersArray. Compare it against Party.PlayersIndexes[Party.CurrentPlayer] to see if selected player is part of the party.
    InInventory is true if player inventory (or Stats, Skills, Awards) screen is open.
    ProcessActions()
    Rand()
    DoPause() Pauses game logic
    DoResume() Resumes game logic
    Pause() Pauses game logic, increments Game.PauseCount by 1 and updates Game.BackupPaused
    Resume() Subtracts 1 from Game.PauseCount and resumes game logic upon reaching 0 if the the game wasn't paused before Game.Pause was called
    DoPause2() Pauses updating 3D view (honored by the game only if logic is also paused)
    DoResume2() Resumes updating 3D view
    Pause2() Pauses updating 3D view, increments Game.PauseCount2 by 1 and updates Game.BackupPaused2 (honored by the game only if logic is also paused)
    Resume2() Subtracts 1 from Game.PauseCount2 and resumes updating 3D view upon reaching 0 if the the game wasn't paused before Game.Pause2 was called
    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.
    IsMoviePlaying() [MM7+]
    LoadHouseMovie(Name, Loop = true)
    EndMovie()
    RestartHouseMovie()
    PlayShopSound(House, SoundIndex)
    GetNPCPtrFromIndex(Index) [MM7+]
    GetCurrentNPCPtr()
    CalcSpellDamage(Spell, Skill, Mastery, MonsterHP)
    GetSpellDamageType(Spell)
    GetStatisticEffect(Stat)
    SummonMonster(Id, X, Y, Z)
    SummonObjects(Type, X, Y, Z, Speed, Count = 1, RandomAngle = false, Bits = 0, pItem [MM7+]) This function is called by evt.SummonObject internally. If you specify the pItem parameter, it will only work properly in MM8.
    GenerateChests() You can add random items (Number = -1 to -6 for different power or -7 for artifact) to some chests and then call this function to generate them
    IsMonsterOfKind(Id, Kind) [MM7+]
    FileRead(pTarget, Size, Count, FileStream) Reads Size*Count bytes from FileStream into pTarget buffer. The FileStream can be obtained by calling FindFile method of a Lod archive.
    FileSeek(FileStream, Offset, Origin = 0) Sets current position of FileStream.
    Origin = 0 sets absolute position to Offset.
    Origin = 1 adds Offset to current position.
    Origin = 2 sets position to end of file plus Offset.
    FileTell(FileStream) Returns current position of FileStream.
    Uncompress(pTarget, pTargetSize, pSrc, SrcSize) pTargetSize must point to a 4-byte buffer specifying unpacked size.
    Compress(pTarget, pTargetSize, pSrc, SrcSize, Compression[MM7+] = -1) pTargetSize must point to a 4-byte buffer specifying max size. The function sets it to actual size it has used up. If successful, returns 0.
    PlayMapTrack()
    PlayTrack(Index)
    LoadSound(SoundId, Unk = 0, Unk2 = 0) Unk2 is present only in MM8
    PlaySound(SoundId, Object = 0, Loops = 0, X = -1, Y = 0, Unk = 0, Volume = 0, PlaybackRate = 0) Each object kind has a number of sound channels to use. Special Object values of '-1' and '-2' also have 1 channel reserved for each (lower values have the same effect as '-2'). So, when many sounds are played at once you could use one of these negative values instead of the default Object = 0.
    StopAllSounds(KeepMin = -1, KeepMax = -1)
    LoadDecSprite(Name) Loads a sprite and returns its ID.
    LoadBitmap(Name) Loads a texture and returns its ID.
    UpdateDialogTopics()
    NewDialog(Left, Top, Width, Height, DlgID, Param, StrParam, InitProc, InitParam) If specified, InitProc(dlg, InitParam) is called before any calls to the NewDialog event.
    GetDialogFromPoint(Returns the dialog that the mouse is over.)
    GetButtonFromPoint(Returns item, dialog that the mouse is over. Uses the logic of hint updates rather than clicks. That is, stops iteration upon finding an item in specified position or encountering a dialog with Height equal to 480, beyond which it wouldn't go.
    Note that the logic of clicks is generally less permissive: it's GetDialogFromPoint followed by GetFromPoint of said dialog.)
    GetTopDialog(Returns the dialog that the mouse is over.)
    ShowStatusText(Text, Seconds = 2, NoRedraw)
    ShowStatusHint(Text, AcceptEmpty) Unless AcceptEmpty is true, passing an empty string won't do anything.
    EscMessage(Text, ActionOnClose = 0)
    StartTextInput(MaxLength = 50, Numerical = false, Dialog = nil)
    EndTextInput(State)
    LoadPalette(PalNum)
    LoadDataFileFromLod(Name, UseMalloc)
    LoadTextFileFromLod(Name)
    CanLoadFileFromLod(Name) Returns true if specified file exists in LOD archives that LoadTextFileFromLod and LoadTextFileFromLod functions use.
    The archives are: icons.lod in MM6, events.lod in MM7, EnglishD.lod and EnglishT.lod in MM8.
    LoadPcx(Name, PcxBuffer, FromEnglishD = false, LoadKind = 0) Returns loaded pcx. PcxBuffer can be nil, a pcx strucutre or a pointer to the buffer. If it's nil, the buffer gets allocated and must freed via a call to Destroy function.
    LoadFont()
    GetCurrentHouse()
    GetCurrentNoHouseNPC()
    GetNPCFromPtr()
    GetNPCFromIndex()


    Party

     Fields:
    Pos[]
    X
    Y
    Z
    Direction 0 – 2047. 0 is East, 512 is North and so on.
    LookAngle -512 – 512. Values allowed with mouse look: -240 – 300 (prior to patch 2.5: -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[] Array of all players
    PlayersIndexes[] [MM8] Array of players indexes in PlayersArray corresponding to each player slot
    Players[] (Default) Array of players corresponding to each player slot
    HiredNPC[] [MM6, MM7]
    HiredNPCName[] [MM6, MM7]
    LastRegenerationTime
    SpellBuffs[buff]
    Gold
    BankGold
    Food
    Deaths
    PrisonTerms
    BountiesCollected
    Fine [MM7+]
    BountyHuntTarget[] Only index 0 is normally used in MM8
    MonsHuntTarget[] (deprecated old name)
    BountyHuntKilled[] Only index 0 is normally used in MM8
    MonsHuntKilled[] (deprecated old name, integer in MM7+ instead of boolean)
    NextBountyHunt[]
    MonsHuntReset[] (deprecated old name)
    QBits[]
    AutonotesBits[]
    InArenaQuest
    ArenaWinsPage
    ArenaWinsSquire
    ArenaWinsKnight
    ArenaWinsLord
    ArtifactsFound[]
    Alignment [MM7] 0 = good, 1 = neutral, 2 = evil
    Reputation
    History[] [MM7+]
    SpecialDates[] [MM7+] E.g. set date 1:
    evt.Add("SpecialDate1", 0)

    Use date 1: "%51" in any NPC message
    ArcomageWins[] [MM7+]
    CurrentPlayer
    StateBits
    NeedRender
    Drowning
    InAir
    EnemyDetectorRed
    EnemyDetectorYellow
    FlyingBit
    WaterWalkingBit
    InJumpSpell
    InLava

     Functions:
    RestAndHeal()
    Wait(Minutes)
    FindActivePlayer()
    GetFame()
    GetReputation()
    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, ...})
    GetCurrentPlayer()

     Methods:
    ResetStartingPlayer(arg1 = false, arg2 = false) [MM8]


    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 The day of refill plus 1
    OutdoorReputation [MM7+]
    OutdoorAlertState [MM7+]
    OutdoorSanityFacetsCount [MM7+]
    OutdoorSanitySpritesCount [MM7+]
    SanityModelsCount [MM7+]
    OutdoorExtra
    OutdoorLastVisitTime
    VisibleMap1[][]
    VisibleMap2[][]
    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 The day of refill plus 1
    IndoorExtra
    IndoorLastVisitTime
    VisibileOutlines[]
    IndoorReputation [MM7+]
    IndoorAlertState [MM7+]
    IndoorSanityFacetsCount [MM7+]
    IndoorSanitySpritesCount [MM7+]
    SanityDoorDataSize [MM7+] Added in MMExtension. Instead of being checked against, it actually replaces Map.IndoorHeader.DoorDataSize when loading the .dlv, if it's non-zero.
    Spawns
    RefillCount
    LastRefillDay The day of refill plus 1
    Extra
    LastVisitTime
    Reputation [MM7+]
    AlertState [MM7+]
    SanityFacetsCount [MM7+]
    SanitySpritesCount [MM7+]
    SpriteLights[] [MM7+]

     Functions:
    RemoveObject(Index)
    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() Returns ObjectRef of current mouse target
    GetPos() Returns floating-point mouse position that includes sub-pixel difference caused by upscaling.
    In UILayout mode this is the only way to find mouse coordinates when it's over 3D view. Mouse.X and Mouse.Y would just return the middle of the view. When mouse is over interface items, both this function and Mouse.X, Mouse.Y get coordinates within traditional interface to which UI layout is mapped.

     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.


    Screen

     Fields:
    IsD3D [MM7+]
    Width
    Height
    Pitch
    cx1
    cy1
    cx2
    cy2
    Buffer
    ObjectByPixel
    RedBits
    BlueBits
    GreenBits
    RedMask
    GreenMask
    BlueMask
    Pitch2 [MM7+]
    ClipTop [MM7+]
    ClipLeft [MM7+]
    ClipBottom [MM7+]
    ClipRight [MM7+]

     Methods:
    SaveToPcx(name, x = 0, y = 0, width = 640, height = 480) x, y, width, height can only be specified in MM6. MM7 and MM8 save a shot of whole screen area.
    SaveBufferToPcx(name, buf, width = 640, height = 480) [MM7+]
    SetClipRect(left = 0, top = 0, right = 640, bottom = 480) [MM7+]
    Draw(x, y, pic, style, rotate, EnglishD) style:
    "transparent", false – draw treating color index 0 as transparent (default)
    "opaque", true – draw without transparency
    "red" – draw broken item
    "green" – draw unidentified item
    Adding "p" in the beginning of style string signals that pic is a pointer to an image rather than its index. Note that "pred" and "pgreen" aren't supported in MM6.
    DrawItemEffect(x, y, shapePic, effectPic, palShift, palAnimateFrom, palAnimateTo, rotate, EnglishD, effectEnglishD)
    DrawToObjectByPixel(x, y, pic, index, rotate, EnglishD)
    DrawToObjectByPixelOpaque(x, y, pic, index, EnglishD) [MM7+]
    DrawPcx(x, y, LoadedPcx)
    DrawMessageBox(Dialog, Text = nil, SnapToViewBox = false) Draws a message box border with optional text inside.
    In place of Dialog you can pass a table in form of {Left, Top, Width, Height}.
    The function modifies the dialog position to make it fit on the screen. If you pass a table with box position and size, it's modified accordingly.
    If Text is specified or Dialog.StrParamPtr is not 0, the text is drawn in the middle of the dialog and dialog box is drawn with appropriate height, but dialog height is not modified to reflect that.
    DrawMessageBoxBorder(Left, Top, Width, Height) Draws a message box border.
    Minimal dimensions for proper display are 64.


    structs.ActionItem

     Fields:
    Action
    Param
    Param2


    structs.Arcomage

    [MM7+]

     Fields:
    StartingTower
    StartingWall
    StartingIncome[3]
    StartingIncomeBricks
    StartingIncomeGems
    StartingIncomeBeasts
    CardsCount Internally up to 10 cards are supported.
    MinIncome[3] If you change these values, StartingIncome and player income would also change.
    TowerToWin
    ResToWin
    StartingRes[3]
    StartingBricks
    StartingGems
    StartingBeasts
    AI 0 – 2
    Players[2] (Default) Player 0 is the human, player 1 is AI
    CardKinds[]
    Deck[]


    structs.ArcomageAction

    [MM7+]

     Fields:
    Income[]
    Res[]
    Damage
    Wall
    Tower


    structs.ArcomageActions

    [MM7+]

     Fields:
    PlayAgain
    DiscardCards
    Me
    Enemy
    All


    structs.ArcomageCard

    [MM7+]

     Fields:
    Name
    Sprite
    CostKind
    CostIncome[]
    CostRes[]
    Discardable
    If :const.ArcomageIf
    Then
    Else


    structs.ArcomagePlayer

    [MM7+]

     Fields:
    Name
    Human
    Tower
    Wall
    Income[3]
    Res[3]
    Cards[10]
    unk[10][2]


    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[]
    BitmapsCount
    RedBits
    GreenBits
    BlueBits
    NonTmpCount
    TmpIndex
    KeepCompressed
    IsHardware [MM7+]
    D3D_Surfaces[] [MM7+]
    D3D_Textures[] [MM7+]

     Methods:
    HasFile(name) Does a slow search for a file. For sorted LOD archives FindFile works faster.
    FindFile(name, unsorted = false) Finds a file and returns file stream address or 0 if file isn't found. By default performs fast binary search. Pass unsorted = true when searching in Game.GamesLod and Game.SaveGameLod, because these archives aren't sorted lexicographically and thus binary search can't be used for them.
    Returned file stream can be used in Game.FileRead, Game.FileSeek and Game.FileTell functions. Its position is set to the beginning of specified file.
    LoadBitmap()
    LoadBitmapPtr()
    LoadTFTBitmap()
    LoadBitmapInPlace(bmp, name, unused_must_be_2 = 2) Used for loading of progress bar bitmaps
    ReplaceBitmap(bmp, name, unused_must_be_2 = 2) [MM7+] Used for changing party faces and in MM7 for recoloring of interface. Assumes the new bitmap has the same dimensions.
    BeginTmp()
    EndTmp()
    Cleanup()


    structs.BlvHeader

     Fields:
    Name
    FacetDataSize
    RoomDataSize
    RoomLightDataSize
    DoorDataSize


    structs.Button

     Fields:
    Left
    Top
    Width
    Height
    RightPixel = Left + Width - 1 (it was called Right before MMExtension v2.3, old name is supported for backward compatibility)
    BottomPixel = Top + Height - 1 (it was called Bottom before MMExtension v2.3, old name is supported for backward compatibility)
    Shape 1 – Rectangle.
    2 – Ellipse. Left and Top are center coordinates, Width and Height are radii. In MM6 it's always a circle and Height is 0.
    3 – Skill rectangle.
    HintAction
    Action Was called ActionType before MMExtension v2.3, old name is supported for backward compatibility
    ActionParam
    ActionParam2 [MM7+]
    Pressed
    PrevItemPtr
    NextItemPtr
    Parent
    ParentPtr
    Sprites[] A list of pointers to associated icons
    Key Was called ShortCut before MMExtension v2.3, old name is supported for backward compatibility
    Hint

     Methods:
    Destroy() Make sure to update Parent.KeyboardItemsCount on your own if you delete one of them
    MoveBefore(Target) If Target is 0 or nil, moves the item to the end of the items list
    Note that first item in the list is topmost and the last one is at the bottom.
    MoveAfter(Target) If Target is 0 or nil, moves the item to the beginning of the items list


    structs.CurrentTileBin

    [MM8]

     Fields:
    Items[] (Default)


    structs.CustomLods

     Fields:
    RecordIndex
    Records[]

     Functions:
    Load(StdLod, Name)
    Free(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.DialogLogic

     Fields:
    List[] List of indexes to be displayed
    ScrollPage
    CountOnScreen
    ListCount
    ScrollPos
    AutonoteTab6Clicked [MM7+]
    AutonoteTab5Clicked
    MapMoveRightClicked
    AutonoteTab4Clicked
    MapMoveLeftClicked
    AutonoteTab3Clicked
    MapMoveDownClicked
    AutonoteTab2Clicked
    MapMoveUpClicked
    AutonoteTab1Clicked
    ScrollDownClicked
    ScrollUpClicked
    SpellBookSelection Selected spell index within current page (1..11)
    SpellBookSelectedNewSpell [MM7+]
    AutonotesCategory
    ArmorSkills[] [MM7+]
    WeaponSkills[] [MM7+]
    MiscSkills[] [MM7+]
    MagicSkills[] [MM7+]
    MonsterInfoMonster
    PlayerRingsOpen
    PaperDollPositionX
    PaperDollPositionY


    structs.Dlg

     Fields:
    Left
    Top
    Width
    Height
    RightPixel = Left + Width - 1 (it was called Right_ before MMExtension v2.3, old name is supported for backward compatibility)
    BottomPixel = Top + Height - 1 (it was called Bottom_ before MMExtension v2.3, old name is supported for backward compatibility)
    DlgID
    Param 2D Events Id / Chest Id / ...
    ItemsCount
    KeyboardItemsCount
    KeyboardItem
    KeyboardNavigationTrackMouse
    KeyboardLeftRightStep
    KeyboardItemsStart
    Index Current index in Game.Dialogs array.
    TextInputState
    UseKeyboadNavigation
    StrParam
    StrParamPtr
    FirstItemPtr
    LastItemPtr

     Methods:
    SetKeyboardNavigation(KeyboardItemsCount, KeyboardNavigationTrackMouse, KeyboardLeftRightStep, KeyboardItemsStart)
    GetItemPtrByIndex(Index)
    AddButton(Left, Top, Width, Height, Shape = 1, HintAction, ActionType, ActionParam, Key, Hint = "", [EnglishD] = true, Sprites...) Can also accept a table where some parameters are supplied by their name. In this case EnglishD and Sprites must be supplied by name.
    Returns button address and the wrap function. Pass the returned address to the wrap function to create a dialog item structure to access it.
    Example:
    -- make area to the left of first player portrait bring up the Maps dialog (note: this would interfere with object-oriented dialogs in MM8 and cause bugs when clicked inside them)
    local p, wrap = Game.Dialogs[0]:AddButton{0, 384, 31, 80, ActionType = 202, Hint = "Another Maps Button", Sprites = {"ib-td3-A"}}
    local btn = wrap(p)
    btn:MoveAfter(0) -- make it take priority over other buttons

    Destroy(KeepMonsterPicture [MM8])
    Enum(Backwards) To be used in a for statement. Enumerates dialog items returning item index, dialog item and the wrap function each time.
    If Backwards is true, enumeration goes in reverse order.
    Note that the same Lua table gets reused for the item structure during enumeration. If you want to create separate Lua tables for each item, use the Wrap function. Here's an example:
    local t = {} -- this table will be populated with all dialog items from adventure screen
    for i, it, wrap in Game.Dialogs[0]:Enum() do
    t[i] = wrap(it)
    end

    If you're wandering, the wrap function itself simply does the following: structs.Button:new(it['?ptr'] or tonumber(it))
    GetByIndex(Index) Returns dialog item at specified index in the items list.
    GetRelativePoint(X, Y) Returns relative coordinates or nothing if the coordinates don't fall within the dialog.
    GetFromPoint(X, Y, Absolute) Returns dialog item at specified relative or absolute coordinates.


    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
    OwnerPicture Was called PictureUnk before MMExtension v2.3, old name is supported for backward compatibility
    State
    Rep
    Per
    C
    Val
    A [MM7+]
    OpenHour
    CloseHour
    ExitPic
    ExitMap
    QBit Was called QuestBitRestriction before MMExtension v2.3, old name is supported for backward compatibility


    structs.FaceAnimationInfo

     Fields:
    Sounds[]
    Sound1
    Sound2
    Expressions[]
    Expression1
    Expression2
    Expression3
    Expression4
    Expression5


    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.Fnt

     Fields:
    MinChar
    MaxChar
    Height
    PalettesCount
    Palettes[]
    ABC[][]
    GlyphOffsets[]
    GlyphData[]

     Methods:
    GetLineWidth(Text)
    GetTextHeight(Text, Dialog = nil, X = 0, IgnoreStrRightSymbol = false [MM7+]) In place of Dialog you can pass a table in form of {Left, Top, Width, Height}.
    Calls WordWrap internally and stores the result in Game.WordWrappedText.
    WordWrap(Text, Dialog = nil, X = 0, IgnoreStrRightSymbol = false [MM7+], ReturnPointer = false) Returns text with extra line breaks inserted.
    In place of Dialog you can pass a table in form of {Left, Top, Width, Height}.
    If ReturnPointer = true, returns Game.WordWrappedTextBytes table instead of Lua string. You can then pass this table to any of the font methods.
    Draw(Text, Dialog = nil, X = 0, Y = 0, Color = 0, ShadowColor [MM7+], Bottom [MM7+], Opaque [MM7+]) In place of Dialog you can pass a table in form of {Left, Top, Width, Height}.
    If X is 0, in MM6 and MM7 it gets set to 12 by the function.
    Passing 0 as Color would draw text using default color.
    Unless Bottom is specified, it calls WordWrap internally and stores the result in Game.WordWrappedText.
    Bottom is specified in absolute coordinates, not relative to dialog. When specified, the text doesn't get word-wrapped, but doesn't get drawn below its value. If not specified, text gets ward-wrapped when it exceeds dialog width horizontally, but is not limited vertically.
    DrawLimited(Text, Dialog = nil, Width, X = 0, Y = 0, Color = 0, TruncateStart = false) In place of Dialog you can pass a table in form of {Left, Top, Width, Height}.
    X should not be 0 in MM6 and MM7, because it then gets set to 12 by the function if text fits and is kept at '0 if it doesn't.
    Passing 0 as Color would draw text using default color.
    If TruncateStart is true, end of the string is kept and beginning is truncated to fit the required size.
    Calls WordWrap internally and stores the result in Game.WordWrappedText.
    DrawCentered(Text, Dialog = nil, X = 0, Y = 0, Color = 0, ReduceLineHeight = 3) In place of Dialog you can pass a table in form of {Left, Top, Width, Height}.
    Passing 0 as Color would draw text using default color.
    Calls WordWrap internally and stores the result in Game.WordWrappedText.


    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.GeneralStoreItemKind

    [MM6]

     Fields:
    Level
    Items[1..6] (Default) If it's zero, random Boots or Gauntlets are generated.


    structs.HistoryTxtItem

    [MM7+]

     Fields:
    Text
    Title
    Time


    structs.HouseMovie

     Fields:
    FileName
    Background EVTPAR* index, 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 From STDITEMS.TXT. You can use const.Stats, just add 1 to a supported value from it.
    BonusStrength
    Bonus2 From SPCITEMS.TXT. Value in case of gold.
    Charges
    Identified
    Broken
    TemporaryBonus
    Stolen
    Hardened
    Refundable Added in patch v2.5.4. Used internally to remove artifacts generated in unopened chests from ArtifactsFound upon map refill.
    Condition
    BodyLocation
    MaxCharges
    Owner
    BonusExpireTime [MM7+]

     Methods:
    GetValue()
    GetName()
    GetIdentifiedName()
    GenerateArtifact()
    Clear()
    Randomize(Strength, Type, AlwaysEnchant [MM8]) Generates a random item. The chance that it would be enchanted depends on Strength. In MM8 you can guarantee its enchantment by passing true as AlwaysEnchant parameter.
    T() Returns ItemsTxt entry.
    InitSpecial() [MM7+] Sets up enchantments if the item is "Special" as marked by "material" column of items.txt


    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.LanguageLod

    [MM8]

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

     Methods:
    FindFile(name, unsorted = false) Finds a file and returns file stream address or 0 if file isn't found. Performs fast binary search (unless unsorted is set to true, which you shouldn't do for language LODs).
    Returned file stream can be used in Game.FileRead, Game.FileSeek and Game.FileTell functions. Its position is set to the beginning of specified file.


    structs.LanguageLodFile

    [MM8]

     Fields:
    Name
    Offset
    Size


    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

     Methods:
    HasFile(name) Does a slow search for a file. For sorted LOD archives FindFile works faster.
    FindFile(name, unsorted = false) Finds a file and returns file stream address or 0 if file isn't found. By default performs fast binary search. Pass unsorted = true when searching in Game.GamesLod and Game.SaveGameLod, because these archives aren't sorted lexicographically and thus binary search can't be used for them.
    Returned file stream can be used in Game.FileRead, Game.FileSeek and Game.FileTell functions. Its position is set to the beginning of specified file.


    structs.LodBitmap

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

     Methods:
    LoadBitmapPalette()
    Destroy()
    DestroyInPlace()


    structs.LodFile

     Fields:
    Name
    Offset
    Size


    structs.LodPcx

     Fields:
    BufSize
    Width
    Height
    WidthLn2
    HeightLn2
    WidthMinus1
    HeightMinus1
    Bits
    Image

     Methods:
    Destroy(FreeBuffer = true)


    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

     Methods:
    RefundArtifacts()


    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)
    IsPortal
    IsSecret [MM7+] show in red with Perception
    ScrollDown [MM7+] moving texture
    AlignTop [MM7+] align door texture in D3D
    IsWater
    ScrollUp [MM7+] moving texture
    ScrollLeft [MM7+] moving texture
    ProjectToXY
    ProjectToXZ
    ProjectToYZ
    ScrollRight [MM7+] moving texture
    AlignLeft [MM7+] align door texture in D3D
    Invisible
    AnimatedTFT
    AlignRight [MM7+] align door texture in D3D
    AlignBottom [MM7+] align door texture in D3D
    MoveByDoor
    IsEventJustHint [MM7+]
    AlternativeSound
    IsSky outdoor in software mode: horizontal flow
    FlipU
    FlipV
    TriggerByClick
    TriggerByStep
    DisableEventByCtrlClick [MM8] indoor only: click event gets disabled by Ctrl+Click
    EventDisabledByCtrlClick [MM8]
    TriggerByMonster [MM6, MM7] happens even if there's no event assigned
    TriggerByObject [MM6, MM7] happens even if there's no event assigned
    Untouchable great for vertical facets of stairs. [MM7+] Shouldn't be used for sloped floor, like it's used in MM6.
    IsLava
    HasData
    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

     Methods:
    GetData(Create) Returns Map.FacetData structure associated with the facet. If Create is true, the data gets automatically allocated if it doesn't exist.
    On outdoor maps the method returns the facet itself, because all data is inside its own structure.


    structs.MapLight

     Fields:
    Pos[]
    X
    Y
    Z
    Off
    Bits
    Brightness
    Radius
    R [MM7+]
    G [MM7+]
    B [MM7+]
    Type [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 [MM6] Index in Game.StreetNPC + 1
    [MM7+] Index in Game.NPC or index in Game.StreetNPC + 5000
    Active inside the active radius
    ShowOnMap monster was once seen by party
    Invisible
    NoFlee
    Hostile
    OnAlertMap
    TreasureGenerated treasure is in Items[0] and Items[1], gold is in Items[3]
    ShowAsHostile show as hostile on map
    IsObeliskChest [MM8]
    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.Necro [MM8]
    Prefers.Knight
    Prefers.Paladin [MM6, MM7]
    Prefers.Archer [MM6, MM7]
    Prefers.Druid [MM6, MM7]
    Prefers.Cleric
    Prefers.Troll [MM8]
    Prefers.Minotaur [MM8]
    Prefers.DarkElf [MM8]
    Prefers.Vampire [MM8]
    Prefers.Dragon [MM8]
    Prefers.Sorcerer [MM6, MM7]
    Prefers.Ranger [MM7]
    Prefers.Thief [MM7]
    Prefers.Monk [MM7]
    Prefers.Male in monsters.txt it's "M" in MM6 and "X" in MM7 and MM8
    Prefers.Female
    Prefers.Human [MM7]
    Prefers.Elf [MM7]
    Prefers.Dwarf [MM7]
    Prefers.Goblin [MM7]
    PrefClass Preferred target
    Bonus (steal, curse, ...)
    BonusMul Disease1x5 etc. The chance that a monster would use the bonus is Level*BonusMul
    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+]
    ElecResistance [MM6]
    ColdResistance [MM6]
    PoisonResistance [MM6]
    PhysResistance
    Special [MM7+] 1 = shot, 2 = summon, 3 = 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
    FramesGotHit
    FramesDie
    FramesDead
    FramesFidget
    Sounds[]
    SoundAttack
    SoundDie
    SoundGetHit
    SoundGotHit
    SoundFidget
    SpellBuffs[buff]
    Items[] [MM7+] Indexes 0 and 1 are used for stolen items, indexes 2 and 3 are used if TreasureGenerated bit is set: index 2 holds the item and index 3 holds the gold.
    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 [MM7+] From PlaceMon.txt

     Methods:
    IsAgainst(Mon2) [MM7+] Returns aggression number between 0 and 4. If Mon2 isn't specified, attitude towards party is checked.
    LoadFrames(SoundLoaded = false) If SoundLoaded = false, sound indexes would be loaded for the monster as well.
    ChooseTargetPlayer() Returns player slot index
    CalcTakenDamage(DamageKind, Damage) Returns the amount of damage the monster has to actually receive
    CalcHitByEffect(DamageKind) Returns true if the monster couldn't dodge the effect
    CalcHitOrMiss(Player)
    UpdateGraphicState() Updates GraphicState in accordance with AIState
    ShowSpellEffect(Color24 = 0) [MM7+] Shows effect from a spell (as a cylinder of colored dots around the monster)
    GotHit(By = 4, ResetAnimation = false) Shows monster's getting hit animation, produces sound and boosts aggression level. By is the attacker object reference value.
    PlaySound(SoundIndex) [MM7+] SoundIndex is from 0 to 3 or any of these corresponding strings: "Attack", "Die", "GotHit", "Fidget"
    LoadFramesAndSounds()
    ChangeLook(id) Takes on the look of another monster kind
    GetPropertiesFromId(id) Takes all properties, except appearance and sounds from another monster kind
    SetId(id) Changes Id and, if it's not 0, Id2
    SetCustomFrames(Stand, Walk, Attack, Shoot, Stun, GotHit, Die, Dead, Fidget) Any argument can be nil. Also loads the frames.
    GetIndex()


    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
    Spell same as SpellType
    SpellSkill
    SpellLevel
    SpellMastery same as 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, 4 – Explode
    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:
    HasNonVerticalPortals
    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
    TriggerByTouch only for "Event Trigger" sprites – triggered when a player comes into TriggerRadius
    TriggerByMonster only for "Event Trigger" sprites – triggered when a monster comes into TriggerRadius
    TriggerByObject only for "Event Trigger" sprites – triggered when an object gets into TriggerRadius
    ShowOnMap
    IsChest
    Invisible
    IsObeliskChest [MM7+]
    IsShip [MM6]
    Bits
    Pos[]
    X
    Y
    Z
    Direction
    Id [MM7+]
    EventVariable event variable for barrels etc.
    Event normal event
    TriggerRadius
    DirectionDegrees only used if Direction is 0


    structs.MapStatsItem

     Fields:
    Name
    FileName
    Monster1Pic
    Monster2Pic
    Monster3Pic
    ResetCount
    FirstVisitDay
    RefillDays
    AlertDays [MM7+]
    StealPerm [MM7+]
    Per [MM7+]
    Lock "x5 Lock" from MapStats.txt. In MM6 the condition for successful disarming is Lock*5 < player:GetDisarmTrapTotalSkill() + math.random(0, 9). In MM7+ the condition is Lock*2 <= player:GetDisarmTrapTotalSkill().
    Trap "D20's Trap" from MapStats.txt. The damage is Trap rolls of 1-20 damage.
    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.MissileSetup

     Fields:
    AlwaysShowSprite When there's a special way to display the object, still show the sprite as well
    HideSpecialDisplay Don't display the object in a special way
    AutoCollision When the object hits anything, show an explosion, play explosion sound of the spell and call MonsterAttacked or PlayerAttacked appropriately


    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)
    IsPortal
    IsSecret [MM7+] show in red with Perception
    ScrollDown [MM7+] moving texture
    AlignTop [MM7+] align door texture in D3D
    IsWater
    ScrollUp [MM7+] moving texture
    ScrollLeft [MM7+] moving texture
    ProjectToXY
    ProjectToXZ
    ProjectToYZ
    ScrollRight [MM7+] moving texture
    AlignLeft [MM7+] align door texture in D3D
    Invisible
    AnimatedTFT
    AlignRight [MM7+] align door texture in D3D
    AlignBottom [MM7+] align door texture in D3D
    MoveByDoor
    IsEventJustHint [MM7+]
    AlternativeSound
    IsSky outdoor in software mode: horizontal flow
    FlipU
    FlipV
    TriggerByClick
    TriggerByStep
    DisableEventByCtrlClick [MM8] indoor only: click event gets disabled by Ctrl+Click
    EventDisabledByCtrlClick [MM8]
    TriggerByMonster [MM6, MM7] happens even if there's no event assigned
    TriggerByObject [MM6, MM7] happens even if there's no event assigned
    Untouchable great for vertical facets of stairs. [MM7+] Shouldn't be used for sloped floor, like it's used in MM6.
    IsLava
    HasData
    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.Necro [MM8]
    Prefers.Knight
    Prefers.Paladin [MM6, MM7]
    Prefers.Archer [MM6, MM7]
    Prefers.Druid [MM6, MM7]
    Prefers.Cleric
    Prefers.Troll [MM8]
    Prefers.Minotaur [MM8]
    Prefers.DarkElf [MM8]
    Prefers.Vampire [MM8]
    Prefers.Dragon [MM8]
    Prefers.Sorcerer [MM6, MM7]
    Prefers.Ranger [MM7]
    Prefers.Thief [MM7]
    Prefers.Monk [MM7]
    Prefers.Male in monsters.txt it's "M" in MM6 and "X" in MM7 and MM8
    Prefers.Female
    Prefers.Human [MM7]
    Prefers.Elf [MM7]
    Prefers.Dwarf [MM7]
    Prefers.Goblin [MM7]
    PrefClass Preferred target
    Bonus (steal, curse, ...)
    BonusMul Disease1x5 etc. The chance that a monster would use the bonus is Level*BonusMul
    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+]
    ElecResistance [MM6]
    ColdResistance [MM6]
    PoisonResistance [MM6]
    PhysResistance
    Special [MM7+] 1 = shot, 2 = summon, 3 = 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.MoveToMap

     Fields:
    Pos[]
    X
    Y
    Z
    Direction 0 – 2047. 0 is East.
    LookAngle
    SpeedZ
    Defined

     Methods:
    Set()


    structs.NPC

     Fields:
    Exist Use to check if a slot is empty in Party.HiredNPC array
    Name
    Pic
    TalkedOnce [MM7+] Set to true the first time you interact with the NPC, set to false the second time
    TalkedBefore [MM7+] Set to true when you visit the NPC the second time
    BribedBefore [MM6] Set to true the first time you interact with the NPC, set to false the second time
    BeggedBefore [MM6] Set to true when you visit the NPC the second time
    ThreatenedBefore
    Hired
    Bits
    Fame
    Rep
    House
    Profession
    Greet [MM7+]
    Joins
    TellsNews
    Events[]
    EventA
    EventB
    EventC
    EventD [MM7+]
    EventE [MM7+]
    EventF [MM7+]
    Sex
    UsedSpell
    NewsTopic

     Methods:
    InitPeasant(MonType, House, MapStatsIndex) [MM6, MM7]


    structs.NPCNewsItem

    [MM6]

     Fields:
    Topic
    Text
    Map


    structs.NPCProfTxtItem

    [MM6, MM7]

     Fields:
    Chance [MM6]
    Cost
    Personality [MM6]
    Benefit
    ActionText [MM7]
    JoinText
    DismissText [MM7]
    ProfNewsTopic[] [MM6]
    ProfNewsText[] [MM6]


    structs.OODialogManager

    [MM8]

     Fields:
    VMT
    CurrentDialogPtr
    DialogPtrs[]
    Count
    Disabled

     Methods:
    ShowDialog()
    CloseCurrent(arg1 = 0, arg2 = true)
    FindDialog()
    CloseSpecific()


    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, in other screens it equals Kind + Index*8.
    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
    RawPaletteSMul [MM7+]
    RawPaletteVMul [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 Actually, it should be read as "not borderless fulscreen". It's set to false only when the game is in Borderless Fullscreen mode
    CompatibleMovieRender
    SmoothMovieScaling
    SupportTrueColor
    RenderRectLeft
    RenderRectTop
    RenderRectRight
    RenderRectBottom
    FixUnimplementedSpells [MM7+]
    IndoorMinimapZoomMul
    IndoorMinimapZoomPower
    FixMonsterSummon [MM7+]
    FixInterfaceBugs [MM7]
    UILayout [MM7+]
    PaperDollInChests
    HigherCloseRingsButton [MM7]
    RenderBottomPixel
    TrueColorTextures [MM7+]
    ResetPalettes [MM7+]
    FixSFT
    AxeGMFullProbabilityAt [MM7+]
    MouseDX
    MouseDY
    TrueColorSprites [MM7+]
    FixMonstersBlockingShots [MM7+]
    FixParalyze [MM6] May come to MM7 and MM8 in the future.
    EnableAttackSpell
    ShooterMode
    MaxMLookUpAngle
    FixIceBoltBlast [MM7+]
    MonSpritesSizeMul Default is 0 – disabled. 0x10000 stands for 1.0.
    FixMonsterAttackTypes [MM7+]
    FixMonsterSpells
    FixSouldrinker
    MouseLookPermKey
    LastSoundSample
    WaterWalkDamage [MM7+]
    FixUnmarkedArtifacts [MM6, MM7]
    FixClubsDelay [MM7+]
    FixDarkTrainers [MM7]
    FixLightBolt [MM7+]
    ArmageddonElement
    FixKelebrim [MM7]
    FixBarrels [MM7]
    ClimbBetter [MM7+]
    FixWaterWalkManaDrain
    KeepEmptyWands
    DontSkipSimpleMessage [MM6, MM7]
    FixItemDuplicates
    FixClubsGeneration [MM8]
    FixAcidBurst [MM7+]
    EnchantMayFail
    TownPortalMayFail
    RegenerationIcon [MM7+] In MM8 it's used for "SeparateBuffIcons" setting.
    SubDirection
    SubLookAngle
    TownPortalCost Gets set before opening Town Portal dialog, retrieved when the town is chosen.
    MouseFlyKey
    ModernStrafe
    ExtraSMulD3D [MM7+]
    ExtraVMulD3D [MM7+]
    DataFilesDir
    ProperSky [MM7+]
    SkyHeight [MM7+] Parameter of ProperSkyD3D
    SkyDistance [MM7+] Parameter of ProperSkyD3D
    SkyScale [MM7+] Parameter of ProperSkyD3D
    SkySpeedX [MM7+] Parameter of ProperSkyD3D
    SkySpeedY [MM7+] Parameter of ProperSkyD3D
    SkyOffsetX [MM7+] Parameter of ProperSkyD3D
    SkyOffsetY [MM7+] Parameter of ProperSkyD3D
    PaletteSMul [MM7+]
    PaletteVMul [MM7+]

     Functions:
    Present(name) Returns true if the option is supported by patch version being used
    Ptr(name) Returns address of an option if it's supported by patch version being used
    UILayoutActive() Returns true if UILayout mode is currently active


    structs.Player

     Fields:
    Biography [MM8]
    Sex [MM6, MM7]
    Cursed
    Weak
    Asleep
    Afraid
    Drunk
    Insane
    Poison1
    Disease1
    Poison2
    Disease2
    Poison3
    Disease3
    Paralyzed
    Unconscious
    Dead
    Stoned
    Eradicated
    Zombie [MM7+]
    Good
    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[spell]
    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
    ItemGauntlets Was called ItemGountlets before MMExtension v2.3, old name is supported for backward compatibility
    ItemBoots
    ItemAmulet
    ItemRing1
    ItemRing2
    ItemRing3
    ItemRing4
    ItemRing5
    ItemRing6
    SpellBookPage
    QuickSpell
    AttackSpell Added in version 2.5 of my patches
    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
    FaceBeforeZombie [MM7]
    OriginalFace [MM7]
    VoiceBeforeZombie [MM7]
    OriginalVoice [MM7]

     Methods:
    GetSex(BasedOnVoice[MM8] = false) [MM7+] 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)
    CalcHitOrMiss(Monster, Range = 0, Bonus = 0) AttackType: 0 – melee, 1 – less than 1024, 2 – less then 2560, 3 – 2560 or more. See the Mechanics page on my site for more info on the formula.
    GetMeleeDamageRangeText()
    GetRangedDamageRangeText()
    CanTrain()
    AddHP(Amount)
    DoDamage(Damage, DamageKind = const.Damage.Phys)
    DoBadThing(Thing, Monster[MM7+]) Monster must be specified for stealing in MM7+
    GetAttackDelay(Shoot = false)
    GetFullHP()
    GetFullSP()
    GetMeleeDamageMin() [MM7+]
    GetMeleeDamageMax() [MM7+]
    GetRangedDamageMin() [MM7+]
    GetRangedDamageMax() [MM7+]
    GetBaseResistance(Res) [MM7+]
    GetResistance(Res) [MM7+]
    HasItemBonus(Bonus2) [MM7+] Checks whether the player is wearing an item with specified Bonus2 See SPCITEMS.TXT for more info about each bonus.
    GetBaseFireResistance() [MM6]
    GetBaseElectricityResistance() [MM6]
    GetBaseColdResistance() [MM6]
    GetBasePoisonResistance() [MM6]
    GetBaseMagicResistance() [MM6]
    GetFireResistance() [MM6]
    GetElectricityResistance() [MM6]
    GetColdResistance() [MM6]
    GetPoisonResistance() [MM6]
    GetMagicResistance() [MM6]
    WearsItem(ItemNum, Slot = 16) If Slot isn't specified, searches all slots for the item
    RemoveFromInventory(Slot)
    GetStartingClass() [MM8]
    GetRace() [MM7]
    GetDiplomacyTotalSkill() [MM6]
    GetBaseArmorClass()
    GetArmorClass()
    GetBaseAge()
    GetAge()
    Recover(ByAmount)
    SetRecoveryDelayRaw(Delay)
    CalcStatBonusByItems(Stat, IgnoreExtraHand [MM7+] = false)
    CalcStatBonusByMagic(Stat)
    CalcStatBonusBySkills(Stat)
    GetMerchantTotalSkill()
    GetDisarmTrapTotalSkill()
    ShowFaceExpression(Expression, Time = 0)
    ShowFaceAnimation(Animation)
    IsConscious()
    GetSkill(Skill) [MM7+]
    GetPerceptionTotalSkill() [MM7+]
    GetLearningTotalSkill() [MM7+]
    AddCondition(Condition, CanResist = false) [MM7+] Passing const.Condition.Good isn't supported.
    CanResist only affects application of Protection from Magic spell. If it's true and the spell protects the player, spell strength is decreased instead of condition being applied.
    GetMainCondition() [MM7+] Returns the condition that affects character stats. Also see GetDisplayedCondition.
    ResetToClass(arg1) [MM6, MM7]
    GetDisplayedCondition() Returns the condition displayed on character face and in character properties. Since pacth 2.5 it can differ from GetMainCondition.
    EnumActiveItems(includeBroken)
    GetActiveItem(slot, includeBroken)
    CountItems({item1, item2, ...})
    SetRecoveryDelay(Delay)
    GetIndex() Returns player index in Party.PlayersArray
    GetSlot() Returns player slot index. Returns nil in MM8 if the player is not in the active party.


    structs.ProgressBar

     Fields:
    Max
    Current
    Kind
    SeenScreens[] [MM7+]
    PcxLoading
    PcxWomover
    PcxDemover
    PcxWomover2
    PcxDemover2
    BmpFireball
    BmpBardata
    BmpLoadprog [MM7+]

     Methods:
    Show()
    Hide()
    Draw()
    Increment()
    SetMax(arg1)


    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 [MM7+] only views 0,2,4 exist (mirrored)
    Glow [MM7+]
    Transparent [MM7+]
    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.ShopItemKind

     Fields:
    Level
    Types[1..4] (Default)


    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-M3a, 7-9: M1b-M3b, 10-12: M1c-M3c) or item (1-6 for regular items, 7 for artifact)
    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

     Methods:
    Set(ExpireTime, Skill, Power, OverlayId, Caster)


    structs.SpellEffect

    [MM7+]

     Fields:


    structs.SpellInfo

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


    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:
    HasFile(name) Does a slow search for a file. For sorted LOD archives FindFile works faster.
    FindFile(name, unsorted = false) Finds a file and returns file stream address or 0 if file isn't found. By default performs fast binary search. Pass unsorted = true when searching in Game.GamesLod and Game.SaveGameLod, because these archives aren't sorted lexicographically and thus binary search can't be used for them.
    Returned file stream can be used in Game.FileRead, Game.FileSeek and Game.FileTell functions. Its position is set to the beginning of specified file.
    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:
    Shade 0 = sunny, 1 = dark, 2 = misty
    Rain [MM8]
    Snow [MM6, MM7]
    Fog
    FogRange1
    FogRange2

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



    Constants


    const.*

     Values:
    SkillClub
    Novice = 1
    Expert = 2
    Master = 3
    GM = 4 [MM7+]
    SkillMisc
    RTSecond = 128
    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.Actions

     Values:
    Exit = 113
    CustomDialogButton = 1000
    CustomDialogHint = 1001
    CustomDialogMouseUp = 1002


    const.ArcomageIf

     Values:
    Always = 1
    LessIncomeBricks = 2
    LessIncomeGems = 3
    LessIncomeBeasts = 4
    EqualIncomeBricks = 5
    EqualIncomeGems = 6
    EqualIncomeBeasts = 7
    MoreIncomeBricks = 8
    MoreIncomeGems = 9
    MoreIncomeBeasts = 10
    NoWall = 11
    HaveWall = 12
    NoEnemyWall = 13
    HaveEnemyWall = 14
    LessWall = 15
    LessTower = 16
    EqualWall = 17
    EqualTower = 18
    MoreWall = 19
    MoreTower = 20


    const.CharScreens

     Values:
    Stats = 100
    Skills = 101
    Awards = 102
    Inventory = 103


    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+]
    Good


    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+]
    Elec = 3 [MM6]
    Cold = 4 [MM6]
    Poison = 5 [MM6]
    Energy
    Dragon = 50 [MM8]


    const.DlgID

     Values:
    Generic = 1 a lot of dialogs use this Id
    Menu = 3
    Inventory = 4 character screen, not necessarily Inventory
    Controls = 6
    Info = 9 Quests, Autonotes, Map, Calendar, History, Town Portal, Lloyd Beacon. See const.InfoDialog for values of Param that define the dialog type.
    NPC = 10 Param is NPC index
    QuickReference = 12
    Rest = 16
    WalkToMap = 17
    SpellBook = 18
    SimpleMessage = 19
    Chest = 20
    SaveGame = 23
    LoadGame = 24
    House = 25 Param is the house index
    MapEntrance = 26
    SelectTarget = 27 Heal and other such spells
    Scroll = 30 When reading a message scroll
    ItemSpell = 31
    EscMessage = 70
    Query = 80
    CheatCreateItem = 89
    Button = 90 shown for 1 frame when clicking most buttons
    ButtonImg2 = 91
    ButtonTransparent = 92
    ButtonTransparentImg2 = 93
    ButtonSaveLoad = 94 clicking Save/Load button in corresponding dialog
    ButtonEscTransparent = 95
    ButtonEsc = 96
    ButtonEscImg2 = 97
    ButtonRestAndHeal = 98
    DrawImage = 99 used in Info screen to draw the currently selected book
    CheatCreateMonster = 103
    ConfigureKeyboard = 105
    VideoOptions = 106
    CustomDialog = 1000 used by CustomDialog function
    BlockDialogs = 1001 in MM8 if custom dialogs exist, these screens are created for each OO dialog in order to prevent processing of said custom dialogs
    BlockDialogsNoDraw = 1002 used in situation discribed above when it's also important to block drawing the dialogs


    const.ExitMapAction

     Values:
    None = 0
    Exit = 1 used in main menu
    LoadMap = 2 when you exit a map and enter another one
    LoadGame = 3
    NewGame = 4
    MainMenu = 7
    Death = 8
    WinScreen = 9 draw the Win message


    const.FaceAnimation

     Values:
    KillSmallEnemy = 1
    KillBigEnemy = 2
    StoreClosed = 3
    DisarmTrap = 4
    TrapExploaded = 5 sorry about that / it's gonna blow!
    AvoidDamage = 6 sits down. Avoids either trap damage with Perception or attack damage with Dodging
    IdentifyUseless = 7
    IdentifyGreat = 8
    IdentifyFail = 9
    RepairItem = 10
    RepairFail = 11
    SetQuickSpell = 12
    CantRestHere = 13
    SkillIncreased = 14 in Skills screen
    CantCarry = 15
    MixPotion = 16
    PotionExplode = 17
    DoorLocked = 18
    WontBudge = 19 like pulling sword out of stone in MM6
    CantLearnSpell = 20
    LearnSpell = 21
    Hello = 22
    HelloNight = 23 10PM <= time < 5AM
    Damaged = 24
    Weak = 25
    Afraid = 26
    Poisoned = 27
    Deseased = 28
    Insane = 29
    Cursed = 30
    Drunk = 31
    Unconsious = 32
    Death = 33
    Stoned = 34
    Eradicated = 35
    DinkPotion = 36 or eat reagent
    ReadScoll = 37
    NotEnoughGold = 38
    CantEquip = 39
    ItemBrokenStolen = 40
    SPDrained = 41
    Aged = 42
    SpellFailed = 43
    DamagedParty = 44 with explosive impact
    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
    Threat = 55
    ThreatFail = 56
    Bribe = 57
    BribeFail = 58
    NPCDontTalk = 59
    FoundItem = 60
    HireNPC = 61
    LookUp = 63
    LookDown = 64
    Yell = 65
    Falling = 66
    TavernPacksFull = 67 shakes head
    TavernDrink = 68
    TavernGotDrunk = 69
    TavernTip = 70
    TravelHorse = 71
    TravelBoat = 72
    ShopIdentify = 73
    ShopRepair = 74
    ShopItemBought = 75
    ShopAlreadyIdentified = 76
    ShopItemSold = 77
    SkillLearned = 78
    ShopWrongShop = 79
    ShopRude = 80
    BankDeposit = 81 or paying a fine
    TempleHeal = 82
    TempleDonate = 83
    HelloHouse = 84
    SkillMasteryIcreased = 85 by a teacher
    JoinedGuild = 86
    LevelUp = 87
    StatBonusIncreased = 91
    StatBaseIncreased = 92
    QuestGot = 93
    AwardGot = 96 or autonote added, or QBits removed, or used Genie Lamp
    AfraidSilent = 98
    CheatedDeath = 99 "okay!". After death of party / after zombification
    InPrison = 100
    ChooseMe = 102
    Awaken = 103
    IdMonsterWeak = 104
    IdMonsterBig = 105
    IdMonsterFail = 106
    LastManStanding = 107
    NotEnoughFood = 108
    DeathBlow = 109


    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
    ProjectToXY = 0x100
    ProjectToXZ = 0x200
    ProjectToYZ = 0x400
    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 great for vertical facets of stairs. [MM7+] Shouldn't be used for sloped floor, like it's used in MM6.
    IsLava = 0x40000000
    HasData = 0x80000000


    const.HouseScreens

     Values:
    Teacher = -1
    ChoosePerson = 0
    Main = 1
    BuyStandard = 2
    Sell = 3
    Identify = 4
    BuySpecial
    BuySpecialMM6 = 6
    BankDeposit = 7
    BankWithdraw = 8
    Heal = 10
    Donate = 11
    ProfNews = 12 NPC command
    JoinMenu = 13 NPC command
    News = 14 NPC command
    TavernSleep = 15
    TavernFood = 16
    Train = 17
    BuySpells = 18
    A = 19 NPC command
    B = 20 NPC command
    C = 21 NPC command
    D = 22 [MM7+] NPC command
    E = 23 [MM7+] NPC command
    F = 24 [MM7+] NPC command
    Beg = 22 [MM6] NPC command
    SeerHint = 22 [MM6] NPC command
    Threat = 23 [MM6] NPC command
    Bribe = 24 [MM6] NPC command
    TavernDrink = 25
    TavernTip = 26
    Staff = 36
    Sword = 37
    Dagger = 38
    Axe = 39
    Spear = 40
    Bow = 41
    Mace = 42
    Blaster = 43
    Shield = 44
    Leather = 45
    Chain = 46
    Plate = 47
    Fire = 48
    Air = 49
    Water = 50
    Earth = 51
    Spirit = 52
    Mind = 53
    Body = 54
    Light = 55
    Dark = 56
    DarkElfAbility = 57 [MM8]
    VampireAbility = 58 [MM8]
    DragonAbility = 59 [MM8]
    IdentifyItem
    Merchant
    Repair
    Bodybuilding
    Meditation
    Perception
    Regeneration = 66 [MM8]
    Diplomacy = 63 [MM6, MM7]
    Thievery = 64 [MM6, MM7]
    DisarmTraps
    Dodging [MM7+]
    Unarmed [MM7+]
    IdentifyMonster [MM7+]
    Armsmaster [MM7+]
    Stealing [MM7+]
    Alchemy [MM7+]
    Learning
    Travel1
    Travel2
    Travel3
    HireOrDismiss NPC command
    MoreInformation NPC command
    TeachSkill NPC command
    DoTeachSkill NPC command
    JoinGuild NPC command
    DoJoinGuild NPC command
    BountyHuntNPC NPC command
    SeerILostIt NPC command
    ArenaPage NPC command
    ArenaSquire NPC command
    ArenaKight NPC command
    ArenaLord NPC command
    ArenaMenu NPC command
    ArenaGoBack NPC command
    ArenaWin NPC command
    ArenaAlreadyWon NPC command
    DisplayInventory = 94 [MM7+]
    LearnSkills = 96 [MM7+]
    BountyHunt = 99 [MM7+]
    PayFine = 100 [MM7+]
    ArcomageMenu = 101 [MM7+]
    ArcomageRules = 102 [MM7+]
    ArcomageConditions = 103 [MM7+]
    ArcomagePlay = 104 [MM7+]
    Travel4 = 109 [MM7+]
    BuySpellsFire = 110 [MM8]
    BuySpellsAir = 111 [MM8]
    BuySpellsWater = 112 [MM8]
    BuySpellsEarth = 113 [MM8]
    BuySpellsSpirit = 114 [MM8]
    BuySpellsMind = 115 [MM8]
    BuySpellsBody = 116 [MM8]
    BuySpellsLight = 117 [MM8]
    BuySpellsDark = 118 [MM8]
    JoinRoster = 119 [MM8] Yes item in the join menu
    JoinRosterNo = 120 [MM8]
    SeerPilgrimage = 88 [MM6] NPC command
    StreetNPC = 200 Not used by the game, only by MMExt for PopulateNPCDialog event.
    LackFame = 201 Not used by the game, only by MMExt for PopulateNPCDialog event.
    BegThreatBribe = 202 Not used by the game, only by MMExt for PopulateNPCDialog event.
    ThreatBribe = 203 Not used by the game, only by MMExt for PopulateNPCDialog event.


    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.InfoDialog

     Values:
    LloydBeacon = 177
    TownPortal = 195
    Quests = 200
    Autonotes = 201
    Map = 202
    Calendar = 203
    History = 224


    const.ItemSlot

     Values:
    ExtraHand = 0
    MainHand = 1
    Bow = 2
    Armor = 3
    Helm = 4
    Belt = 5
    Cloak = 6
    Gauntlets = 7 Was called Gountlets before MMExtension v2.3, old name is supported for backward compatibility
    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
    Gauntlets = 9 Was called Gountlets before MMExtension v2.3, old name is supported for backward compatibility
    Boots = 10
    Ring = 11
    Amulet = 12
    Wand = 13 weaponw
    Reagent = 14 herb
    Potion = 15 bottle
    Scroll = 16 sscroll
    Book = 17
    MScroll = 18 always creates item 001
    Gold = 19
    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
    Gauntlets_ = 38 Was called Gountlets_ before MMExtension v2.3, old name is supported for backward compatibility
    Boots_ = 39
    Ring_ = 40
    Amulet_ = 41
    Wand_ = 42
    Scroll_ = 43
    Potion_ = 44
    Reagent_ = 45
    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
    ENTER = 13
    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
    SCROLLLOCK = 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.MonsterAction

     Values:
    Attack1 = 0
    Attack2 = 1
    Spell1 = 2
    Spell2 = 3 [MM7+]


    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 in monsters.txt it's "M" in MM6 and "X" in MM7 and MM8
    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 in Party.PlayersArray
    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
    Menu = 1
    Controls = 2
    Info = 3 Quests, Autonotes, Map, Calendar, History, Town Portal, Lloyd Beacon
    NPC = 4
    Rest = 5
    Query = 6 like with hotkeys in Chinese debug MM6
    Inventory = 7 character screen, not necessarily Inventory
    SpellBook = 8
    NewGameBriefing = 9 was called NewGameBreefing before MMExtension v2.3, old name is supported for backward compatibility
    Chest = 10
    SaveGame = 11
    LoadGame = 12
    House = 13
    InventoryInShop = 14 double clicking a character in any Buy dialog in MM6 or in Buy Standard in MM7
    InventoryInChest = 15
    MainManu = 16 or movie
    WalkToMap = 17
    MapEntrance = 18 or Question screen
    SimpleMessage = 19
    SelectTarget = 20 Heal and other such spells in MM8
    CreateParty = 21
    EscMessage = 22
    ItemSpell = 23
    KeyConfig = 26
    VideoOptions = 28
    AdventurersInn = 29
    ItemSpellMM6 = 103
    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 proper name "RepairItem" is supported since MMExt 2.3
    Bodybuilding
    Meditation
    Perception
    Regeneration = 30 [MM8]
    Diplomacy = 27 [MM6, MM7]
    Thievery = 28 [MM6, MM7]
    DisarmTraps proper name "DisarmTrap" is supported since MMExt 2.3
    Dodging [MM7+]
    Unarmed [MM7+]
    IdentifyMonster [MM7+]
    Armsmaster [MM7+]
    Stealing [MM7+]
    Alchemy [MM7+]
    Learning


    const.Spells

     Values:
    TorchLight = 1
    FlameArrow = 2 [MM6]
    ProtectionFromFire = 3 [MM6]
    FireBolt
    FireResistance = 3 [MM7+]
    FireAura = 4 [MM7+]
    Haste = 5
    Fireball = 6
    FireSpike = 7 [MM7+]
    Immolation = 8 [MM7+]
    RingOfFire = 7 [MM6]
    FireBlast = 8 [MM6]
    MeteorShower = 9
    Inferno = 10
    Incinerate = 11
    WizardEye = 12
    StaticCharge = 13 [MM6]
    ProtectionFromElectricity = 14 [MM6]
    Sparks = 15
    FeatherFall
    AirResistance = 14 [MM7+]
    Shield = 17
    LightningBolt = 18
    Jump
    Invisibility = 19 [MM7+]
    Implosion = 20
    Fly = 21
    Starburst = 22
    Awaken = 23
    ColdBeam = 24 [MM6]
    ProtectionFromCold = 25 [MM6]
    PoisonSpray
    WaterResistance = 25 [MM7+]
    WaterWalk = 27
    IceBolt
    RechargeItem = 28 [MM7+]
    EnchantItem
    AcidBurst
    TownPortal = 31
    IceBlast = 32
    LloydsBeacon = 33
    Stun = 34
    MagicArrow = 35 [MM6]
    ProtectionFromMagic
    DeadlySwarm = 37
    StoneSkin = 38
    Blades = 39
    StoneToFlesh = 40
    RockBlast = 41
    TurnToStone = 42 [MM6]
    DeathBlossom = 43
    MassDistortion = 44
    SpiritArrow = 45 [MM6]
    Bless = 46
    HealingTouch = 47 [MM6]
    LuckyDay = 48 [MM6]
    RemoveCurse = 49
    GuardianAngel = 50 [MM6]
    Heroism = 51
    TurnUndead
    RaiseDead = 53
    SharedLife = 54
    Resurrection = 55
    Meditation = 56 [MM6]
    RemoveFear
    MindBlast
    Precision = 59 [MM6]
    CureParalysis
    Charm
    MassFear
    Feeblemind = 63 [MM6]
    CureInsanity = 64
    PsychicShock = 65
    Telekinesis
    CureWeakness = 67
    FirstAid = 68 [MM6]
    ProtectionFromPoison = 69 [MM6]
    Harm = 70
    CureWounds = 71 [MM6]
    CurePoison = 72
    Speed = 73 [MM6]
    CureDisease = 74
    Power = 75 [MM6]
    FlyingFist = 76
    PowerCure = 77
    CreateFood = 78 [MM6]
    GoldenTouch = 79 [MM6]
    DispelMagic = 80
    Slow
    EarthResistance = 36 [MM7+]
    DetectLife = 45 [MM7+]
    Fate = 47 [MM7+]
    Preservation = 50 [MM7+]
    SpiritLash = 52 [MM7+]
    MindResistance = 58 [MM7+]
    Telepathy [MM7+]
    Berserk = 62 [MM7+]
    Enslave = 66 [MM7+]
    Heal = 68 [MM7+]
    BodyResistance = 69 [MM7+]
    Regeneration = 71 [MM7+]
    Hammerhands = 73 [MM7+]
    LightBolt = 78 [MM7+]
    DestroyUndead
    DayOfTheGods = 83
    PrismaticLight = 84
    HourOfPower
    Paralyze
    SummonElemental = 82 [MM7+]
    SummonWisp = 82 [MM8]
    SunRay = 87 [MM6]
    DivineIntervention = 88
    Reanimate = 89
    ToxicCloud = 90
    MassCurse = 91 [MM6]
    Shrapmetal
    ShrinkingRay
    DayOfProtection
    Sunray = 87 [MM7+]
    VampiricWeapon = 91 [MM7+]
    ControlUndead = 94 [MM7+]
    PainReflection = 95 [MM7+]
    DarkGrasp = 96 [MM8]
    Sacrifice = 96 [MM7]
    FingerOfDeath = 95 [MM6]
    MoonRay = 96 [MM6]
    DragonBreath = 97
    Armageddon = 98
    Souldrinker = 99 [MM7+]
    Glamour = 100 [MM8]
    TravelersBoon = 101 [MM8]
    Blind = 102 [MM8]
    DarkfireBolt = 103 [MM8]
    Lifedrain = 111 [MM8]
    Levitate = 112 [MM8]
    Mistform = 114 [MM8]
    Fear = 122 [MM8]
    FlameBlast = 123 [MM8]
    Flight = 124 [MM8]
    WingBuffet = 125 [MM8]
    DarkContainment = 99 [MM6]
    Shoot
    ShootFire unused
    ShootBlaster
    ShootCannonBall = 136 [MM8]
    ShootDragon = 137 [MM8]


    const.SpriteBits

     Values:
    TriggerByTouch = 1 only for "Event Trigger" sprites – triggered when a player comes into TriggerRadius
    TriggerByMonster = 2 only for "Event Trigger" sprites – triggered when a monster comes into TriggerRadius
    TriggerByObject = 4 only for "Event Trigger" sprites – triggered when an object gets into TriggerRadius
    ShowOnMap = 8
    IsChest = 16
    Invisible = 32
    IsObeliskChest = 64 [MM7+]
    IsShip = 64 [MM6]


    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 For Stats screen. Only used in CalcStatBonusByItems, other events use MeleeDamageBase
    MeleeDamageMax For Stats screen. Only used in CalcStatBonusByItems, other events use MeleeDamageBase
    RangedAttack
    RangedDamageBase
    RangedDamageMin For Stats screen. Only used in CalcStatBonusByItems, other events use RangedDamageBase
    RangedDamageMax For Stats screen. Only used in CalcStatBonusByItems, other events use RangedDamageBase
    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
    Items = 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+]
    LightResistance = 53 [MM7+] unused resistance
    DarkResistance = 54 [MM7+] unused resistance
    ElecResistance = 47 [MM6]
    ColdResistance = 48 [MM6]
    PoisonResistance = 49 [MM6]
    MagicResistance unused resistance
    FireResBonus
    AirResBonus = 58 [MM7+]
    WaterResBonus = 59 [MM7+]
    EarthResBonus = 60 [MM7+]
    SpiritResBonus = 61 [MM7+]
    MindResBonus = 62 [MM7+]
    BodyResBonus = 63 [MM7+]
    LightResBonus = 64 [MM7+] unused resistance
    DarkResBonus = 65 [MM7+] unused resistance
    ElecResBonus = 52 [MM6]
    ColdResBonus = 53 [MM6]
    PoisonResBonus = 54 [MM6]
    MagicResBonus unused resistance
    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
    RepairItemSkill
    RepairSkill
    BodybuildingSkill
    MeditationSkill
    PerceptionSkill
    RegenerationSkill = 98 [MM8]
    DiplomacySkill [MM6, MM7]
    ThieverySkill [MM6, MM7]
    DisarmTrapSkill
    DisarmTrapsSkill
    DodgingSkill [MM7+]
    UnarmedSkill [MM7+]
    IdentifyMonsterSkill [MM7+]
    ArmsmasterSkill [MM7+]
    StealingSkill [MM7+]
    AlchemySkill [MM7+]
    LearningSkill
    Cursed
    Weak
    Asleep
    Afraid
    Drunk
    Insane
    Poison1
    PoisonedGreen
    Disease1
    DiseasedGreen
    Poison2
    PoisonedYellow
    Disease2
    DiseasedYellow
    Poison3
    PoisonedRed
    Disease3
    DiseasedRed
    Paralysed
    Paralyzed
    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
    DaysCounter1 evt.Set starts the count, evt.Cmp compares the difference of dates
    DaysCounter2 evt.Set starts the count, evt.Cmp compares the difference of dates
    DaysCounter3 evt.Set starts the count, evt.Cmp compares the difference of dates
    DaysCounter4 evt.Set starts the count, evt.Cmp compares the difference of dates
    DaysCounter5 evt.Set starts the count, evt.Cmp compares the difference of dates
    DaysCounter6 evt.Set starts the count, evt.Cmp compares the difference of dates
    Flying
    HasNPCProfession
    TotalCircusPrize
    SkillPoints
    MonthIs
    Counter1 [MM7+] evt.Set starts the count, evt.Cmp compares the exact time spent in hours
    Counter2 [MM7+] evt.Set starts the count, evt.Cmp compares the exact time spent in hours
    Counter3 [MM7+] evt.Set starts the count, evt.Cmp compares the exact time spent in hours
    Counter4 [MM7+] evt.Set starts the count, evt.Cmp compares the exact time spent in hours
    Counter5 [MM7+] evt.Set starts the count, evt.Cmp compares the exact time spent in hours
    Counter6 [MM7+] evt.Set starts the count, evt.Cmp compares the exact time spent in hours
    Counter7 [MM7+] evt.Set starts the count, evt.Cmp compares the exact time spent in hours
    Counter8 [MM7+] evt.Set starts the count, evt.Cmp compares the exact time spent in hours
    Counter9 [MM7+] evt.Set starts the count, evt.Cmp compares the exact time spent in hours
    Counter10 [MM7+] evt.Set starts the count, evt.Cmp compares the exact time spent in hours
    SpecialDate1 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %51
    SpecialDate2 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %52
    SpecialDate3 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %53
    SpecialDate4 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %54
    SpecialDate5 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %55
    SpecialDate6 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %56
    SpecialDate7 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %57
    SpecialDate8 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %58
    SpecialDate9 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %59
    SpecialDate10 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %60
    SpecialDate11 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %61
    SpecialDate12 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %62
    SpecialDate13 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %63
    SpecialDate14 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %64
    SpecialDate15 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %65
    SpecialDate16 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %66
    SpecialDate17 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %67
    SpecialDate18 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %68
    SpecialDate19 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %69
    SpecialDate20 [MM7+] evt.Set remembers current time and plays sound. The date can be used in messages as %70
    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[]
    Conditions[]
    Counters[] [MM7+]
    CurrentStats[]
    DaysCounters[]
    History[] [MM7+]
    MapVars[]
    ResBonus[]
    Resistance[]
    Skills[]
    SpecialDates[] [MM7+]