-------------------------------------------------------------------------------- -- Gui.lua is part of ZS Shaiya Bot. -- -- ZS Shaiya Bot is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- ZS Shaiya Bot is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with ZS Shaiya Bot. If not, see . -- -- Copyright © 2009 ZS Shaiya Bot -------------------------------------------------------------------------------- -- Gui The Graphical User Interface. GUI_TEXT_MESSAGE_COUNT = 5 GUI_TEXT_MESSAGE_OBSTACLE = "There is an obstacle." GUI_TEXT_MESSAGE_LAND_OBSTACLE = "There is a land obstacle." GUI_TEXT_MESSAGE_SKILL_RECHARGING = "Recharge must be completed before next use" GUI_TEXT_MESSAGE_WRONG_TARGET = "Wrong target" GUI_TEXT_MESSAGE_PREV_SKILL_REQ = "A previous skill is required(%s*)" GUI_TEXT_MESSAGE_CANNOT_ATTACK = "Cannot attack" GUI_TEXT_MESSAGE_INVENTORY_FULL = "Insufficient inventory." GUI_TEXT_MESSAGE_SKILL_USED = "Used %s(.*)" GUI_TEXT_MESSAGE_CANNOT_USE_ITEM = "cannot use the item due to its limitation" GUI_TEXT_INSUFFICIENT_RANGE = "insufficient range" --GUI_TEXT_MESSAGE_SKILL_FAILED = "failed %s Lv%d " ------------------------------------------------------------------------------- -- Target variables ------------------------------------------------------------------------------- target_status = { unknown=0, damaged=1, full=2, } target_health_bar_color = { _min=RGB(150,10,50), _max=RGB(180,40,80), } TARGET_HEALTH_BAR_PIXEL_OFFSET_1 = {x=42, y=42}; TARGET_HEALTH_BAR_PIXEL_OFFSET_2 = {x=179, y=42}; -- Target Name Color TARGET_NAME_COLOR_SCAN_OFFSET_1 = {x=51, y=24}; TARGET_NAME_COLOR_SCAN_OFFSET_2 = {x=152, y=24}; GUI_STATUSMINIBAR_BAR_OFFSETS = { hp={x=80,y=41,w=118,}, mp={x=81,y=56,w=116,}, sp={x=76,y=73,w=120,}, } GUI_STATUSMINIBAR_COLOR_RANGE = { hp={_min=RGB(140,0,45), _max=RGB(210,30,75)}, mp={_min=RGB(0,145,195), _max=RGB(0,175,225)}, sp={_min=RGB(160,125,0), _max=RGB(190,155,30)}, } GUI_STATUSMINIBAR_BAR_SAMPLES = 20 target_name_color = { unknown=0, white=1, cyan=2, blue=3, green=4, yellow=5, orange=6, red=7, purple=8, grey=9, } target_name_color_rgb = { [target_name_color.white]={ _min=RGB(255,255,255), _max=RGB(255,255,255), }, [target_name_color.cyan]={ _min=RGB(120,255,255), _max=RGB(140,255,255), }, [target_name_color.blue]={ _min=RGB(0,0,255), _max=RGB(0,0,255), }, [target_name_color.green]={ _min=RGB(0,255,0), _max=RGB(0,255,0), }, [target_name_color.yellow]={ _min=RGB(255,255,0), _max=RGB(255,255,0), }, [target_name_color.orange]={ _min=RGB(255,115,0), _max=RGB(255,135,0), }, [target_name_color.red]={ _min=RGB(255,0,0), _max=RGB(255,0,0), }, [target_name_color.purple]={ _min=RGB(255,0,255), _max=RGB(255,0,255), }, --[[[target_name_color.grey]={ _min=RGB(255,255,255), _max=RGB(255,255,255), },]] } ------------------------------------------------------------------------------- -- Status Mini-bar (Your own bars). ------------------------------------------------------------------------------- GUI_STATUSMINIBAR_BAR_OFFSETS = { hp={x=82,y=38,w=130,}, mp={x=92,y=56,w=120,}, sp={x=95,y=75,w=115,}, } GUI_STATUSMINIBAR_COLOR_RANGE = { hp={_min=RGB(140,0,45), _max=RGB(210,30,75)}, mp={_min=RGB(0,145,195), _max=RGB(0,175,225)}, sp={_min=RGB(160,125,0), _max=RGB(190,155,30)}, } GUI_STATUSMINIBAR_BAR_SAMPLES = 20 -- constructor. Gui = class( function(obj) end ) GUI_MINIMAP_CIRCLE_OFFSET = {x=5,y=12,w=130,h=130} function Gui:get_closest_party_member() --local l_color = makeColor(56, 143, 189) local l_color = makeColor(56, 189, 86) l_minimap = {x=g_game_cfg[g_interface].MINIMAP_POS_X, y=g_game_cfg[g_interface].MINIMAP_POS_Y} local l_minimap_point_start = {x=(l_minimap.x + GUI_MINIMAP_CIRCLE_OFFSET.x), y=(l_minimap.y + GUI_MINIMAP_CIRCLE_OFFSET.y)} local l_minimap_point_end = {x=(l_minimap_point_start.x + GUI_MINIMAP_CIRCLE_OFFSET.w), y=(l_minimap_point_start.y + GUI_MINIMAP_CIRCLE_OFFSET.h)} local matches = match_pixels_in_rect(g_hdc, l_color, {l_minimap_point_start.x, l_minimap_point_start.y}, {l_minimap_point_end.x , l_minimap_point_end.y}, 5) print ("matches=", #matches) print_r(matches) local l_center_offset = {x=(l_minimap_point_start.x + (GUI_MINIMAP_CIRCLE_OFFSET.w / 2)), y=(l_minimap_point_start.y + (GUI_MINIMAP_CIRCLE_OFFSET.h / 2))} --print("l_center_offset:") print_r(l_center_offset) local l_closet_index = nil local l_closet_point = nil if (#matches == 0) then return 0, nil, nil end for k, v in pairs(matches) do --v.x = v.x - l_center_offset.x --v.y = v.y - l_center_offset.y v.dist = distance_2d_point(l_center_offset, v) if (l_closet_point == nil or l_closet_point > v.dist) then l_closest_index = k l_closet_point = v.dist end end --print(l_closest_index) print_r(l_closet_point) print_r(matches[l_closest_index]) matches[l_closest_index].x = matches[l_closest_index].x - l_center_offset.x matches[l_closest_index].y = matches[l_closest_index].y - l_center_offset.y --print_r(matches) --print_r(matches[l_closest_index]) return matches[l_closest_index] end -- accepts a data expression or a table of data expressions. function Gui:in_latest_text_msg(data) --local l_message = self:get_latest_text_msg(); local l_message = Hook:get_latest_text_msg("main", g_proc) --print_r(data) --print("l_msg: \"" .. l_message .. "\"") --local l_res = l_message:find(data) if (type(data) == "table") then for k,v in ipairs(data) do if (l_message:find(v) ~= nil) then return true end end return false else if (l_message:find(data) ~= nil) then return true end return false end end -- @param needle the needle in the message stack to search for. -- @return The index of the most recent message which contains the needle, and false otherwise. function Gui:find_in_text_msg_array(needle) --debug_message("gui - find_in_text_msg_array") local l_message local l_msg_index local l_msg_needle_index local l_msg_array_len = GUI_TEXT_MESSAGE_COUNT --local l_msg_latest_index = self:get_text_msg_offset() local l_msg_latest_index = Hook:get_text_msg_offset(g_proc) local l_address for i = 1, l_msg_array_len do --debug_message(i) l_msg_index = (l_msg_latest_index - i) % l_msg_array_len --debug_message("l_msg_index: " .. l_msg_index) --l_address = MEM_GAME_MESSAGE_OFFSET + (l_msg_index * MEM_GAME_MESSAGE_SIZE) local l_address = g_cfg.mem_text_message_offset + (l_msg_index * g_cfg.mem_text_message_size) --debug_message("l_address: " .. l_address) l_message = memoryReadString(get_process(), l_address) --debug_message("l_message: " .. l_message) l_msg_needle_index = l_message:find(needle) if (l_msg_needle_index ~= nil) then --debug_message("needle found, l_msg_index: " .. l_msg_index) return l_msg_index end end return false end function Gui:get_chat_common_latest() return memoryReadString(get_process(), GUI_CHAT_COMMON) end ------------------------------------------------------------------------------- -- Party Bars. ------------------------------------------------------------------------------- GUI_PARTY_MEMBER_BAR_SAMPLES = 10; GUI_PARTY_BAR_BARS = {x=30, y=30, width=120, height=22}; GUI_PARTY_BAR_MEMBER_HEIGHT = 52; GUI_PARTY_BAR_MAX_MEMBERS = 2; GUI_PARTY_BAR_HP = 1; GUI_PARTY_BAR_MP = 2; GUI_PARTY_BAR_SP = 3; GUI_PARTY_BAR_BAR_Y_OFFSET = {0, 9, 16,} GUI_PARTY_BAR_COLOR_RANGE = { {_min=RGB(150,50,80), _max=RGB(180,80,110)}, } -- gets the status of each party member. function Gui:get_party_status() local l_player_status_hp = {} local l_val for i = 1, GUI_PARTY_BAR_MAX_MEMBERS do l_val = self:get_party_member_status((i - 1), GUI_PARTY_BAR_HP) debug_message(sprintf("member: %d, status: %f", i, l_val)) table.insert(l_player_status_hp, {index=i, value=l_val}) end return l_player_status_hp end -- get the status bar value of a party member. -- @param index The index of the party member. -- @param bar_type The type of bar you want to check. -- @return The percentage of the bar in decimal format. function Gui:get_party_member_status(index, bar_type) -- which pixel to look at. --print(g_game_cfg[g_interface].PARTYMINIBAR_POS_X) local l_user_bar = { x=g_game_cfg[g_interface].PARTYMINIBAR_POS_X + GUI_PARTY_BAR_BARS.x, y=g_game_cfg[g_interface].PARTYMINIBAR_POS_Y + (index * GUI_PARTY_BAR_MEMBER_HEIGHT) + GUI_PARTY_BAR_BARS.y + GUI_PARTY_BAR_BAR_Y_OFFSET[bar_type], } local l_bar_piece = (GUI_PARTY_BAR_BARS.width / GUI_PARTY_MEMBER_BAR_SAMPLES) local l_min = GUI_PARTY_BAR_COLOR_RANGE[bar_type]._min local l_max = GUI_PARTY_BAR_COLOR_RANGE[bar_type]._max --print("rgb_min:") ; l_min:debug_msg() --print("rgb_max:") ; l_max:debug_msg() local l_pixel_offset local l_pixel --print("rgb_val:") for i=0, (GUI_PARTY_MEMBER_BAR_SAMPLES - 1) do l_pixel_offset = { x= l_user_bar.x + (l_bar_piece * i), y= l_user_bar.y , } --[[print(l_user_bar.x) print(l_bar_piece * i) print("l_pixel_offset:") print_r(l_pixel_offset)]] --l_r, l_g, l_b = getPixel(get_hdc(), l_pixel_offset.x, l_pixel_offset.y) --l_pixel = RGB(l_r, l_g, l_b) l_pixel = RGB( getPixel(get_hdc(), l_pixel_offset.x, l_pixel_offset.y)) --print_r(l_pixel) if (match_pixel(l_pixel, l_min, l_max) == false) then return (i / GUI_PARTY_MEMBER_BAR_SAMPLES) end end return 1 end -- get the status bar value of the user. -- @param bar_type The type of bar you want to check. -- @return The percentage of the bar in decimal format. function Gui:get_user_status(bar_type) local l_user_bar = { x=g_game_cfg[g_interface].STATUSMINIBAR_POS_X + GUI_STATUSMINIBAR_BAR_OFFSETS[bar_type].x, y=g_game_cfg[g_interface].STATUSMINIBAR_POS_Y + GUI_STATUSMINIBAR_BAR_OFFSETS[bar_type].y, } local l_bar_piece = (GUI_STATUSMINIBAR_BAR_OFFSETS[bar_type].w / GUI_STATUSMINIBAR_BAR_SAMPLES) local l_min = GUI_STATUSMINIBAR_COLOR_RANGE[bar_type]._min local l_max = GUI_STATUSMINIBAR_COLOR_RANGE[bar_type]._max local l_pixel_offset local l_pixel for i=0, GUI_STATUSMINIBAR_BAR_SAMPLES do l_pixel_offset = { x = l_user_bar.x + (l_bar_piece * i), y = l_user_bar.y, } l_pixel = RGB(getPixel(g_hdc, l_pixel_offset.x, l_pixel_offset.y)) if (match_pixel(l_pixel, l_min, l_max) == false) then return (i / GUI_STATUSMINIBAR_BAR_SAMPLES) end end end -- Looks at pixels in the status info bar in the h/w device context, -- to determine the status of the monster. -- @return target_status.unknown does not have any detectable red bar. -- target_status.damaged if some red bar exists. -- target_status.full full red bar. function Gui:get_target_status() l_infobar = { x=g_game_cfg[g_interface].STATUSINFOBAR_POS_X, y=g_game_cfg[g_interface].STATUSINFOBAR_POS_Y } local pos_1 = {x=(l_infobar.x + TARGET_HEALTH_BAR_PIXEL_OFFSET_1.x), y=(l_infobar.y + TARGET_HEALTH_BAR_PIXEL_OFFSET_1.y)}; local pos_2 = {x=(l_infobar.x + TARGET_HEALTH_BAR_PIXEL_OFFSET_2.x), y=(l_infobar.y + TARGET_HEALTH_BAR_PIXEL_OFFSET_2.y)}; --debug_message(string.format("x1:%d y1:%d x2:%d y2:%d\n", pos_1.x, pos_1.y, pos_2.x, pos_2.y)); local start_pixel = RGB(getPixel(g_hdc, pos_1.x, pos_1.y)) local end_pixel = RGB(getPixel(g_hdc, pos_2.x, pos_2.y)) if (match_pixel(start_pixel, target_health_bar_color._min, target_health_bar_color._max)) then if (match_pixel(end_pixel, target_health_bar_color._min, target_health_bar_color._max)) then return target_status.full; else return target_status.damaged; end end return target_status.unknown; end -- Gets the monster difficulty color, by reading each pixel in a small fixed -- line in the middle through the top of the lower case letters, -- in the monster name label. -- @return The color index of the name text on success, 0 on failure. function Gui:get_target_difficulty_color() --print("get_target_difficulty_color()") l_infobar = { x=g_game_cfg[g_interface].STATUSINFOBAR_POS_X, y=g_game_cfg[g_interface].STATUSINFOBAR_POS_Y} local pos_1 = {x=(l_infobar.x + TARGET_NAME_COLOR_SCAN_OFFSET_1["x"]), y=(l_infobar.y + TARGET_NAME_COLOR_SCAN_OFFSET_1["y"])} local pos_2 = {x=(l_infobar.x + TARGET_NAME_COLOR_SCAN_OFFSET_2["x"]), y=(l_infobar.y + TARGET_NAME_COLOR_SCAN_OFFSET_2["y"])} local pixel; --local l_hdc = get_hdc(); for i=pos_1.x, pos_2.x do for j=pos_1.y, pos_2.y do pixel = RGB(getPixel(g_hdc, i, j)) --pixel:debug_msg() for k,v in pairs(target_name_color_rgb) do if (match_pixel(pixel, v._min, v._max)) then return k end end end end return target_name_color.unknown end function Gui:check_player_requests() local pixel_pos = {x=(g_game_cfg.VIDEO.SIZE_X / 2) - 120, y=(g_game_cfg.VIDEO.SIZE_Y / 2) - 90} --print_r(pixel) color = makeColor(0, 0, 0); local l_x, l_y = pixelSearch(g_hdc, color, pixel_pos.x, pixel_pos.y, pixel_pos.x, pixel_pos.y, 10); --printf("x: %d, y: %d\n", l_x, l_y) return (l_x ~= -1) end