Bot stopped working.. help plz :)
Posted: Wed Dec 09, 2009 4:42 pm
I check everyday for updates for the bot. It get's an error now & never did before.
I tried deleting the micromacro folder and reinstalling after I restarted my pc and it didn't help.
Here's the error:
Here's my settings.lua
micromacro\lib\lib.lua
I tried deleting the micromacro folder and reinstalling after I restarted my pc and it didn't help.
Here's the error:
Code: Select all
Wed Dec 09 16:34:27 2009 : Executing script 'bot.lua'
--------------------------------------------------------------------------------
Wed Dec 09 16:34:27 2009 : Language: english
Wed Dec 09 16:34:50 2009 : Using static char address 0x901990, player address 0x15046900
In main thread:
stack traceback:
...nd Settings/gino/Desktop/micromacro/lib/mods/xml.lua:309: in function 'open'
...ngs/gino/Desktop/micromacro/scripts/rom/settings.lua:537: in function 'loadProfile'
scripts\rom\bot.lua:140: in function 'foo'
...nts and Settings\gino\Desktop\micromacro\lib\lib.lua:489: in function <...nts and Settings\gino\Desktop\micromacro\lib\lib.lua:487>
----------TRACEBACK END----------
Wed Dec 09 16:34:50 2009 : ...ngs/gino/Desktop/micromacro/scripts/rom/settings.lua:537: XML Parse Error.
File: ...sktop/micromacro/scripts/rom/profiles/mycharactername.xml
Line: 95
Column: 4
Message: mismatched tag
Wed Dec 09 16:34:50 2009 : Execution error: Runtime error
Code: Select all
settings_default = {
hotkeys = {
MOVE_FORWARD = {key = _G.key.VK_W, modifier = nil},
MOVE_BACKWARD = {key = _G.key.VK_S, modifier = nil},
ROTATE_LEFT = {key = _G.key.VK_A, modifier = nil},
ROTATE_RIGHT = {key = _G.key.VK_D, modifier = nil},
STRAFF_LEFT = {key = _G.key.VK_Q, modifier = nil},
STRAFF_RIGHT = {key = _G.key.VK_E, modifier = nil},
JUMP = {key = _G.key.VK_SPACE, modifier = nil},
TARGET = {key = _G.key.VK_TAB, modifier = nil},
TARGET_FRIEND = {key = _G.key.J, modifier = nil},
START_BOT = {key = _G.key.VK_DELETE, modifier = nil},
STOP_BOT = {key = _G.key.VK_END, modifier = nil}
},
options = {
ENABLE_FIGHT_SLOW_TURN = false,
MELEE_DISTANCE = 45,
LANGUAGE = "english",
USE_CLIENT_LANGUAGE = true, -- automatic use client language after loading the bot
DEBUGGING = false,
DEBUGGING_MACRO = false,
ROMDATA_PATH = nil,
},
profile = {
options = {
-- common options
HP_LOW = 85,
MP_LOW_POTION = 50,
HP_LOW_POTION = 40,
COMBAT_TYPE = "melee",
COMBAT_RANGED_PULL = "true", -- only for melee classes , use ranged skill to pull
COMBAT_DISTANCE = 200,
ANTI_KS = true,
WAYPOINTS = "demo.xml",
RETURNPATH = nil,
PATH_TYPE = "waypoints",
WANDER_RADIUS = 500,
WAYPOINT_DEVIATION = 0,
LOOT = true,
LOOT_TIME = 2000,
LOOT_AGAIN = 2000, -- second loot try if rooted after x ms
LOOT_IN_COMBAT = true,
LOOT_DISTANCE = nil,
LOOT_PAUSE_AFTER = 10, -- probability in % for short pause after loot to look more human
MAX_FIGHT_TIME = 12,
DOT_PERCENT = 90,
LOGOUT_TIME = 0,
LOGOUT_SHUTDOWN = false,
LOGOUT_WHEN_STUCK = true,
MAX_UNSTICK_TRIALS = 10,
TARGET_LEVELDIF_BELOW = 99,
TARGET_LEVELDIF_ABOVE = 99,
QUICK_TURN = false,
MP_REST = 15,
HP_REST = 15,
RES_AUTOMATIC_AFTER_DEATH = false, -- automatic resurrect after death true|false,
HEALING_POTION = 0, -- shopping options, how many to buy/have in inventory
MANA_POTION = 0, -- shopping options, how many to buy/have in inventory
ARRAY_QUIVER = 0, -- shopping options, how many to buy/have in inventory
THROWN_BAG = 0, -- shopping options, how many to buy/have in inventory
POISON = 0, -- shopping options, how many to buy/have in inventory
RELOAD_AMMUNITION = false, -- false|arrow|thrown
-- expert options
MAX_SKILLUSE_NODMG = 3, -- maximum casts without damaging the target before break it
MAX_TARGET_DIST = 999, -- maximum distance to select a target (helpfull to limit at small places)
AUTO_ELITE_FACTOR = 5, -- mobs with x * your HP value counts as 'Elite' and we will not target it
AUTO_TARGET = true, -- bot will target mobs automaticly (set it to false if you want to use the bot only as fight support)
SKILL_GLOBALCOOLDOWN = 1200, -- Global Skill Use Cooldown (1000ms) we use a little more
SKILL_USE_PRIOR = 0, -- cast x ms before cooldown is finished
PK_COUNTS_AS_DEATH = true, -- count playerkill's as death
POTION_COOLDOWN = 15, -- always 15
POTION_COOLDOWN_HP = 0, -- will only be used if not 0, if 0 POTION_COOLDOWN will be used
POTION_COOLDOWN_MANA = 0, -- will only be used if not 0, if 0 POTION_COOLDOWN will be used
SIT_WHILE_RESTING = false, -- sit while using the rest function
USE_MANA_POTION = "best", -- which mana potion type to use: best | minstack
USE_HP_POTION = "best", -- which HP potion type to use: best | minstack
WAYPOINTS_REVERSE = false, -- use the waypoint file in reverse order
WAYPOINT_PASS = 100, -- skip a waypoint if we pass in distance x while fighting a mob (go to as melee)
WAYPOINT_PASS_DEGR = 90, -- skip a waypoint if we touched one and the next is at least x degrees in front
MAX_DEATHS = 10, -- maximal death if automatic resurrect befor logout
WAIT_TIME_AFTER_RES = 8000, -- time to wait after resurrection, needs more on slow PCs
RETURNPATH_SUFFIX = "_return", -- suffix for default naming of returnpath
HARVEST_SCAN_WIDTH = 5, -- steps horizontal
HARVEST_SCAN_HEIGHT = 5, -- steps vertical
HARVEST_SCAN_STEPSIZE = 60, -- wide of every step
HARVEST_SCAN_TOPDOWN = false, -- true = top->down false = botton->up
HARVEST_SCAN_XMULTIPLIER = 1.0, -- multiplier for scan width
HARVEST_SCAN_YMULTIPLIER = 1.1, -- multiplier for scan line height
HARVEST_SCAN_YREST = 10, -- scanspeed
HARVEST_SCAN_YMOVE = 1.1, -- move scan area top/down ( 1=middle of screen )
HARVEST_TIME = 45, -- how long we maximum harvest a node
USE_SLEEP_AFTER_RESUME = false, -- enter sleep mode after pressing pause/resume key
IGNORE_MACRO_ERROR = false, -- ignore missing MACRO hotkey error (only temporary option while beta)
DEBUG_INV = false, -- to help to find the item use error (only temporary option while beta)
DEBUG_LOOT = false, -- debug loot issues
DEBUG_TARGET = false, -- debug targeting issues
DEBUG_HARVEST = false, -- debug harvesting issues
DEBUG_WAYPOINT = false, -- debug waypoint issues
DEBUG_AUTOSELL = false, -- debug autosell issues
-- debug skill use issues
DEBUG_SKILLUSE = {
ENABLE = false,
TIMEGAP = true, -- show the time gap between cast starts
ONCOOLDOWN = true, -- show the time in ms that we are before the cooldown
NOCOOLDOWN = true, -- show the time in ms that we are over the cooldown
HPLOW = true
},
-- expert inventar
INV_MAX_SLOTS = 60, -- maximal slots to update in the inventory:update()
INV_UPDATE_INTERVAL = 300, -- full inventory update every x seconds (only used indirect atm)
INV_AUTOSELL_ENABLE = false, -- autosell items at merchant true|false
INV_AUTOSELL_FROMSLOT = 0, -- autosell from slot #
INV_AUTOSELL_TOSLOT = 0, -- autosell to slot #
INV_AUTOSELL_QUALITY = "white", -- itemcolors to sell
INV_AUTOSELL_IGNORE = nil, -- itemnames never so sell
INV_AUTOSELL_NOSELL_DURA = 0, -- durability > x will not sell, 0=sell all
INV_AUTOSELL_STATS_NOSELL = nil, -- stats (text search at right tooltip side) that will not be selled
INV_AUTOSELL_STATS_SELL = nil, -- stats (text search at right tooltip side) that will be selled, even if in nosell
},
hotkeys = { },
skills = {},
friends = {},
mobs = {},
events = {
onDeath = nil,
onLoad = nil,
onLeaveCombat = nil,
onSkillCast = nil,
onLevelup = nil,
}
},
};
bot = { -- global bot values
ClientLanguage, -- ingame language of the game [ DE|RU|FR|ENUS|ENEU
GetTimeFrequency, -- calculated CPU frequency for calculating with the getTime() function
LastSkillKeypressTime = getTime(), -- remember last time we cast (press key)
IgfAddon = false, -- check if igf addon is active
};
settings = settings_default;
check_keys = { name = { } };
function checkKeySettings( _name, _key, _modifier)
-- args are the VK in stringform like "VK_CONTROL", "VK_J", ..
local hf_check_where;
if( bindings ) then -- keys are from bindings.txt
hf_check_where = language[141]; -- Datei settings.xml
else
hf_check_where = language[140]; -- Ingame -> System -> Tastenbelegung
end
local msg = nil;
-- no empty keys pls
if( _key == nil) then
msg = sprintf(language[115], _name); -- key for \'%s\' is empty!
msg = msg .. hf_check_where;
end
-- check if all keys are valid virtual keys (VK)
if( _key ) then
if( key[_key] == nil and
string.upper(_key) ~= "MACRO" ) then -- hotekey MACRO is a special case / it's not a virtual key
msg = sprintf(language[116], _key, _name); -- The hotkey ... is not a valid key
msg = msg .. hf_check_where;
end
end;
-- no modifiers allowed at the moment
if( _modifier ) then
if( key[_modifier] == nil ) then
msg = sprintf(language[117], _modifier, _name); -- The modifier ... is not a valid key
msg = msg .. hf_check_where;
end
end;
-- now we check for double key settings
-- we translate the strings "VK..." to the VK numbers
if( string.upper(_key) ~= "MACRO" ) then
_key = key[_key];
end
_modifier = key[_modifier];
-- check the using of modifiers
-- they are not usable at the moment
if( _modifier ~= nil) then
msg = sprintf(language[118], -- we don't support modifiers
getKeyName(_modifier), getKeyName(_key), _name);
end
-- error output
if( msg ~= nil) then
-- only a warning for TARGET_FRIEND / else an error
if(_name == "TARGET_FRIEND") then
cprintf(cli.yellow, msg .. language[119]); -- can't use the player:target_NPC() function
else
error(msg, 0);
end
end
-- check for double key settings
for i,v in pairs(check_keys) do
if( v.name ~= _nil and -- empty entries from deleted settings.xml entries
v.key == _key and
string.upper(_key) ~= "MACRO" and -- hotkey MACRO is allowed to set more then once
v.modifier == _modifier ) then
local modname;
if( v.modifier ) then
modname = getKeyName(v.modifier).."+";
else
modname = "";
end;
local errstr = sprintf(language[121], -- assigned the key \'%s%s\' double
modname,
getKeyName(v.key),
v.name, _name) ..
hf_check_where;
error(errstr, 0);
end
end;
check_keys[_name] = {};
check_keys[_name].name = _name;
check_keys[_name].key = _key;
check_keys[_name].modifier = _modifier;
end
function settingsPrintKeys()
-- That function prints the loaded key settings to the MM window and to the log
local msg;
msg ="QUICK_TURN = "..tostring(settings.profile.options.QUICK_TURN); -- we wander around
logMessage(msg); -- log keyboard settings
if( bindings ) then -- we read from bindings.txt
msg = sprintf(language[167], "bindings.txt"); -- Keyboard settings are from
else -- we read settings.xml
msg = sprintf(language[167], "settings.xml"); -- Keyboard settings are from
end
-- cprintf(cli.green, msg.."\n"); -- Keyboard settings are from
logMessage(msg); -- log keyboard settings
for i,v in pairs(check_keys) do
if(v.name) then
msg = string.sub(v.name.." ", 1, 30); -- function name
local modname;
if( v.modifier ) then
modname = getKeyName(v.modifier).."+"; -- modifier name
else
modname = "";
end;
local keyname;
if( string.upper(v.key) == "MACRO" ) then
keyname = "MACRO";
else
keyname = getKeyName(v.key);
end
msg = msg..modname..keyname; -- add key name
-- printf(msg.."\n"); -- print line
logMessage(msg); -- log keyboard settings
end;
end;
end
function settings.load()
local filename = getExecutionPath() .. "/settings.xml";
local root = xml.open(filename);
local elements = root:getElements();
check_keys = { }; -- clear table, because of restart from createpath.lua
-- Specific to loading the hotkeys section of the file
local loadHotkeys = function (node)
local elements = node:getElements();
for i,v in pairs(elements) do
-- If the hotkey doesn't exist, create it.
settings.hotkeys[ v:getAttribute("description") ] = { };
settings.hotkeys[ v:getAttribute("description") ].key = key[v:getAttribute("key")];
settings.hotkeys[ v:getAttribute("description") ].modifier = key[v:getAttribute("modifier")];
if( key[v:getAttribute("key")] == nil ) then
local err = sprintf(language[122], -- does not have a valid hotkey!
v:getAttribute("description"));
error(err, 0);
end
checkKeySettings( v:getAttribute("description"),
v:getAttribute("key"),
v:getAttribute("modifier") );
end
end
local loadOptions = function (node)
local elements = node:getElements();
for i,v in pairs(elements) do
settings.options[ v:getAttribute("name") ] = v:getAttribute("value");
end
end
-- Load RoM keyboard bindings.txt file
local function load_RoM_bindings_txt()
local filename, file;
local userprofilePath = os.getenv("USERPROFILE");
local documentPaths = {
userprofilePath .. "\\My Documents\\" .. "Runes of Magic", -- English
userprofilePath .. "\\Eigene Dateien\\" .. "Runes of Magic", -- German
userprofilePath .. "\\Mes Documents\\" .. "Runes of Magic", -- French
userprofilePath .. "\\Omat tiedostot\\" .. "Runes of Magic", -- Finish
userprofilePath .. "\\Belgelerim\\" .. "Runes of Magic", -- Turkish
userprofilePath .. "\\Mina Dokument\\" .. "Runes of Magic", -- Swedish
userprofilePath .. "\\Dokumenter\\" .. "Runes of Magic", -- Danish
userprofilePath .. "\\Documenti\\" .. "Runes of Magic", -- Italian
userprofilePath .. "\\Mijn documenten\\" .. "Runes of Magic", -- Dutch
userprofilePath .. "\\Moje dokumenty\\" .. "Runes of Magic", -- Polish
userprofilePath .. "\\Mis documentos\\" .. "Runes of Magic", -- Spanish
};
-- Use a user-specified path from settings.xml
if( settings.options.ROMDATA_PATH ) then
table.insert(documentPaths, settings.options.ROMDATA_PATH);
end
-- Select the first path that exists
for i,v in pairs(documentPaths) do
if( string.sub(v, -1 ) ~= "\\" and string.sub(v, -1 ) ~= "/" ) then
v = v .. "\\"; -- Append the trailing backslash if necessary.
end
local filename = v .. "bindings.txt"
if( fileExists(filename) ) then
file = io.open(filename, "r");
local tmp = filename;
cprintf(cli.green, language[123], filename); -- read the hotkey settings from your bindings.txt
end
end
-- If we wern't able to locate a document path, return.
if( file == nil ) then
return;
end
-- delete hotkeys from settings.xml in check table to avoid double entries / wrong checks
check_keys["MOVE_FORWARD"] = nil;
check_keys["MOVE_BACKWARD"] = nil;
check_keys["ROTATE_LEFT"] = nil;
check_keys["ROTATE_RIGHT"] = nil;
check_keys["STRAFF_LEFT"] = nil;
check_keys["STRAFF_RIGHT"] = nil;
check_keys["JUMP"] = nil;
check_keys["TARGET"] = nil;
check_keys["TARGET_FRIEND"] = nil;
-- Load bindings.txt into own table structure
bindings = { name = { } };
-- read the lines in table 'lines'
for line in file:lines() do
for name, key1, key2 in string.gfind(line, "(%w*)%s([%w+]*)%s*([%w+]*)") do
bindings[name] = {};
bindings[name].key1 = key1;
bindings[name].key2 = key2;
--settings.hotkeys[name].key =
end
end
local function bindHotkey(bindingName)
local links = { -- Links forward binding names to hotkey names
MOVEFORWARD = "MOVE_FORWARD",
MOVEBACKWARD = "MOVE_BACKWARD",
TURNLEFT = "ROTATE_LEFT",
TURNRIGHT = "ROTATE_RIGHT",
STRAFELEFT = "STRAFF_LEFT",
STRAFERIGHT = "STRAFF_RIGHT",
JUMP = "JUMP",
TARGETNEARESTENEMY = "TARGET",
TARGETNEARESTFRIEND = "TARGET_FRIEND",
};
local hotkeyName = bindingName;
if(links[bindingName] ~= nil) then
hotkeyName = links[bindingName];
end;
if( bindings[bindingName] ~= nil ) then
if( bindings[bindingName].key1 ~= nil ) then
-- Fix key names
bindings[bindingName].key1 = string.gsub(bindings[bindingName].key1, "CTRL", "CONTROL");
if( string.find(bindings[bindingName].key1, '+') ) then
local parts = explode(bindings[bindingName].key1, '+');
-- parts[1] = modifier
-- parts[2] = key
settings.hotkeys[hotkeyName].key = key["VK_" .. parts[2]];
settings.hotkeys[hotkeyName].modifier = key["VK_" .. parts[1]];
checkKeySettings(hotkeyName, "VK_" .. parts[2], "VK_" .. parts[1] );
else
settings.hotkeys[hotkeyName].key = key["VK_" .. bindings[bindingName].key1];
checkKeySettings(hotkeyName, "VK_" .. bindings[bindingName].key1 );
end
else
local err = sprintf(language[124], bindingName); -- no ingame hotkey for
error(err, 0);
end
end
end
bindHotkey("MOVEFORWARD");
bindHotkey("MOVEBACKWARD");
bindHotkey("TURNLEFT");
bindHotkey("TURNRIGHT");
bindHotkey("STRAFELEFT");
bindHotkey("STRAFERIGHT");
bindHotkey("JUMP");
bindHotkey("TARGETNEARESTENEMY");
bindHotkey("TARGETNEARESTFRIEND");
end
-- check ingame settings
-- only if we can find the bindings.txt file
local function check_ingame_settings( _name, _ingame_key)
-- no more needed, because we take the keys from the file if we found the file
if( not bindings ) then -- no bindings.txt file loaded
return
end;
if( settings.hotkeys[_name].key ~= key["VK_"..bindings[_ingame_key].key1] and
settings.hotkeys[_name].key ~= key["VK_"..bindings[_ingame_key].key2] ) then
local msg = sprintf(language[125], _name); -- settings.xml don't match your RoM ingame
error(msg, 0);
end
end
function checkHotkeys(_name, _ingame_key)
if( not settings.hotkeys[_name] ) then
error(language[126] .. _name, 0); -- Global hotkey not set
end
-- check if settings.lua hotkeys match the RoM ingame settings
-- check_ingame_settings( _name, _ingame_key);
end
for i,v in pairs(elements) do
local name = v:getName();
if( string.lower(name) == "hotkeys" ) then
loadHotkeys(v);
elseif( string.lower(name) == "options" ) then
loadOptions(v);
end
end
-- TODO: don't work at the moment, becaus MACRO hotkey not available at this time
-- will first be available after reading profile file
-- read language from client if not set in settings.xml
-- if( not settings.options.LANGUAGE ) then
-- local hf_language = RoMScript("GetLanguage();"); -- read clients language
-- if( hf_language == "DE" ) then
-- settings.options.LANGUAGE = "deutsch";
-- elseif(hf_language == "ENEU" ) then
-- settings.options.LANGUAGE = "english";
-- elseif(hf_language == "FR" ) then
-- settings.options.LANGUAGE = "french";
-- else
-- settings.options.LANGUAGE = "english";
-- end
-- end
-- Load language files
-- Load "english" first, to fill in any gaps in the users' set language.
local function setLanguage(name)
include("/language/" .. name .. ".lua");
end
local lang_base = {};
setLanguage("english");
for i,v in pairs(language) do lang_base[i] = v; end;
setLanguage(settings.options.LANGUAGE);
for i,v in pairs(lang_base) do
if( language[i] == nil ) then
language[i] = v;
end
end;
lang_base = nil; -- Not needed anymore, destroy it.
logMessage("Language: " .. settings.options.LANGUAGE);
load_RoM_bindings_txt(); -- read bindings.txt from RoM user folder
-- Check to make sure everything important is set
-- bot hotkey name RoM ingame key name
checkHotkeys("MOVE_FORWARD", "MOVEFORWARD");
checkHotkeys("MOVE_BACKWARD", "MOVEBACKWARD");
checkHotkeys("ROTATE_LEFT", "TURNLEFT");
checkHotkeys("ROTATE_RIGHT", "TURNRIGHT");
checkHotkeys("STRAFF_LEFT", "STRAFELEFT");
checkHotkeys("STRAFF_RIGHT", "STRAFERIGHT");
checkHotkeys("JUMP", "JUMP");
checkHotkeys("TARGET", "TARGETNEARESTENEMY");
checkHotkeys("TARGET_FRIEND", "TARGETNEARESTFRIEND");
end
function settings.loadProfile(_name)
-- Delete old profile settings (if they even exist), restore defaults
settings.profile = settings_default.profile;
local filename = getExecutionPath() .. "/profiles/" .. _name .. ".xml";
local root = xml.open(filename);
local elements = root:getElements();
local loadOptions = function(node)
local elements = node:getElements();
for i,v in pairs(elements) do
settings.profile.options[v:getAttribute("name")] = v:getAttribute("value");
end
end
local loadHotkeys = function(node)
local elements = node:getElements();
for i,v in pairs(elements) do
settings.profile.hotkeys[v:getAttribute("name")] = {};
settings.profile.hotkeys[v:getAttribute("name")].name = v:getAttribute("name");
settings.profile.hotkeys[v:getAttribute("name")].key = key[v:getAttribute("key")];
settings.profile.hotkeys[v:getAttribute("name")].modifier = key[v:getAttribute("modifier")];
if( key[v:getAttribute("key")] == nil ) then
local err = sprintf(language[127], tostring(v:getAttribute("name")), _name ); -- Please set a valid key
error(err, 0);
end
checkKeySettings(v:getAttribute("name"),
v:getAttribute("key"),
v:getAttribute("modifier") );
end
end
local loadOnLoadEvent = function(node)
local luaCode = node:getValue();
if( luaCode == nil ) then return; end;
if( string.len(luaCode) > 0 and string.find(luaCode, "%w") ) then
settings.profile.events.onLoad = loadstring(luaCode);
assert(settings.profile.events.onLoad, sprintf(language[151], "onLoad"));
if( type(settings.profile.events.onLoad) ~= "function" ) then
settings.profile.events.onLoad = nil;
end;
end
end
local loadOnDeathEvent = function(node)
local luaCode = node:getValue();
if( luaCode == nil ) then return; end;
if( string.len(luaCode) > 0 and string.find(luaCode, "%w") ) then
settings.profile.events.onDeath = loadstring(luaCode);
assert(settings.profile.events.onDeath, sprintf(language[151], "onDeath"));
if( type(settings.profile.events.onDeath) ~= "function" ) then
settings.profile.events.onDeath = nil;
end;
end
end
local loadOnLeaveCombatEvent = function(node)
local luaCode = node:getValue();
if( luaCode == nil ) then return; end;
if( string.len(luaCode) > 0 and string.find(luaCode, "%w") ) then
settings.profile.events.onLeaveCombat = loadstring(luaCode);
assert(settings.profile.events.onLeaveCombat, sprintf(language[151], "onLeaveCombat"));
if( type(settings.profile.events.onLeaveCombat) ~= "function" ) then
settings.profile.events.onLeaveCombat = nil;
end;
end
end
local loadOnLevelupEvent = function(node)
local luaCode = node:getValue();
if( luaCode == nil ) then return; end;
if( string.len(luaCode) > 0 and string.find(luaCode, "%w") ) then
settings.profile.events.onLevelup = loadstring(luaCode);
assert(settings.profile.events.onLevelup, sprintf(language[151], "onLevelup"));
if( type(settings.profile.events.onLevelup) ~= "function" ) then
settings.profile.events.onLevelup = nil;
end;
end
end
local loadOnSkillCastEvent = function(node)
local luaCode = node:getValue();
if( luaCode == nil ) then return; end;
if( string.len(luaCode) > 0 and string.find(luaCode, "%w") ) then
settings.profile.events.onSkillCast= loadstring(luaCode);
assert(settings.profile.events.onSkillCast, sprintf(language[151], "onSkillCast"));
if( type(settings.profile.events.onSkillCast) ~= "function" ) then
settings.profile.events.onSkillCast = nil;
end;
end
end
local skillSort = function(tab1, tab2)
if( tab2.priority < tab1.priority ) then
return true;
end;
return false;
end
local loadSkills = function(node)
local elements = node:getElements();
for i,v in pairs(elements) do
local name, hotkey, modifier, level;
name = v:getAttribute("name");
-- hotkey = key[v:getAttribute("hotkey")];
modifier = key[v:getAttribute("modifier")];
level = v:getAttribute("level");
-- using the MACRO key as hotkey is also a valid key
if( string.upper( v:getAttribute("hotkey") ) == "MACRO" ) then
hotkey = "MACRO"; -- set MACRO as hotkey
else
hotkey = key[v:getAttribute("hotkey")]; -- read the virtual key numer
end
checkKeySettings( v:getAttribute("name"),
v:getAttribute("hotkey"),
v:getAttribute("modifier") );
-- Over-ride attributes
local priority, maxhpper, maxmanaper, cooldown, inbattle, pullonly, maxuse, autouse, rebuffcut;
priority = v:getAttribute("priority");
maxhpper = tonumber(v:getAttribute("hpper"));
targetmaxhpper = tonumber(v:getAttribute("targethpper"));
targetmaxhp = tonumber(v:getAttribute("targethp"));
maxmanaper = tonumber(v:getAttribute("manaper"));
cooldown = tonumber(v:getAttribute("cooldown"));
inbattle = v:getAttribute("inbattle");
pullonly = v:getAttribute("pullonly");
maxuse = tonumber(v:getAttribute("maxuse"));
rebuffcut = tonumber(v:getAttribute("rebuffcut"));
autouse = v:getAttribute("autouse");
-- Ensure that autouse is a proper type.
if( not (autouse == true or autouse == false) ) then
autouse = true;
end;
-- check if 'wrong' options are set
if( v:getAttribute("mana") or
v:getAttribute("manainc") or
v:getAttribute("rage") or
v:getAttribute("energy") or
v:getAttribute("concentration") or
v:getAttribute("range") or
v:getAttribute("minrange") or
v:getAttribute("type") or
v:getAttribute("target") or
v:getAttribute("casttime") ) then
local msg = sprintf(language[128], name, _name); -- are no valid options for your skill
error(msg, 0);
end;
if( v:getAttribute("modifier") ) then
local msg = sprintf(language[129], name, _name); -- modifier not supported
error(msg, 0);
end;
if( name == nil) then
local msg = sprintf(language[130], _name); -- empty\' skill name
error(msg, 0);
end;
if( inbattle ~= nil ) then
if( inbattle == "true" or
inbattle == true ) then
inbattle = true;
elseif( inbattle == "false" or
inbattle == false ) then
inbattle = false;
else
local msg = sprintf(language[131], inbattle, name, _name); -- wrong option inbattle
error(msg, 0);
end;
end
if( pullonly ~= nil ) then
if( pullonly == "true" or
pullonly == true ) then
pullonly = true;
else
local msg = sprintf(language[132], pullonly, name, _name); -- wrong option pullonly
error(msg, 0);
end;
end
if( level == nil or level < 1 ) then
level = 1;
end
local baseskill = database.skills[name];
if( not baseskill ) then
local err = sprintf("ERROR: \'%s\' is not defined in the database!", name);
error(err, 0);
end
local tmp = CSkill(database.skills[name]);
tmp.hotkey = hotkey;
tmp.modifier = modifier;
tmp.Level = level;
if( toggleable ) then tmp.Toggleable = toggleable; end;
if( priority ) then tmp.priority = priority; end
if( targetmaxhpper ) then tmp.TargetMaxHpPer = targetmaxhpper; end;
if( targetmaxhp ) then tmp.TargetMaxHp = targetmaxhp; end;
if( maxhpper ) then tmp.MaxHpPer = maxhpper; end;
if( maxmanaper ) then tmp.MaxManaPer = maxmanaper; end;
if( cooldown ) then tmp.Cooldown = cooldown; end;
if( inbattle ~= nil ) then tmp.InBattle = inbattle; end;
if( pullonly == true ) then tmp.pullonly = pullonly; end;
if( maxuse ) then tmp.maxuse = maxuse; end;
if( rebuffcut ) then tmp.rebuffcut = rebuffcut; end;
if( autouse == false ) then tmp.AutoUse = false; end;
table.insert(settings.profile.skills, tmp);
end
table.sort(settings.profile.skills, skillSort);
end
local loadFriends = function(node)
local elements = node:getElements();
for i,v in pairs(elements) do
local name = v:getAttribute("name");
if( name ) then name = trim(name); end;
if( name ) then
-- fix, because getAttribute seems not to recognize the escape characters
-- for special ASCII characters
name = string.gsub (name, "\\132", string.char(132)); -- ä
name = string.gsub (name, "\\142", string.char(142)); -- Ä
name = string.gsub (name, "\\148", string.char(148)); -- ö
name = string.gsub (name, "\\153", string.char(153)); -- Ö
name = string.gsub (name, "\\129", string.char(129)); -- ü
name = string.gsub (name, "\\154", string.char(154)); -- Ü
name = string.gsub (name, "\\225", string.char(225)); -- ß
table.insert(settings.profile.friends, name);
end
end
end
local loadMobs = function(node)
local elements = node:getElements();
for i,v in pairs(elements) do
local name = v:getAttribute("name");
if( name ) then name = trim(name); end;
if( name ) then
-- fix, because getAttribute seems not to recognize the escape characters
-- for special ASCII characters
name = string.gsub (name, "\\132", string.char(132)); -- ä
name = string.gsub (name, "\\142", string.char(142)); -- Ä
name = string.gsub (name, "\\148", string.char(148)); -- ö
name = string.gsub (name, "\\153", string.char(153)); -- Ö
name = string.gsub (name, "\\129", string.char(129)); -- ü
name = string.gsub (name, "\\154", string.char(154)); -- Ü
name = string.gsub (name, "\\225", string.char(225)); -- ß
table.insert(settings.profile.mobs, name);
end
end
end
local hf_temp = _name; -- remember profile name shortly
for i,v in pairs(elements) do
local name = v:getName();
if( string.lower(name) == "options" ) then
loadOptions(v);
elseif( string.lower(name) == "hotkeys" ) then
loadHotkeys(v);
elseif( string.lower(name) == "skills" ) then
loadSkills(v);
elseif( string.lower(name) == "friends" ) then
loadFriends(v);
elseif( string.lower(name) == "mobs" ) then
loadMobs(v);
elseif( string.lower(name) == "onload" ) then
loadOnLoadEvent(v);
elseif( string.lower(name) == "ondeath" ) then
loadOnDeathEvent(v);
elseif( string.lower(name) == "onleavecombat" ) then
loadOnLeaveCombatEvent(v);
elseif( string.lower(name) == "onlevelup" ) then
loadOnLevelupEvent(v);
elseif( string.lower(name) == "onskillcast" ) then
loadOnSkillCastEvent(v);
elseif( string.lower(name) == "skills_warrior" and
player.Class1 == CLASS_WARRIOR ) then
loadSkills(v);
elseif( string.lower(name) == "skills_scout" and
player.Class1 == CLASS_SCOUT ) then
loadSkills(v);
elseif( string.lower(name) == "skills_rogue" and
player.Class1 == CLASS_ROGUE ) then
loadSkills(v);
elseif( string.lower(name) == "skills_mage" and
player.Class1 == CLASS_MAGE ) then
loadSkills(v);
elseif( string.lower(name) == "skills_priest" and
player.Class1 == CLASS_PRIEST ) then
loadSkills(v);
elseif( string.lower(name) == "skills_knight" and
player.Class1 == CLASS_KNIGHT ) then
loadSkills(v);
elseif( string.lower(name) == "skills_warden" and
player.Class1 == CLASS_WARDEN ) then
loadSkills(v);
elseif( string.lower(name) == "skills_druid" and
player.Class1 == CLASS_DRUID ) then
loadSkills(v);
else -- warning for other stuff and misspellings
if ( string.lower(name) ~= "skills_warrior" and
string.lower(name) ~= "skills_scout" and
string.lower(name) ~= "skills_rogue" and
string.lower(name) ~= "skills_mage" and
string.lower(name) ~= "skills_priest" and
string.lower(name) ~= "skills_knight" and
string.lower(name) ~= "skills_warden" and
string.lower(name) ~= "skills_druid" ) then
cprintf(cli.yellow, tostring(language[60]), string.lower(tostring(name)),
tostring(hf_temp));
end;
end
end
-- checks for MACRO hotkey
-- print error if new macro option isn't defined
if( not settings.profile.hotkeys.MACRO ) then
cprintf(cli.yellow, language[900]);
cprintf(cli.yellow, language[901]);
cprintf(cli.yellow, language[902]);
cprintf(cli.yellow, language[903]);
cprintf(cli.yellow, language[904], "VK_0"); -- TODO: Change VK_0 to the actual hotkey we should use
local msg = sprintf(language[905], _name);
error(msg, 0);
end
-- check if new macro option is working / ingame macro defined and assigned
-- check it with a function with defined return values
settings.options.DEBUGGING_MACRO = true;
local hf_return = RoMScript("1234;ChatFrame1:AddMessage(\"MACRO test: send value 1234 to macro place 2\");");
if( hf_return ~= 1234 ) then -- return values not found
-- RoMScript("ChatFrame1:AddMessage(\"MACRO test: test failed !!! No return values found!\");"); -- overwrite return values
cprintf(cli.yellow, language[906] ); -- Define ingame an empty macro
if ( settings.profile.hotkeys.MACRO.key) then
hf_temp = getKeyName(settings.profile.hotkeys.MACRO.key);
else
local hf_temp ="<UNKNOWN>"; -- if ignore, key must not be set, so give value
end
local msg = sprintf(language[904], hf_temp );
error(msg, 0);
else -- return values found, clear it and send message
cprintf(cli.green, "MACRO Test: ok\n" );
RoMScript("xxxx; ChatFrame1:AddMessage(\"MACRO test: successful\");"); -- overwrite values
end
settings.options.DEBUGGING_MACRO = false;
-- MACRO is working, we can automaticly reset the langugae
-- remember game client language
local hf_langu = RoMScript("GetLanguage();");
if( not hf_langu ) then
local msg = sprintf(language[62]); -- Error while reading the language settings
-- error(msg, 0);
cprintf(cli.yellow, msg);
hf_langu = "ENEU";
end
bot.ClientLanguage = hf_langu; -- remember clients language
-- reset bot language to clients language
if( settings.options.USE_CLIENT_LANGUAGE ) then
local hf_language;
if( bot.ClientLanguage == "DE" ) then
hf_language = "deutsch";
elseif(bot.ClientLanguage == "FR" ) then
hf_language = "french";
elseif(bot.ClientLanguage == "RU" ) then
hf_language = "russian";
else
hf_language = "english";
end
if( settings.options.LANGUAGE ~= hf_language ) then -- load new language?
local function setLanguage(_name)
include(getExecutionPath() .. "/language/" .. _name .. ".lua");
end
local lang_base = {};
for i,v in pairs(language) do lang_base[i] = v; end; -- remember current language value to fill gaps with that
setLanguage(hf_language);
for i,v in pairs(lang_base) do
if( language[i] == nil ) then
language[i] = v;
end
end;
lang_base = nil; -- Not needed anymore, destroy it.
logMessage("Load Language according to client language: " .. hf_language);
end
end
-- now we can do all other setting checks
-- Check if the player has any ranged damage skills
local rangedSkills = false;
for i,v in pairs(settings.profile.skills) do
if( v.Range > 100 and
( v.Type == STYPE_DAMAGE or
v.Type == STYPE_DOT ) ) then
rangedSkills = true;
printf(language[176], v.Name); -- Ranged skill found
break;
end
end
if( rangedSkills == false and settings.profile.options.COMBAT_RANGED_PULL ) then
cprintf(cli.yellow, language[200]);
settings.profile.options.COMBAT_RANGED_PULL = false;
end
-- function checkProfileHotkeys(name)
-- if( not settings.profile.hotkeys[name] ) then
-- error("ERROR: Hotkey not set for this profile: " ..name, 0);
-- end
-- end
-- default combat type if not in profile defined
if( settings.profile.options.COMBAT_TYPE ~= "ranged" and
settings.profile.options.COMBAT_TYPE ~= "melee" ) then
if( player.Class1 == CLASS_WARRIOR or
player.Class1 == CLASS_ROGUE or
player.Class1 == CLASS_WARDEN or
player.Class1 == CLASS_KNIGHT ) then
settings.profile.options.COMBAT_TYPE = "melee";
elseif(
player.Class1 == CLASS_PRIEST or
player.Class1 == CLASS_SCOUT or
player.Class1 == CLASS_DRUID or
player.Class1 == CLASS_MAGE ) then
settings.profile.options.COMBAT_TYPE = "ranged";
else
error("undefined player.Class1 in settings.lua", 0);
end;
end
-- check if range attack range and combat distance fit together
local best_range = 0;
for i,v in pairs(settings.profile.skills) do
if( v.Range > best_range and
( v.Type == STYPE_DAMAGE or
v.Type == STYPE_DOT ) ) then
best_range = v.Range;
end
end
-- check is combat distance is greater then maximum ranged attack
if( best_range < settings.profile.options.COMBAT_DISTANCE and
(settings.profile.options.COMBAT_TYPE == "ranged" or
settings.profile.options.COMBAT_RANGED_PULL == true) ) then
local msg = sprintf(language[179], settings.profile.options.COMBAT_DISTANCE); -- Maximum range of range attack skills is lesser
error(msg, 0);
end
-- warning if not all inventory slots are updated
if( settings.profile.options.INV_AUTOSELL_TOSLOT > settings.profile.options.INV_MAX_SLOTS ) then
cprintf(cli.yellow, language[1003], settings.profile.options.INV_MAX_SLOTS, settings.profile.options.INV_AUTOSELL_TOSLOT);
end
-- check if igf addon is active
if ( RoMScript("IGF_INSTALLED") == true ) then
bot.IgfAddon = true;
else
bot.IgfAddon = false;
end
-- error if igf (ingamefunctions) addon isn't installed and options are set
if( bot.IgfAddon == false and
( settings.profile.options.INV_AUTOSELL_NOSELL_DURA > 0 or
settings.profile.options.INV_AUTOSELL_STATS_NOSELL ~= nil ) ) then
error(language[1004], 0) -- Ingamefunctions addon (igf) is not installed
end
-- check if automatic targeting is active
if( settings.profile.options.AUTO_TARGET == false ) then
cprintf(cli.yellow, "Caution: Automatic targeting is deactivated with option AUTO_TARGET=\"false\"\n");
end
end
Code: Select all
--[[ lib.lua
This is a pseudo library designed for MicroMaco.
Functions, variables, etc. declared here will
be accessable in all scripts made for MicroMacro.
Note: You should not modify this script unless
you are fixing something. Please report fixes
to the author (admin@solarstrike.net) or post
on the forums at www.solarstrike.net
Any changes you make may be overwritten if
you chose to update. Consider making a module
instead.
--]]
cocoAvailable = (coroutine.coco == true);
------------------------------------------------------
-- Import configurations and libraries, load modules
------------------------------------------------------
-- Set module path
package.path = ".\\?.lua;" .. getPath() .. "/lib/mods/?.lua" ;
package.cpath = ".\\?.dll;" .. getPath() .. "/plugins/?.dll;" .. getPath() .. "/lib/mods/?.dll";
local plugintab = getDirectory(getPath() .. "/plugins");
if( plugintab ) then
for i,v in pairs(plugintab) do
local extpos = string.find(v, ".dll");
if( extpos ) then
local fname = string.sub(v, 0, extpos - 1);
-- Make sure it's not already loaded for some reason
if( not package.loaded[fname] ) then
local success = package.loadlib(getPath() .. "/plugins/" .. v, "luaopen_" .. fname);
if( type(success) == "function" ) then
package.loaded[fname] = success();
else
package.loaded[fname] = success;
end
if( success ) then
logMessage("Loaded plugin \'" .. fname .. "\'");
else
logMessage("Failed to load plugin \'" .. fname .. "\'");
end
end
end
end
end
-- Autoload modules/plugins
local autoloadFile = io.open(getPath() .. "/lib/autoload.lua");
if( autoloadFile ) then
autoloadFile:close();
local autoload = dofile(getPath() .. "/lib/autoload.lua");
for i,v in pairs(autoload) do
require(v);
end
end
------------------------------------------------------
-- Keyboard & Language setup
------------------------------------------------------
key = nil;
if( keyboard ~= nil and type(keyboard) == "string" ) then
key = require("keyboard/" .. keyboard);
end
if( key == true or key == nil ) then
setTextColor(cli.yellow);
error("Error loading keyboard module.");
key = { };
end
------------------------------------------------------
-- VARIABLE DECLARATION
------------------------------------------------------
-- Our start/stop keys.
-- Only useful when using startMacro()
local startKeyDefault = key.VK_F5;
local stopKeyDefault = key.VK_F6;
local startKey = startKeyDefault;
local stopKey = stopKeyDefault;
-- Timed function list.
-- These are automatically "timed" when registered
local timerList = {}
-- Priority Defines -- DEPRECATED! Use priority.high, priority.low, or priority.normal instead
PRIORITY_HIGH = 1;
PRIORITY_NORMAL = 0;
PRIORITY_LOW = -1;
-- Protected environment vars
local __PErunning = false;
local __PEco;
------------------------------------------------------
-- FUNCTION DECLARATION
------------------------------------------------------
function setStartKey(val)
startKey = val
end
function getStartKey()
return startKey
end
function setStopKey(val)
stopKey = val
end
function getStopKey()
return stopKey
end
-- Runs a coroutine in a protected state, if available
function safeYield()
-- make sure we're not trying to yield in the main thread
-- do nothing.
local co = coroutine.running();
if( co == nil ) then
return;
end
if( cocoAvailable ) then
local status, err = pcall(coroutine.yield);
if( status ~= true ) then
setTextColor(cli.yellow);
error(err, 3);
end
else
coroutine.yield();
end
end
-- unpacks varargs and returns them as a table.
-- also returns 'n', the true size of the table.
function unpack2(...)
local n = select('#', ...);
local t = {};
for i = 1,n do
local v = select(i, ...);
t[i] = v;
end
return t, n;
end
-- Formatted output
-- C printf-like function
function printf(format, ...)
local t, n = unpack2(...);
for i = 1,n do
local v = t[i];
if( type(v) == "nil" ) then
local err = sprintf("bad argument #%d to 'printf' (got %s)", i, type(v));
error(err, 2);
end
if( type(v) == "table" or type(v) == "boolean" or type(v) == "function"
or type(v) == "thread" or type(v) == "userdata" ) then
t[i] = tostring(t[i]);
end
end
local status, err = pcall(string.format, format, unpack(t));
if( status == false ) then
error(err, 2);
end
io.write(err);
end
-- Formatted output
-- C sprintf-like function
--sprintf = string.format;
function sprintf(format, ...)
local t, n = unpack2(...);
for i = 1,n do
local v = t[i];
if( type(v) == "nil" ) then
local err = sprintf("bad argument #%d to 'sprintf' (got %s)", i, type(v));
error(err, 2);
end
if( type(v) == "table" or type(v) == "boolean" or type(v) == "function"
or type(v) == "thread" or type(v) == "userdata" ) then
t[i] = tostring(t[i]);
end
end
local status, err = pcall(string.format, format, unpack(t));
if( status == false ) then
error(err, 2);
end
return err;
end
-- Include another file
-- Directly calling dofile() may lead to issues with
-- relative paths. It is recommended to use include().
function include(file)
if( file == nil or string.len(file) < 1 ) then
error("Cannot include \'nil\'.", 2);
end
local startExecutionPath = getExecutionPath();
local test = string.find(file, "%a:[/\\]");
local isRelative = ( test == nil );
local status, err;
if( isRelative ) then
local fullpath = startExecutionPath .. "/" .. file;
setExecutionPath(getFilePath(fullpath));
status, err = pcall(dofile, fullpath);
else
setExecutionPath(getFilePath(file));
status, err = pcall(dofile, file);
end
if( not status ) then
error(err, 2);
end
setExecutionPath(startExecutionPath);
end
-- Time conversion for timers
-- Convert hours to timer value
function hoursToTimer(hours)
return math.floor( hours * 3600000 );
end
-- Convert minutes to timer value
function minutesToTimer(minutes)
return math.floor( minutes * 60000 );
end
-- Converts seconds to timer value
function secondsToTimer(seconds)
return math.floor( seconds * 1000 );
end
-- Prepares an at-exit callback function that is
-- called when the script terminates
local __EXIT_CALLBACK = nil;
function atExit(func)
if( type(func) ~= "function" and type(func) ~= "nil" ) then
local err = "Error: Non-function type passed to atExit() where a function is expected.";
setTextColor(cli.yellow);
error(err, 2);
return;
end
__EXIT_CALLBACK = func;
end
-- Prepare an at-pause callback function
-- called when the script is paused.
local function defaultPauseCallback()
printf("Paused.\n");
end
local __PAUSE_CALLBACK = defaultPauseCallback;
function atPause(func)
if( type(func) ~= "function" and type(func) ~= "nil" ) then
local err = "Error: Non-function type passed to atPause() where a function is expected.";
setTextColor(cli.yellow);
error(err, 2);
return;
end
__PAUSE_CALLBACK = func;
if( func == nil ) then
__PAUSE_CALLBACK = defaultPauseCallback;
end
end
-- Prepare an at-resume callback function
-- called when the script is resumed.
local function defaultResumeCallback()
printf("Started.\n");
end
local __RESUME_CALLBACK = defaultResumeCallback;
function atResume(func)
if( type(func) ~= "function" and type(func) ~= "nil" ) then
local err = "Error: Non-function type passed to atResume() where a function is expected.";
setTextColor(cli.yellow);
error(err, 2);
return;
end
__RESUME_CALLBACK = func;
if( func == nil ) then
__RESUME_CALLBACK = defaultResumeCallback;
end
end
-- Register a function to be called automatically.
-- Should be used in combination with startMacro
-- as opposed to manually.
function registerTimer(name, time, func, ...)
if( type(func) ~= "function" ) then
local err = "Error: Non-function type passed to registerTimer() where a function is expected.";
setTextColor(cli.yellow);
error(err, 2);
return;
end
if( type(time) ~= "number" ) then
local err = "Error: Non-numerical type passed to registerTimer() where a time value is expected.";
setTextColor(cli.yellow);
error(err, 2);
return;
end
local tmp = {};
tmp.time = time;
tmp.func = func;
tmp.args = unpack2(...);
newTimer(name);
startTimer(name, time);
timerList[name] = tmp;
end
-- Unregisters a function from being called automatically.
-- Only works if the function has been registered
function unregisterTimer(name)
if( timerList[name] ) then
timerList[name] = nil;
removeTimer(name);
end;
end
-- Toggles __PErunning to 0 in order to stop
-- the protected environment from continuing.
function stopPE()
__PErunning = false;
safeYield();
end
-- Start/resume the script
local function __start()
for i,v in pairs(timerList) do
if( isTriggered(i) ) then
-- restart timers
startTimer(i, v.time);
end
end
if( __RESUME_CALLBACK ~= nil ) then
__RESUME_CALLBACK();
end
__PErunning = true;
end
-- Stop/pause the script
local function __stop()
if( __PAUSE_CALLBACK ~= nil ) then
__PAUSE_CALLBACK();
end
__PErunning = false;
if( coroutine.running() ) then
-- Do not yield from main thread...
coroutine.yield();
end
end
-- Get debug information from any running script
local script_line = 0;
local script_name = "";
local function get_script_info(event, line)
script_line = line;
script_name = debug.getinfo(2).short_src;
end
debug.sethook(get_script_info, "l");
local function checkGlobalHotkeys()
local kp;
if( getAttachedHwnd() ~= 0 ) then
kp = keyPressedLocal(startKey);
else
kp = keyPressed(startKey);
end;
if( kp ) then
lastStartKey = true;
else
if( lastStartKey and not __PErunning ) then
__start();
end
lastStartKey = false;
end
if( getAttachedHwnd() ~= 0 ) then
kp = keyPressedLocal(stopKey);
else
kp = keyPressed(stopKey);
end;
if( kp ) then
lastStopKey = true;
else
if( lastStopKey and __PErunning ) then
__stop();
end
lastStopKey = false;
end
if( keyPressedLocal(key.VK_CONTROL) and keyPressedLocal(key.VK_L) ) then
return true;
else
return false;
end;
end
local function global_hotkey_hook(event, line)
if( checkGlobalHotkeys() ) then
stopPE();
end;
end
-- Protected environment for startMacro to run.
-- Runs the function as a coroutine.
-- It allows us to easily run certain tasks
-- regularly without having to program them
-- directly into the macro.
function __ProtectedEnvironment(foo, defaultstate)
if( defaultstate == false ) then
__PErunning = false;
printf("The macro is currently not running. Press the start key (%s) to begin.\n", getKeyName(startKey));
printf("You may use (%s) key to stop/pause the script.\n", getKeyName(stopKey));
else
__PErunning = true;
printf("Press the (%s) key to stop/pause the script.\nYou can resume with the (%s) key.\n",
getKeyName(stopKey), getKeyName(startKey));
end
local lastStartKey, lastStopKey = false, false;
__PEco = coroutine.create(function ()
math.randomseed(getTime().low);
foo();
end
);
-- Check global hotkeys every 10 lines.
-- This is to ensure that a thread doesn't get out of control
-- and become unrecoverable.
debug.sethook(__PEco, global_hotkey_hook, "l", 10);
local timerCo = coroutine.create(function()
math.randomseed(getTime().low);
while(true) do
-- automatic timer functions
if( __PErunning ) then
for i,v in pairs(timerList) do
if( isTriggered(i) ) then
startTimer(i, v.time); -- restart timer.
if( type(v.func) ~= "function" ) then
-- throw an error
local err = sprintf("Timer \'%s\' error: invalid function", i);
setTextColor(cli.yellow);
error(err, 2);
else
v.func(unpack(v.args));
end
end
end
end
coroutine.yield();
end
end
);
while( true ) do
if( checkGlobalHotkeys() ) then
break;
end;
if( coroutine.status(__PEco) ~= 'dead' ) then
-- continue macro
if( __PErunning ) then
-- Run main thread
local runstatus,message = coroutine.resume(__PEco);
if( runstatus == false ) then
local msg = debug.traceback(__PEco, "In main thread:", 1) ..
"\n\n----------TRACEBACK END----------\n\n";
logRaw(msg);
setTextColor(cli.yellow);
error(message, 2);
end
-- Run timer thread
runstatus,message = coroutine.resume(timerCo);
if( runstatus == false ) then
local msg = debug.traceback(timerCo, "In timer thread:", 1) ..
"\n\n----------TRACEBACK END----------\n\n";
logRaw(msg);
setTextColor(cli.yellow);
error(message, 2);
end
else
rest(10); -- minimize CPU usage
end
else
-- macro is "dead"
break;
end
end
-- cleanup timers
for i,v in pairs(timerList) do
timerList[i] = nil;
end
print("Stopping execution.");
--[[if( __PAUSE_CALLBACK ~= defaultPauseCallback and __PAUSE_CALLBACK ~= nil ) then
__PAUSE_CALLBACK();
end]]
if( __EXIT_CALLBACK ~= nil ) then
__EXIT_CALLBACK();
end
-- restore defaults
startKey = startKeyDefault;
stopKey = stopKeyDefault;
atResume(nil);
atPause(nil);
atExit(nil);
end
-- startMacro passes the call off to
-- __ProtectedEnvironment, and handles
-- any errors.
function startMacro(foo, defaultstate)
if( defaultstate ~= true ) then defaultstate = false; end;
if( type(foo) ~= "function" ) then
local err = "Error: Non-function type passed to startMacro(). Value is of type " .. type(foo) .. ".";
setTextColor(cli.yellow);
error(err, 2);
return;
end
local status, err = pcall(__ProtectedEnvironment, foo, defaultstate);
if( status ) then
-- no errors
else
-- errors occured...log them
setTextColor(cli.yellow);
error(err, 3);
end
end
-- A pretty standard rest/sleep command.
-- It automatically will yeild, though.
function yrest(msec)
if( msec == nil ) then error("yrest() cannot rest for \'nil\'.\n", 2); end;
safeYield();
-- if Coco is available, use 10ms sections. This is the highest
-- resolution available on Windows.
-- if Coco is not available, fall back on 100ms sections to
-- avoid yielding across C-boundaries
local resttime;
local sections;
local ext;
if( cocoAvailable ) then
resttime = 10;
else
resttime = 100;
end
if( msec < resttime ) then
rest(msec);
return;
else
local startTime = getTime();
while( deltaTime(getTime(), startTime) < msec ) do
rest(resttime);
safeYield();
end
end
end
-- Checks if a color is within 'accuracy' of another color.
-- Each channel is checked individually.
-- 'accuracy' should be between 0 and 255.
function colorMatch(color1, color2, accuracy)
local r1, g1, b1, r2, g2, b2;
if( accuracy == nil ) then accuracy = 0; end;
if( accuracy < 0 ) then accuracy = 0; end;
if( accuracy > 255 ) then accuracy = 255; end;
r1 = getR(color1); g1 = getG(color1); b1 = getB(color1);
r2 = getR(color2); g2 = getG(color2); b2 = getB(color2);
if( math.abs(r2 - r1) <= accuracy and
math.abs(g2 - g1) <= accuracy and
math.abs(b2 - b1) <= accuracy ) then
return true; -- they match
end;
return false; -- they don't match
end
-- Checks and returns true if a file exists.
function fileExists(fullpath)
local handle = io.open(fullpath, "r");
local success = handle ~= nil;
if( success ) then
handle:close();
end
return success;
end
-- "explode" a string into a table, splitting at 'token'
-- i.e. "Hello World, how are you?" explodes using the space
-- character would return {"Hello", "World,", "how", "are", "you?"}
-- if 'token' is not given, space is assumed.
function explode(instr, token)
local findpos;
local holder = {};
if( token == nil ) then token = " "; end
findpos = string.find(instr, token);
if( findpos == nil ) then return {instr}; end
while( findpos ) do
table.insert(holder, string.sub(instr, 0, findpos -1));
instr = string.sub(instr, findpos + string.len(token));
findpos = string.find(instr, token);
end
if( string.len(instr) ) then
table.insert(holder, instr);
end
return holder;
end
-- Throw a warning and log it
function warning(msg, showline)
if( type(msg) ~= "string" ) then
if( type(msg) == "number" ) then
msg = tostring(msg);
else
error("Non-string passed to function warning", 2);
end;
end;
if( type(showline) ~= "boolean" ) then
showline = true;
end;
if( showline ) then
msg = script_name .. ":" .. script_line .. "\n" .. msg;
end
setTextColor(cli.yellow);
print("[WARN]: " .. msg);
setTextColor(cli.lightgray);
logMessage("[WARN]: " .. msg);
end