Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Исходник [AHK] RuneScape Nom AHK — Маркер и автокликер с хуманизацией

Sloppy
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
445
Реакции
10
Народ, кто плотно сидит в RuneScape и ищет способ автоматизировать рутину без моментального бана — нашел обновленный скрипт от NOM. Автор PilgrimMites допилил базу, добавив вменяемую хуманизацию. Теперь мышь не просто прыгает по координатам, а имитирует движение живого игрока с рандомизацией траекторий и задержек.

Что умеет этот скрипт:
Позволяет размечать до 4 цветовых групп точек, по 28 позиций на каждый цвет. Этого за глаза хватит для большинства задач по скиллингу или фарму.

Основные фичи апдейта:
  1. Улучшенная логика Humanization: мышь возвращается в исходную точку с небольшим разбросом.
  2. Рандомизированные клики и задержки (RandomDelay).
  3. Добавлены функции Click Box и Mouse Move для плавности.
  4. Всплывающие подсказки (ToolTip) с актуальными биндами.
  5. Возможность скрытия GUI-точек прямо во время работы.

Управление и хоткеи:
  1. CTRL + Numpad 1/2/3/4 — Поставить точку для соответствующей группы.
  2. Numpad 1/2/3/4 — Начать прокликивание по отмеченным точкам.
  3. ALT + Numpad 1/2/3/4 — Очистить точки группы.
  4. F5 — Показать/скрыть маркеры на экране.
  5. F6 — Полный выход из скрипта.

