├── .gitignore ├── assets ├── BACK.png ├── BACK2.png ├── CHECK.png ├── MISSION.png ├── SieroTop.png └── icon.ico ├── components.ahk ├── gui ├── autokill.ahk ├── hotkey.ahk ├── panel.ahk ├── sell.ahk ├── skip.ahk └── window.ahk ├── macro.ahk ├── main.ahk ├── matcher ├── cond.ahk ├── matcher.ahk └── pixel.ahk └── utils.ahk /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | AHKGBFR 3 | 4 | test.ahk 5 | 6 | *.exe 7 | *.zip -------------------------------------------------------------------------------- /assets/BACK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TWT233/GBFRAuto/ff04286f2b398af67cdfcacfcbb3d025e2f47d24/assets/BACK.png -------------------------------------------------------------------------------- /assets/BACK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TWT233/GBFRAuto/ff04286f2b398af67cdfcacfcbb3d025e2f47d24/assets/BACK2.png -------------------------------------------------------------------------------- /assets/CHECK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TWT233/GBFRAuto/ff04286f2b398af67cdfcacfcbb3d025e2f47d24/assets/CHECK.png -------------------------------------------------------------------------------- /assets/MISSION.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TWT233/GBFRAuto/ff04286f2b398af67cdfcacfcbb3d025e2f47d24/assets/MISSION.png -------------------------------------------------------------------------------- /assets/SieroTop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TWT233/GBFRAuto/ff04286f2b398af67cdfcacfcbb3d025e2f47d24/assets/SieroTop.png -------------------------------------------------------------------------------- /assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TWT233/GBFRAuto/ff04286f2b398af67cdfcacfcbb3d025e2f47d24/assets/icon.ico -------------------------------------------------------------------------------- /components.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | #Include matcher/matcher.ahk 4 | #Include gui/panel.ahk 5 | #Include utils.ahk 6 | 7 | ; const 8 | 9 | GAME_NAME := "Granblue Fantasy: Relink" 10 | 11 | CONDS := { 12 | ; main match cond 13 | CHECK: Cond().Imgs(, "./assets/CHECK.png"), 14 | BACK: Cond().Imgs(, "./assets/BACK.png", "./assets/BACK2.png"), 15 | MISSION: Cond().Imgs(, "./assets/MISSION.png"), 16 | AUTOKILL: Cond().Pixels(, 17 | WhitePixel2K(510, 1325), 18 | WhitePixel2K(377, 1197), 19 | WhitePixel2K(510, 1060), 20 | ), 21 | CHAIN: Cond().Pixels(40, 22 | CHAINPixel(1274, 110), 23 | CHAINPixel(1156, 866), 24 | CHAINPixel(1599, 892), 25 | ), 26 | ; misc 27 | LotteryLV3: Cond().Pixels(10, 28 | Pixel(Color(113, 98, 78), 600, 380, 1440), 29 | Pixel(Color(113, 98, 78), 600, 525, 1440), 30 | ), 31 | SieroTop: Cond().Imgs(, "./assets/SieroTop.png"), 32 | } 33 | 34 | ; dynamic global vars 35 | 36 | M := Matcher(GAME_NAME) 37 | P := Panel(GAME_NAME) 38 | 39 | DATA := { 40 | times: { 41 | check: 0, 42 | back: 0, 43 | mission: 0, 44 | autokill: 0, 45 | } 46 | } -------------------------------------------------------------------------------- /gui/autokill.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | class PanelAutoKill { 4 | 5 | all := 0 6 | aaa := 0 7 | seya := 0 8 | guard := 0 9 | aim := 0 10 | forward := 0 11 | skills := 0 12 | r := 0 13 | g := 0 14 | chain := 0 15 | 16 | Attach(g, x, y) { 17 | g.Add("GroupBox", "Section w120 h220 x" x " y" y, "自动战斗相关") 18 | 19 | g.Add("CheckBox", "xs9 ys20", "总开关") 20 | .OnEvent("Click", (cb, *) => (this.all := cb.Value)) 21 | 22 | g.Add("CheckBox", , "连发平A") 23 | .OnEvent("Click", (cb, *) => (this.aaa := cb.Value)) 24 | 25 | g.Add("CheckBox", , "连发seya") 26 | .OnEvent("Click", (cb, *) => (this.seya := cb.Value)) 27 | 28 | g.Add("CheckBox", , "按住格挡") 29 | .OnEvent("Click", (cb, *) => (this.guard := cb.Value)) 30 | 31 | g.Add("CheckBox", , "按住索敌") 32 | .OnEvent("Click", (cb, *) => (this.aim := cb.Value)) 33 | 34 | g.Add("CheckBox", , "按住前进") 35 | .OnEvent("Click", (cb, *) => (this.forward := cb.Value)) 36 | 37 | g.Add("CheckBox", , "自动使用技能") 38 | .OnEvent("Click", (cb, *) => (this.skills := cb.Value)) 39 | 40 | g.Add("CheckBox", , "自动连锁") 41 | .OnEvent("Click", (cb, *) => (this.r := cb.Value)) 42 | 43 | g.Add("CheckBox", , "有奥义就开") 44 | .OnEvent("Click", (cb, *) => (this.g := cb.Value)) 45 | 46 | g.Add("CheckBox", , "有奥义等接") 47 | .OnEvent("Click", (cb, *) => (this.chain := cb.Value)) 48 | } 49 | } -------------------------------------------------------------------------------- /gui/hotkey.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | 4 | class PanelHotkey { 5 | reset := { 6 | g: unset, 7 | cb: unset, 8 | current: unset, 9 | } 10 | 11 | exit := { 12 | g: unset, 13 | cb: unset, 14 | current: unset, 15 | } 16 | 17 | sell_sigils := { 18 | g: unset, 19 | cb: unset, 20 | current: unset, 21 | } 22 | 23 | sell_charms := { 24 | g: unset, 25 | cb: unset, 26 | current: unset, 27 | } 28 | 29 | Attach(g, x, y) { 30 | g.Add("GroupBox", "Section w120 h150 x" x " y" y, "键位编辑") 31 | 32 | this.reset.g := g.Add("Hotkey", "xs9 ys25 w40") 33 | g.Add("Text", "xs55 ys30", "重置脚本") 34 | 35 | this.exit.g := g.Add("Hotkey", "xs9 ys55 w40") 36 | g.Add("Text", "xs55 ys60", "强退脚本") 37 | 38 | this.sell_sigils.g := g.Add("Hotkey", "xs9 ys85 w40") 39 | g.Add("Text", "xs55 ys90", "卖因子") 40 | 41 | this.sell_charms.g := g.Add("Hotkey", "xs9 ys115 w40") 42 | g.Add("Text", "xs55 ys120", "卖祝福") 43 | } 44 | 45 | BindReset(cb, initial) { 46 | this._RawBind(this.reset, cb, initial) 47 | } 48 | 49 | BindExit(cb, initial) { 50 | this._RawBind(this.exit, cb, initial) 51 | } 52 | 53 | BindSellSigils(cb, initial) { 54 | this._RawBind(this.sell_sigils, cb, initial) 55 | } 56 | 57 | BindSellCharms(cb, initial) { 58 | this._RawBind(this.sell_charms, cb, initial) 59 | } 60 | 61 | _RawBind(i, cb, initial) { 62 | i.cb := cb 63 | i.current := initial 64 | i.g.Value := initial 65 | Hotkey(i.current, i.cb) 66 | 67 | wrappedCB(ctrl, *) { 68 | try { 69 | Hotkey(ctrl.Value, i.cb) 70 | } catch Error { 71 | ctrl.Value := i.current 72 | return 73 | } 74 | Hotkey(i.current, "Off") 75 | i.current := ctrl.Value 76 | } 77 | 78 | i.g.OnEvent("Change", wrappedCB) 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /gui/panel.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | #Include window.ahk 4 | #Include skip.ahk 5 | #Include autokill.ahk 6 | #Include sell.ahk 7 | #Include hotkey.ahk 8 | 9 | class Panel { 10 | 11 | root := GUI(, "GBFRAuto") 12 | 13 | window := PanelWindow() 14 | skip := PanelSkip() 15 | autokill := PanelAutoKill() 16 | sell := PanelSell() 17 | hotkey := PanelHotkey() 18 | 19 | bar := unset 20 | 21 | __New(game_name) { 22 | this.root.SetFont("s10") 23 | this.window.Attach(this.root, 10, 9, game_name) 24 | this.skip.Attach(this.root, 140, 90) 25 | this.sell.Attach(this.root, 140, 180) 26 | this.hotkey.Attach(this.root, 10, 90) 27 | this.autokill.Attach(this.root, 270, 9) 28 | 29 | this.bar := this.root.Add("StatusBar", , "继续挑战 0 | 奖励确认 0 | 任务结算 0") 30 | } 31 | 32 | Show() { 33 | this.root.Show() 34 | } 35 | 36 | OnClose(on_close) { 37 | this.root.OnEvent("Close", on_close) 38 | } 39 | 40 | OnGameNameChange(cb) { 41 | this.window.OnChange(cb) 42 | } 43 | 44 | UpdateWindowInfo(w, h) { 45 | this.window.UpdateWindowInfo(w, h) 46 | } 47 | 48 | UpdateReport(check := 0, back := 0, mission := 0) { 49 | this.UpdateBar("继续挑战 " check " | 奖励确认 " back " | 任务结算 " mission) 50 | } 51 | 52 | UpdateBar(info) { 53 | this.bar.SetText(info) 54 | } 55 | } -------------------------------------------------------------------------------- /gui/sell.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | 4 | class PanelSell { 5 | 6 | rounds := 0 7 | 8 | Attach(g, x, y) { 9 | g.Add("GroupBox", "Section w120 h70 x" x " y" y, "自动卖因子/祝福") 10 | g.Add("Text", "xs9 ys25", "轮数:") 11 | g.Add("Edit", "w60 xs50 ys20") 12 | g.Add("UpDown", "Range0-10", 0) 13 | .OnEvent("Change", (ud, *) => (this.rounds := ud.Value)) 14 | g.Add("Text", "xs9 ys50", "轮数=0为无限卖") 15 | } 16 | } -------------------------------------------------------------------------------- /gui/skip.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | class PanelSkip { 4 | 5 | mission := 1 6 | back := 1 7 | check := 1 8 | 9 | Attach(g, x, y) { 10 | g.Add("GroupBox", "Section w120 h85 x" x " y" y, "跳过结算相关") 11 | 12 | g.Add("CheckBox", "Checked xs9 ys20", "跳过任务结算") 13 | .OnEvent("Click", (cb, *) => (this.mission := cb.Value)) 14 | 15 | g.Add("CheckBox", "Checked", "跳过奖励确认") 16 | .OnEvent("Click", (cb, *) => (this.back := cb.Value)) 17 | 18 | g.Add("CheckBox", "Checked", "自动继续挑战") 19 | .OnEvent("Click", (cb, *) => (this.check := cb.Value)) 20 | } 21 | } -------------------------------------------------------------------------------- /gui/window.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | class PanelWindow { 4 | g := { 5 | e_game_name: unset, 6 | window_info: unset, 7 | } 8 | 9 | Attach(g, x, y, game_name) { 10 | g.Add("GroupBox", "Section w250 h75 x" x " y" y, "游戏窗口设置") 11 | g.Add("Text", "xs9 ys25", "窗口名:") 12 | 13 | this.g.e_game_name := g.Add("Edit", "w180 xs60 ys20", game_name) 14 | 15 | this.g.window_info := g.Add("Text", "xs9 ys50", "游戏窗口大小: ") 16 | } 17 | 18 | OnChange(cb) { 19 | this.g.e_game_name.OnEvent("Change", cb) 20 | } 21 | 22 | UpdateWindowInfo(w, h) { 23 | this.g.window_info.Value := "游戏窗口大小:" w " x " h 24 | } 25 | } -------------------------------------------------------------------------------- /macro.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | #Include utils.ahk 4 | #Include components.ahk 5 | 6 | GAP := 200 7 | SLOW_GAP := 1000 8 | GUARD := (len := 500) => (Sleep(len)) 9 | 10 | SellCharmAndLottery(*) { 11 | FilterToMain() 12 | i := 0 13 | while (P.sell.rounds == 0 || i < P.sell.rounds) 14 | { 15 | MainToSell() 16 | SellCharms() 17 | SellToLottery() 18 | LotteryToLV3(M) 19 | DoLottery(M) 20 | LotteryToMain() 21 | i++ 22 | } 23 | } 24 | 25 | SellCharms() { 26 | loop 30 { 27 | EventClick("LButton", , , GAP) 28 | EventClick("s", , , GAP) 29 | } 30 | Sell() 31 | GUARD() 32 | } 33 | 34 | SellSigilsAndLottery(*) { 35 | FilterToMain() 36 | i := 0 37 | while (P.sell.rounds == 0 || i < P.sell.rounds) 38 | { 39 | MainToSell() 40 | SellSigils() 41 | SellToLottery() 42 | LotteryToLV3(M) 43 | DoLottery(M) 44 | LotteryToMain() 45 | i++ 46 | } 47 | } 48 | 49 | SellSigils() { 50 | EventClick("Tab", , , GAP) 51 | Sell() 52 | GUARD() 53 | } 54 | 55 | FilterToMain() { 56 | EventClick("RButton", , , GAP) 57 | EventClick("RButton", , , GAP) 58 | GUARD() 59 | } 60 | 61 | MainToSell() { 62 | EventClick("LButton", , , GAP) 63 | } 64 | 65 | Sell() { 66 | EventClick("3", , , GAP) 67 | EventClick("w", , , GAP) 68 | EventClick("LButton", , , GAP) 69 | EventClick("LButton", , , GAP) 70 | EventClick("s", , , GAP) 71 | EventClick("LButton", , , GAP) 72 | EventClick("LButton", , , GAP) 73 | } 74 | 75 | SellToLottery() { 76 | EventClick("RButton", , , SLOW_GAP) 77 | EventClick("RButton", , , GAP) 78 | GUARD(1000) ; slow main menu 79 | EventClick("s", , , GAP) 80 | EventClick("LButton", , , GAP) 81 | GUARD() 82 | } 83 | 84 | LotteryToLV3(M) { 85 | GuardLoop(() => (M.Match(CONDS.LotteryLV3)), 86 | () => (EventClick("s", , , SLOW_GAP)), GUARD) 87 | GUARD() 88 | } 89 | 90 | DoLottery(M) { 91 | loop 1200 { 92 | EventClick("LButton", 20, , 20) 93 | } 94 | GUARD() 95 | } 96 | 97 | LotteryToMain() { 98 | while (!M.Match(CONDS.SieroTop)) { 99 | EventClick("RButton", , , SLOW_GAP) 100 | } 101 | EventClick("w", , , GAP) 102 | EventClick("LButton", , , GAP) 103 | GUARD() 104 | } -------------------------------------------------------------------------------- /main.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | #Include utils.ahk 4 | #Include macro.ahk 5 | #Include components.ahk 6 | 7 | ; main 8 | Init() 9 | 10 | M.Register(CONDS.CHECK, CB_CHECK, (*) => P.skip.check) 11 | M.Register(CONDS.BACK, CB_BACK, (*) => P.skip.back) 12 | M.Register(CONDS.MISSION, CB_MISSION, (*) => P.skip.mission) 13 | M.Register(CONDS.AUTOKILL, CB_AUTOKILL, (*) => P.autokill.all) 14 | 15 | M.Run() 16 | 17 | ; init 18 | 19 | Init() { 20 | SetKeyDelay -1 21 | 22 | Refresh() 23 | 24 | P.hotkey.BindReset(OnReset, "]") 25 | P.hotkey.BindExit(OnClose, "[") 26 | P.hotkey.BindSellSigils(SellSigilsAndLottery, "\") 27 | P.hotkey.BindSellCharms(SellCharmAndLottery, "=") 28 | 29 | P.OnClose(OnClose) 30 | P.OnGameNameChange((edit, *) => ( 31 | M.name := edit.Value 32 | Refresh() 33 | )) 34 | P.Show() 35 | } 36 | 37 | ; call backs on search found 38 | 39 | CB_BACK(*) { 40 | EventClick("LButton", , 500) 41 | EventClick("LButton", , 500) 42 | 43 | DATA.times.back++ 44 | Refresh() 45 | } 46 | 47 | CB_CHECK(*) { 48 | EventClick("w", , 500) 49 | EventClick("LButton", , 500) 50 | 51 | DATA.times.check++ 52 | Refresh() 53 | } 54 | 55 | CB_MISSION(*) { 56 | loop { 57 | EventClick("LButton", , , 200) 58 | } until (M.Match(CONDS.MISSION) == 0) 59 | 60 | DATA.times.mission++ 61 | Refresh() 62 | } 63 | 64 | CB_AUTOKILL(*) { 65 | v := P.autokill 66 | 67 | AUTOKILL_ENTER() 68 | loop { 69 | if v.aaa { 70 | loop 20 { 71 | EventClick("LButton", 15, , 15) 72 | } 73 | } else if v.seya { 74 | EventClick("RButton", 15, , 15) 75 | } else { 76 | Sleep(500) 77 | } 78 | AUTOKILL_ROUTINED(M, v) 79 | } until (M.Match(CONDS.AUTOKILL) == 0) 80 | AUTOKILL_LEAVE() 81 | } 82 | 83 | AUTOKILL_ENTER() { 84 | v := P.autokill 85 | 86 | if v.guard { 87 | SendEvent("{q down}") 88 | } 89 | if v.aim { 90 | SendEvent("{MButton down}") 91 | } 92 | if v.forward { 93 | SendEvent("{w down}") 94 | } 95 | } 96 | 97 | AUTOKILL_LEAVE() { 98 | v := P.autokill 99 | 100 | if v.guard { 101 | SendEvent("{q up}") 102 | } 103 | if v.aim { 104 | SendEvent("{MButton up}") 105 | } 106 | if v.forward { 107 | SendEvent("{w up}") 108 | } 109 | } 110 | 111 | AUTOKILL_ROUTINED(M, v) { 112 | if v.skills { 113 | AUTOKILL_SKILLS() 114 | } 115 | if v.r { 116 | EventClick("r", 20, , 20) 117 | } 118 | if v.g { 119 | EventClick("g", 20, , 20) 120 | } 121 | if v.chain { 122 | GuardLoop(() => (!M.Match(CONDS.CHAIN)), () => (EventClick("g", 20, , 20)), () => 0) 123 | } 124 | } 125 | 126 | AUTOKILL_SKILLS() { 127 | EventClick("1", 20, , 20) 128 | EventClick("2", 20, , 20) 129 | EventClick("3", 20, , 20) 130 | EventClick("4", 20, , 20) 131 | } 132 | 133 | ; util functions 134 | 135 | Refresh() { 136 | t := DATA.times 137 | P.UpdateReport(t.check, t.back, t.mission) 138 | 139 | w := 0 140 | h := 0 141 | M.GetGameWindow(&w, &h) 142 | P.UpdateWindowInfo(w, h) 143 | } -------------------------------------------------------------------------------- /matcher/cond.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | #Include pixel.ahk 4 | 5 | class Cond { 6 | matcher := unset 7 | 8 | Imgs(shades := 128, paths*) { 9 | matcher(this, M) { 10 | w := 0 11 | h := 0 12 | ret := M.GetGameWindow(&w, &h) 13 | if ret != 1 { 14 | return 0 15 | } 16 | 17 | _ := 0 18 | for p in paths { 19 | if ImageSearch(&_, &_, 0, 0, w, h, "*" shades " *TransBlack *w" w " *h-1 " p) == true { 20 | return true 21 | } 22 | } 23 | return false 24 | } 25 | this.matcher := matcher 26 | return this 27 | } 28 | 29 | Pixels(shades := 2, pixels*) { 30 | matcher(this, M) { 31 | w := 0 32 | h := 0 33 | ret := M.GetGameWindow(&w, &h) 34 | if ret != 1 { 35 | return 0 36 | } 37 | 38 | for p in pixels { 39 | val := HexToColor(PixelGetColor(p.x * h // p.h, p.y * h // p.h)) 40 | if !p.MatchWithShades(val, shades) { 41 | return false 42 | } 43 | } 44 | return true 45 | } 46 | this.matcher := matcher 47 | return this 48 | } 49 | } -------------------------------------------------------------------------------- /matcher/matcher.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | #Include cond.ahk 4 | 5 | 6 | class Matcher { 7 | name := "" ; attached window name 8 | 9 | interval := 500 10 | 11 | regs := [] ; registered conditions 12 | 13 | __New(name, interval := 500) { 14 | this.name := name 15 | this.interval := interval 16 | } 17 | 18 | Register(con, cb, enabler := (*) => true) { 19 | this.regs.Push({ 20 | cond: con, 21 | cb: cb, 22 | enabler: enabler, 23 | }) 24 | } 25 | 26 | Run() { 27 | loop { 28 | Sleep(this.interval) 29 | 30 | if (!this.IsCurrentGameWindow()) { 31 | continue 32 | } 33 | 34 | for reg in this.regs { 35 | if reg.enabler() != 1 { 36 | continue 37 | } 38 | if this.Match(reg.cond) == 0 { 39 | continue 40 | } 41 | reg.cb() 42 | } 43 | } 44 | } 45 | 46 | Match(con) { 47 | return con.matcher(this) 48 | } 49 | 50 | ; returns 1 if exists, otherwise 0 51 | GetGameWindow(&w, &h) { 52 | try { 53 | WinGetClientPos(, , &w, &h, this.name) 54 | } 55 | catch TargetError { 56 | w := 0 57 | h := 0 58 | return 0 59 | } 60 | return 1 61 | } 62 | 63 | IsCurrentGameWindow() { 64 | return !!WinActive(this.name) 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /matcher/pixel.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | class Color { 4 | __New(r, g, b) { 5 | this.r := r 6 | this.g := g 7 | this.b := b 8 | } 9 | 10 | ToString() { 11 | return Format("{:02X}{:02X}{:02X}", this.r, this.g, this.b) 12 | } 13 | 14 | } 15 | 16 | 17 | class Pixel { 18 | __New(color, x, y, h) { 19 | this.color := color 20 | 21 | this.x := x 22 | this.y := y 23 | this.h := h 24 | } 25 | 26 | MatchWithShades(color, shades := 2) { 27 | ; MsgBox(color.ToString() " vs " this.color.ToString()) 28 | dr := Abs(color.r - this.color.r) 29 | dg := Abs(color.g - this.color.g) 30 | db := Abs(color.b - this.color.b) 31 | return dr <= shades && dg <= shades && db <= shades 32 | } 33 | 34 | ToString() { 35 | return Format("[{},{}]({})", this.x, this.y, this.color.ToString()) 36 | } 37 | } 38 | 39 | HexToColor(hex) { 40 | return Color( 41 | ("0x" SubStr(hex, 3, 2)) + 0, 42 | ("0x" SubStr(hex, 5, 2)) + 0, 43 | ("0x" SubStr(hex, 7, 2)) + 0 44 | ) 45 | } -------------------------------------------------------------------------------- /utils.ahk: -------------------------------------------------------------------------------- 1 | #Requires AutoHotkey v2.0 2 | 3 | #Include matcher/pixel.ahk 4 | 5 | EventClick(key, len := 50, pre := 0, post := 0) { 6 | Sleep pre 7 | SendEvent "{" key " Down}" 8 | Sleep len 9 | SendEvent "{" key " up}" 10 | Sleep post 11 | } 12 | 13 | GuardLoop(untiler, body, post) { 14 | while (untiler() == 0) { 15 | loop { 16 | body() 17 | } until (untiler() == 1) 18 | post() 19 | } 20 | } 21 | 22 | Cleanup() { 23 | SendEvent("{1 up}") 24 | SendEvent("{2 up}") 25 | SendEvent("{3 up}") 26 | SendEvent("{4 up}") 27 | SendEvent("{w up}") 28 | SendEvent("{s up}") 29 | SendEvent("{q up}") 30 | SendEvent("{r up}") 31 | SendEvent("{g up}") 32 | SendEvent("{MButton up}") 33 | SendEvent("{RButton up}") 34 | SendEvent("{LButton up}") 35 | } 36 | 37 | OnReset(*) { 38 | Cleanup() 39 | Reload 40 | } 41 | 42 | OnClose(*) { 43 | Cleanup() 44 | ExitApp 45 | } 46 | 47 | WhitePixel2K(x, y) { 48 | return Pixel(Color(0xFF, 0xFF, 0xFF), x, y, 1440) 49 | } 50 | 51 | CHAINPixel(x, y) { 52 | return Pixel(Color(160, 255, 255), x, y, 1440) 53 | } --------------------------------------------------------------------------------