Код:
Expand Collapse Copy
#NoEnv
SetWorkingDir %A_ScriptDir%
SendMode Input
#SingleInstance Force
#WinActivateForce
CoordMode, mouse, Screen
 
 
SetTimer, RemoveToolTip, -10000
ToolTip, Script Created by Nom`nUpdated By PilgrimMites`nCtrl+Numpad1-4 Add point`nAlt+Numpad1-4 Clear points`nNumpad1-4 Click points`nF6 to exit`nF5 toggle display,0,0
class JSON
{
class Load extends JSON.Functor
{
Call(self, ByRef text, reviver:="")
{
this.rev := IsObject(reviver) ? reviver : false
this.keys := this.rev ? {} : false
static quot := Chr(34), bashq := "\" . quot
, json_value := quot . "{[01234567890-tfn"
, json_value_or_array_closing := quot . "{[]01234567890-tfn"
, object_key_or_object_closing := quot . "}"
key := ""
is_key := false
root := {}
stack := [root]
next := json_value
pos := 0
while ((ch := SubStr(text, ++pos, 1)) != "") {
if InStr(" `t`r`n", ch)
continue
if !InStr(next, ch, 1)
this.ParseError(next, text, pos)
holder := stack[1]
is_array := holder.IsArray
if InStr(",:", ch) {
next := (is_key := !is_array && ch == ",") ? quot : json_value
} else if InStr("}]", ch) {
ObjRemoveAt(stack, 1)
next := stack[1]==root ? "" : stack[1].IsArray ? ",]" : ",}"
} else {
if InStr("{[", ch) {
static json_array := Func("Array").IsBuiltIn || ![].IsArray ? {IsArray: true} : 0
(ch == "{")
? ( is_key := true
, value := {}
, next := object_key_or_object_closing )
: ( value := json_array ? new json_array : []
, next := json_value_or_array_closing )
ObjInsertAt(stack, 1, value)
if (this.keys)
this.keys[value] := []
} else {
if (ch == quot) {
i := pos
while (i := InStr(text, quot,, i+1)) {
value := StrReplace(SubStr(text, pos+1, i-pos-1), "\\", "\u005c")
static tail := A_AhkVersion<"2" ? 0 : -1
if (SubStr(value, tail) != "\")
break
}
if (!i)
this.ParseError("'", text, pos)
value := StrReplace(value,  "\/",  "/")
, value := StrReplace(value, bashq, quot)
, value := StrReplace(value,  "\b", "`b")
, value := StrReplace(value,  "\f", "`f")
, value := StrReplace(value,  "\n", "`n")
, value := StrReplace(value,  "\r", "`r")
, value := StrReplace(value,  "\t", "`t")
pos := i
i := 0
while (i := InStr(value, "\",, i+1)) {
if !(SubStr(value, i+1, 1) == "u")
this.ParseError("\", text, pos - StrLen(SubStr(value, i+1)))
uffff := Abs("0x" . SubStr(value, i+2, 4))
if (A_IsUnicode || uffff < 0x100)
value := SubStr(value, 1, i-1) . Chr(uffff) . SubStr(value, i+6)
}
if (is_key) {
key := value, next := ":"
continue
}
} else {
value := SubStr(text, pos, i := RegExMatch(text, "[\]\},\s]|$",, pos)-pos)
static number := "number", integer :="integer"
if value is %number%
{
if value is %integer%
value += 0
}
else if (value == "true" || value == "false")
value := %value% + 0
else if (value == "null")
value := ""
else
this.ParseError(next, text, pos, i)
pos += i-1
}
next := holder==root ? "" : is_array ? ",]" : ",}"
}
is_array? key := ObjPush(holder, value) : holder[key] := value
if (this.keys && this.keys.HasKey(holder))
this.keys[holder].Push(key)
}
}
return this.rev ? this.Walk(root, "") : root[""]
}
ParseError(expect, ByRef text, pos, len:=1)
{
static quot := Chr(34), qurly := quot . "}"
line := StrSplit(SubStr(text, 1, pos), "`n", "`r").Length()
col := pos - InStr(text, "`n",, -(StrLen(text)-pos+1))
msg := Format("{1}`n`nLine:`t{2}`nCol:`t{3}`nChar:`t{4}"
,     (expect == "")     ? "Extra data"
: (expect == "'")    ? "Unterminated string starting at"
: (expect == "\")    ? "Invalid \escape"
: (expect == ":")    ? "Expecting ':' delimiter"
: (expect == quot)   ? "Expecting object key enclosed in double quotes"
: (expect == qurly)  ? "Expecting object key enclosed in double quotes or object closing '}'"
: (expect == ",}")   ? "Expecting ',' delimiter or object closing '}'"
: (expect == ",]")   ? "Expecting ',' delimiter or array closing ']'"
: InStr(expect, "]") ? "Expecting JSON value or array closing ']'"
:                      "Expecting JSON value(string, number, true, false, null, object or array)"
, line, col, pos)
static offset := A_AhkVersion<"2" ? -3 : -4
throw Exception(msg, offset, SubStr(text, pos, len))
}
Walk(holder, key)
{
value := holder[key]
if IsObject(value) {
for i, k in this.keys[value] {
v := this.Walk(value, k)
if (v != JSON.Undefined)
value[k] := v
else
ObjDelete(value, k)
}
}
return this.rev.Call(holder, key, value)
}
}
class Dump extends JSON.Functor
{
Call(self, value, replacer:="", space:="")
{
this.rep := IsObject(replacer) ? replacer : ""
this.gap := ""
if (space) {
static integer := "integer"
if space is %integer%
Loop, % ((n := Abs(space))>10 ? 10 : n)
this.gap .= " "
else
this.gap := SubStr(space, 1, 10)
this.indent := "`n"
}
return this.Str({"": value}, "")
}
Str(holder, key)
{
value := holder[key]
if (this.rep)
value := this.rep.Call(holder, key, ObjHasKey(holder, key) ? value : JSON.Undefined)
if IsObject(value) {
static type := A_AhkVersion<"2" ? "" : Func("Type")
if (type ? type.Call(value) == "Object" : ObjGetCapacity(value) != "") {
if (this.gap) {
stepback := this.indent
this.indent .= this.gap
}
is_array := value.IsArray
if (!is_array) {
for i in value
is_array := i == A_Index
until !is_array
}
str := ""
if (is_array) {
Loop, % value.Length() {
if (this.gap)
str .= this.indent
v := this.Str(value, A_Index)
str .= (v != "") ? v . "," : "null,"
}
} else {
colon := this.gap ? ": " : ":"
for k in value {
v := this.Str(value, k)
if (v != "") {
if (this.gap)
str .= this.indent
str .= this.Quote(k) . colon . v . ","
}
}
}
if (str != "") {
str := RTrim(str, ",")
if (this.gap)
str .= stepback
}
if (this.gap)
this.indent := stepback
return is_array ? "[" . str . "]" : "{" . str . "}"
}
} else
return ObjGetCapacity([value], 1)=="" ? value : this.Quote(value)
}
Quote(string)
{
static quot := Chr(34), bashq := "\" . quot
if (string != "") {
string := StrReplace(string,  "\",  "\\")
, string := StrReplace(string, quot, bashq)
, string := StrReplace(string, "`b",  "\b")
, string := StrReplace(string, "`f",  "\f")
, string := StrReplace(string, "`n",  "\n")
, string := StrReplace(string, "`r",  "\r")
, string := StrReplace(string, "`t",  "\t")
static rx_escapable := A_AhkVersion<"2" ? "O)[^\x20-\x7e]" : "[^\x20-\x7e]"
while RegExMatch(string, rx_escapable, m)
string := StrReplace(string, m.Value, Format("\u{1:04x}", Ord(m.Value)))
}
return quot . string . quot
}
}
Undefined[]
{
get {
static empty := {}, vt_empty := ComObject(0, &empty, 1)
return vt_empty
}
}
class Functor
{
__Call(method, ByRef arg, args*)
{
if IsObject(method)
return (new this).Call(method, arg, args*)
else if (method == "")
return (new this).Call(arg, args*)
}
}
}
Class JSONFile {
static Instances := []
__New(File) {
FileExist := FileExist(File)
JSONFile.Instances[this] := {File: File, Object: {}}
ObjRelease(&this)
FileObj := FileOpen(File, "rw")
if !IsObject(FileObj)
throw Exception("Can't access file for JSONFile instance: " File, -1)
if FileExist {
try
JSONFile.Instances[this].Object := JSON.Load(FileObj.Read())
catch e {
this.__Delete()
throw e
} if (JSONFile.Instances[this].Object = "")
JSONFile.Instances[this].Object := {}
} else
JSONFile.Instances[this].IsNew := true
return this
}
 
__Delete() {
if JSONFile.Instances.HasKey(this) {
ObjAddRef(&this)
JSONFile.Instances.Delete(this)
}
}
 
__Call(Func, Param*) {
if JSONFile.Instances[this].HasKey(Func)
return JSONFile.Instances[this][Func]
if (Func = "JSON")
return StrReplace(JSON.Dump(this.Object(),, Param.1 ? A_Tab : ""), "`n", "`r`n")
if (Func = "Save") {
try
New := this.JSON(Param.1)
catch e
return false
FileObj := FileOpen(this.File(), "w")
FileObj.Length := 0
FileObj.Write(New)
FileObj.__Handle
return true
}
if (Func = "Fill") {
if !IsObject(Param.2)
Param.2 := []
for Key, Val in Param.1 {
if (A_Index > 1)
Param.2.Pop()
HasKey := Param.2.MaxIndex()
? this.Object()[Param.2*].HasKey(Key)
: this.Object().HasKey(Key)
Param.2.Push(Key)
if IsObject(Val) && HasKey
this.Fill(Val, Param.2), Param.2.Pop()
else if !HasKey
this.Object()[Param.2*] := Val
} return
}
return Obj%Func%(this.Object(), Param*)
}
 
 
__Set(Key, Val) {
return this.Object()[Key] := Val
}
__Get(Key) {
return this.Object()[Key]
}
}
guiCount:=1
width:=30
height:=30
display := True
hoverColor := "Red"
points1:= []
points2:= []
points3:= []
points4:= []
init_points(points1,"Red")
init_points(points2,"Blue")
init_points(points3,"Green")
init_points(points4,"Teal")
SetTimer, hover, 1
return
 
 
Numpad1::
click_points(points1)
return
Numpad2::
click_points(points2)
return
Numpad3::
click_points(points3)
return
Numpad4::
click_points(points4)
return
 
 
^Numpad1::
hoverColor := "Red"
add_point(points1, "Red")
return
^Numpad2::
hoverColor := "Blue"
add_point(points2, "Blue")
return
^Numpad3::
hoverColor := "Green"
add_point(points3, "Green")
return
^Numpad4::
hoverColor := "Teal"
add_point(points4, "Teal")
return
 
 
!Numpad1::
clear_points(points1)
return
!Numpad2::
clear_points(points2)
return
!Numpad3::
clear_points(points3)
return
!Numpad4::
clear_points(points4)
return
 
F5::
display := !display
if (!display) {
    hide_gui()
} else {
    display_gui()
}
return
 
hover:
if (display) {
MouseGetPos, currx, curry
overlay_rect(currx, curry, width, height, 3, hoverColor, False)
}
return
 
init_points(ByRef points,color) {
global width, height, guiCount, js
tempPoints := []
For index, p In points
{
num := overlay_rect(p.currx, p.curry, width, height, 3, color, True)
tempPoints.push({"currx":p.currx,"curry":p.curry,"x1":p.x1,"y1":p.y1,"x2":p.x2,"y2":p.y2,"gui":p.num})
}
points := tempPoints
}
 
clear_points(ByRef points) {
For index, p In points
{
num := p.gui
Gui %num%: Destroy
}
points := []
}
 
add_point(ByRef points, color) {
global width, height, guiCount, js
if (points.MaxIndex() > 28) {
return
}
 
MouseGetPos, currx, curry
num := overlay_rect(currx, curry, width, height, 3, color)
x1 := currx - width/2
x2 := currx + width/2
y1 := curry - height/2
y2 := curry + height/2
points.push({"currx":currx,"curry":curry,"x1":x1,"y1":y1,"x2":x2,"y2":y2,"gui":num})
js.save()
}
 
click_points(ByRef points) {
MouseGetPos, currx, curry
For index, p In points
{
click_box(p.x1, p.y1, p.x2, p.y2)
Sleep, RandomDelay(40,60)
}
X1 := currx + Rand(10), Y1 := curry + Rand(10)
MouseMove(X1, Y1)
}
 
overlay_rect(X:=0, Y:=0, W:=0, H:=0, T:=3, cc:="Red", incr:=True) {
global guiCount
X -= W/2
Y -= H/2
w2:=W-T
h2:=H-T
txt := abs(mod(guiCount,99)+1)
Gui %txt%: +LastFound +AlwaysOnTop -Caption +ToolWindow +E0x08000000 +E0x80020
Gui %txt%: Color, %cc%
Gui %txt%: Show, w%W% h%H% x%X% y%Y% NA
WinSet, Transparent, 150
WinSet, Region, 0-0 %W%-0 %W%-%H% 0-%H% 0-0 %T%-%T% %w2%-%T% %w2%-%h2% %T%-%h2% %T%-%T%
if (incr) {
    guiCount += 1
    }
return txt
}
 
hide_gui() {
loop, 99 {
    Gui %A_Index%: Hide
    }
}
 
display_gui() {
loop, 99 {
    Gui %A_Index%: +LastFound +AlwaysOnTop -Caption +ToolWindow +E0x08000000 +E0x80020
    Gui %A_Index%: Show
    }
}
 
click_box(x1, y1, x2, y2) {
ToolTip
x += PilgrimMites(x1,x2)
y += PilgrimMites(y1,y2)
MouseMove(x,y)
Click()
}
 
MouseMove(xTarget, yTarget, ErrorThreshold := 5, MinRandomDelay := 6, MaxRandomDelay := 8, PreMoveDelayMin := 20, PreMoveDelayMax := 30) {
    Speed := PilgrimMites(.80,2.35)
    MouseGetPos, xCurrent, yCurrent
    xOffset := xTarget - xCurrent, yOffset := yTarget - yCurrent
    distance := Sqrt(xOffset * xOffset + yOffset * yOffset) / Speed
    xStep := xOffset / distance, yStep := yOffset / distance
    Loop, % distance {
        MouseMove, xCurrent += xStep, yCurrent += yStep, % RandomDelay(MinRandomDelay, MaxRandomDelay)
        MouseGetPos, xNew, yNew
        xError := xTarget - xNew, yError := yTarget - yNew
        if (Sqrt(xError * xError + yError * yError) < ErrorThreshold) {
            Sleep, 1
        }
    }
    Sleep, PilgrimMites(PreMoveDelayMin, PreMoveDelayMax)
}
 
Rand(range=30) {
    Random, r, -%range%, +%range%
    Return R
}
 
RandRange(min, max) {
    if (min > max) {
        MsgBox, RandRange %ErrorLevel%
        return -1
    }
    Random, rand, %min%, %max%
    return rand
}
 
RandomDelay(min, max) {
    return RandRange(min, max)
}
 
 
Click(Delay_Min:=35.0, Delay_Max:=60.0,SpamPrevent_Min:=35.0,SpamPrevent_Max:=60.0) {
DllCall("user32.dll\mouse_event", uint, 0x0002, int, 0, int, 0, uint, 0, int, 0)
 
    Sleep, PilgrimMites(Delay_Min, Delay_Max)
 
DllCall("user32.dll\mouse_event", uint, 0x0004, int, 0, int, 0, uint, 0, int, 0)
 
    Sleep, PilgrimMites(SpamPrevent_Min, SpamPrevent_Max)
 
return
}
 
PilgrimMites(M, H) {
Middle := ( M + H ) / 2
    Random, r1, 0, Middle - M, %A_Now% . %A_IsCritical% . %A_TickCount%
    Random, r2, 0, H - Middle, %A_Now% . %A_IsCritical% . %A_TickCount%
    Anchor := M + r1 + r2
    if (Anchor < M || Anchor > H) {
        MsgBox, 49, Anchor Error, % "Invalid anchor: " . Anchor . "`nRestarting`nPlease contact PilgrimMites if this message appears."
        Reload
    } else {
        Return Anchor
    }
}
 
 
RemoveToolTip:
ToolTip
return
 
F6::ExitApp

Скрипт поставляется "как есть". Для легитной игры на мейне — самое то, так как нет прямого вмешательства в память игры, всё работает через имитацию ввода. Но не забывайте про адекватные паузы, чтобы не словить репорт за 24/7 онлайн.

Кто уже гонял этот билд на жирных аккаунтах, как по детектам?
 
Назад
Сверху Снизу