Всем привет. Решил поделится тем что написал за время пока игра не надоела.
Особенность скрипта пожалуй в том что он открывает ресурсы только в пределах своей зоны чести, с распознанием уникальности ресурса(в плане были ли разведчики уже отправлены за ним). Из минусов пожалуй то что требуется активное окно игры и мышь(решается с помощью VMware)
Для правильной работы скрипта требуются деревни расставленные так чтобы зоны чести не пересекались, полностью прокачанные разведчики, в частности это будет влиять на следующие.
Скорость разведки высчитывается в скрипте строкой.
Далее важный параметр это кол-во деревень.
Задается глобальной переменной $cVillage = 3 (у меня было 3 деревни) и смена деревни обрабатывается функ. _set_village($v, $sleep = 4000)
где параметр $sleep зависит от расстояния которое камере придется преодолеть при смене деревни - его лучше не менять.
Для начала не меняйте кол-во деревень в коде если у вас их больше чем 3. Пусть код отработает, вы поймете как он выбирает след. деревню и тогда можете добавить в этот массив данные
Пожалуй самое важное я уже затронул. В остальном - отвечу на вопросы если будут.
На звание героя я не претендую, просто делюсь кодом что бы не лежал на свалке.
Архив с исходниками.
Особенность скрипта пожалуй в том что он открывает ресурсы только в пределах своей зоны чести, с распознанием уникальности ресурса(в плане были ли разведчики уже отправлены за ним). Из минусов пожалуй то что требуется активное окно игры и мышь(решается с помощью VMware)
Для правильной работы скрипта требуются деревни расставленные так чтобы зоны чести не пересекались, полностью прокачанные разведчики, в частности это будет влиять на следующие.
Скорость разведки высчитывается в скрипте строкой.
Код:
$aRet[$i - 1][3] = Floor(_GetDistance(396, 450, $x, $y) * $speed * 1000 + 61000)
; 396, 450 - центр выбранной деревни.
; $speed - был получен из Времени которое займет у разведчика что бы добраться до ресурса, деленное на расстояние в пикселях до ресурса от центра деревни.
; умножение на 1000 - переводим секунды в мсек
; прибавляем 61-у секунду, из которых тридцать(обязательных секунд) - есть время обновления карты игры а еще 31 это максимально возможная задержка(на всякий случай)
Далее важный параметр это кол-во деревень.
Задается глобальной переменной $cVillage = 3 (у меня было 3 деревни) и смена деревни обрабатывается функ. _set_village($v, $sleep = 4000)
где параметр $sleep зависит от расстояния которое камере придется преодолеть при смене деревни - его лучше не менять.
Для начала не меняйте кол-во деревень в коде если у вас их больше чем 3. Пусть код отработает, вы поймете как он выбирает след. деревню и тогда можете добавить в этот массив данные
Код:
$aVillage_Offset[3][2] = [[275, 85],[275, 102],[275, 118]]
Пожалуй самое важное я уже затронул. В остальном - отвечу на вопросы если будут.
На звание героя я не претендую, просто делюсь кодом что бы не лежал на свалке.
Архив с исходниками.
Код:
#RequireAdmin
;~ #include <IS.au3>
#include <GDIPlus.au3>
#include <Pop-ups.au3>
#include <ScreenCapture.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Array.au3>
#include <ListViewConstants.au3>
Opt("MustDeclareVars", 1)
Opt("GUIOnEventMode", 1)
Opt('TrayAutoPause', 0)
Opt('MouseClickDownDelay', 100)
If WinExists("iNelsy ^_^") Then Exit
#Region ### START Koda GUI section ### Form=
Global $WINDOW_MAIN = GUICreate("iNelsy ^_^", 288, 179, 319, 760)
GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
Global $hLIST_VIEW = GUICtrlCreateListView("X|Y|Dis|rTime|iTime|V", 8, 8, 254, 158)
Global $hLIST_VIEW_ITEM[0]
Global $hLABEL_COUNT = GUICtrlCreateLabel(0, 266, 12, 18, 17)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###
Global $SHK_Title = "Stronghold Kingdoms"
_GDIPlus_Startup()
Global $ImageDir = "Data\Image\"
Global $Log = 'Data\Log\log_' & @YEAR & '.' & @MON & '.' & @MDAY & '_' & @HOUR & '.' & @MIN & '.' & @SEC & '.html'
Global $ini = "Data\" & @ScriptName & ".ini"
Global $progres = False, $SBind = 0, $lag = 1.5
Global $STOP = True, $StartOrStop = False
Global $aSent, $cVillage = 3, $iCur_Vill = 1
;~ HotKeySet("{F10}", "Action")
HotKeySet("{PAUSE}", "StartOrStop")
HotKeySet("+{PAUSE}", "_Exit")
SetWindow()
While 1
Sleep(100 * $lag)
If $STOP = False Then Action()
WEnd
; размер окна 1000, 835
;~ 792,717 - размер карты, 396,450(верхняя часть окна 358+92) - середина карты; 704 - высота и ширина зоны чести, 362 радиус зоны чести
;~ найти формулу расстояния в оси координат
Func Action()
If $STOP = True Or $progres = True Then Return
$progres = True
Local $ret = 0, $x, $y, $sleep = 0, $i, $hImage, $aRes
Local $hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\Data\Image\fog.png')
Local $hPopup = _Popup_Register()
_set_village($iCur_Vill)
While 1
While 1
If $STOP = True Then ExitLoop
If Not _Popup_IsActive($hPopup) Then _Popup_Show($hPopup, _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage), 1, 396, 451, -1)
Sleep(1000)
_update_aSent()
_update_ListView()
$aRes = _find_all_res("unknown.png")
If IsArray($aRes) Then ExitLoop
$i = $i + 1
If $i > Floor(30 / $cVillage) Then
If $cVillage <> $iCur_Vill Then
$iCur_Vill = $iCur_Vill + 1
Else
$iCur_Vill = 1
EndIf
_Popup_Hide($hPopup, True)
_set_village($iCur_Vill)
$i = 0
EndIf
WEnd
If _Popup_IsActive($hPopup) Then _Popup_Hide($hPopup, True)
If $STOP = True Then
_GDIPlus_ImageDispose($hImage)
_Popup_Unregister($hPopup)
Return "STOP"
EndIf
_send_to_all($aRes)
_add_aRes_to_aSent($aRes)
WEnd
$progres = False
EndFunc ;==>Action
Func _set_village($v, $sleep = 4000)
Local $map_icon[2] = [558, 71], $select_village[2] = [616, 40], $aVillage_Offset[3][2] = [[275, 85],[275, 102],[275, 118]]
MouseClick("left", $map_icon[0], $map_icon[1], 1, 1)
MouseClick("left", $select_village[0], $select_village[1], 1, 1)
MouseClick("left", $aVillage_Offset[$v - 1][0], $aVillage_Offset[$v - 1][1], 1, 1)
Sleep($sleep)
MouseClick("left", 396, 450, 1, 1) ; mouse in center
MouseWheel("down", 1)
Return
EndFunc ;==>_set_village
Func _update_aSent()
If IsArray($aSent) Then
Local $i, $iS = UBound($aSent), $aDel[0]
For $i = 0 To $iS - 1
If TimerDiff($aSent[$i][4]) > $aSent[$i][3] Then
_ArrayAdd($aDel, $i)
EndIf
Next
If UBound($aDel) > 0 Then
For $i = 0 To UBound($aDel) - 1
_ArrayDelete($aSent, $aDel[$i])
Next
EndIf
EndIf
Return
EndFunc ;==>_update_aSent
Func _update_ListView()
If IsArray($aSent) Then
Local $i, $iS = UBound($aSent)
If UBound($hLIST_VIEW_ITEM) < $iS Then ReDim $hLIST_VIEW_ITEM[$iS]
If UBound($hLIST_VIEW_ITEM) > $iS Then
For $i = $iS To UBound($hLIST_VIEW_ITEM) - 1
GUICtrlDelete($hLIST_VIEW_ITEM[$i])
Next
ReDim $hLIST_VIEW_ITEM[$iS]
EndIf
For $i = 0 To $iS - 1
If $hLIST_VIEW_ITEM[$i] = "" Then
$hLIST_VIEW_ITEM[$i] = GUICtrlCreateListViewItem($aSent[$i][0] & "|" & $aSent[$i][1] & "|" & $aSent[$i][2] & "|" & _SW_TimeFormat($aSent[$i][3]) & "|" & _SW_TimeFormat(TimerDiff($aSent[$i][4])) & "|" & $aSent[$i][5], $hLIST_VIEW)
Else
GUICtrlSetData($hLIST_VIEW_ITEM[$i], $aSent[$i][0] & "|" & $aSent[$i][1] & "|" & $aSent[$i][2] & "|" & _SW_TimeFormat($aSent[$i][3]) & "|" & _SW_TimeFormat(TimerDiff($aSent[$i][4])) & "|" & $aSent[$i][5])
EndIf
Next
EndIf
Return
EndFunc ;==>_update_ListView
Func _find_all_res($res)
Local $speed = 1.556793642567159 ; сек уходит на преодоления одного пикселя
Local $x, $y, $ret = 0, $Left = 35, $Top = 92, $Right = 755, $Bottom = 809, $i = 1, $aRet[1][6], $Height, $Width
_get_HW($Height, $Width, $res)
While 1
$ret = _ImageSearchArea($ImageDir & $res, 0, $x, $y, 100, $Left, $Top, $Right, $Bottom)
If $ret = 0 And $i = 1 Then Return 0
If $ret = 0 And $i > 1 Then Return $aRet
If Not _check_exist(Floor($x + $Width / 2), Floor($y + $Height / 2)) Then
$x = Floor($x + $Width / 2)
$y = Floor($y + $Height / 2)
ReDim $aRet[$i][6]
$aRet[$i - 1][0] = $x
$aRet[$i - 1][1] = $y
$aRet[$i - 1][2] = _GetDistance(396, 450, $x, $y)
$aRet[$i - 1][3] = Floor(_GetDistance(396, 450, $x, $y) * $speed * 1000 + 61000)
$aRet[$i - 1][4] = 0
$aRet[$i - 1][5] = $iCur_Vill
$i = $i + 1
EndIf
$Top = $y + 1
WEnd
EndFunc ;==>_find_all_res
Func _get_HW(ByRef $Height, ByRef $Width, $res)
Local $hImage = _GDIPlus_ImageLoadFromFile($ImageDir & $res)
$Width = _GDIPlus_ImageGetWidth($hImage)
$Height = _GDIPlus_ImageGetHeight($hImage)
_GDIPlus_ImageDispose($hImage)
Return
EndFunc ;==>_get_HW
Func _check_exist($x, $y)
Local $ret, $i, $c = 50
If Not IsArray($aSent) Then Return False
For $i = 0 To UBound($aSent) - 1
If $aSent[$i][0] > $x - $c And $aSent[$i][0] < $x + $c And $aSent[$i][5] = $iCur_Vill Then
If $aSent[$i][1] > $y - $c And $aSent[$i][1] < $y + $c Then Return True
EndIf
Next
Return False
EndFunc ;==>_check_exist
Func _send_to_all(ByRef $aRes)
Local $i = 0, $c
For $i = 0 To UBound($aRes) - 1
WriteLog("X: " & $aRes[$i][0] & ", Y: " & $aRes[$i][1] & ", D: " & $aRes[$i][2] & ", T: " & _SW_TimeFormat($aRes[$i][3]) & ", V: " & $aRes[$i][5] & '
')
_send_scout($aRes[$i][0], $aRes[$i][1])
$aRes[$i][4] = TimerInit()
$c = GUICtrlRead($hLABEL_COUNT)
GUICtrlSetData($hLABEL_COUNT, $c + 1)
_set_village($iCur_Vill, 2000)
Next
Return
EndFunc ;==>_send_to_all
Func _send_scout($x, $y)
Local $sleep = 850
MouseClick("left", $x, $y, 1, 0) ; click res icon for set camera
Sleep($sleep)
MouseClick("left", 395, 449, 1, 0) ; click resource icon in center of the map
Sleep($sleep)
MouseClick("left", 896, 178, 1, 0) ; click icon send scout
Sleep($sleep)
WriteLog("Send Scouts moment.
")
Opt("MouseClickDownDelay", 30)
MouseClick("left", 120, 606, 2, 0) ; select quantity
Opt("MouseClickDownDelay", 100)
Sleep($sleep)
MouseClick("left", 631, 590, 1, 0) ; click confirm send
Sleep($sleep)
Return
EndFunc ;==>_send_scout
Func _add_aRes_to_aSent($aRes)
If IsArray($aSent) Then
Local $i = 0, $iR = 0, $iS = UBound($aSent)
ReDim $aSent[$iS + UBound($aRes)][6]
For $i = $iS To UBound($aSent) - 1
$aSent[$i][0] = $aRes[$iR][0]
$aSent[$i][1] = $aRes[$iR][1]
$aSent[$i][2] = $aRes[$iR][2]
$aSent[$i][3] = $aRes[$iR][3]
$aSent[$i][4] = $aRes[$iR][4]
$aSent[$i][5] = $aRes[$iR][5]
$iR = $iR + 1
Next
Else
$aSent = $aRes
EndIf
Return
EndFunc ;==>_add_aRes_to_aSent
Func _GetDistance($x1, $y1, $x2, $y2) ; функция расчета дистанции от персанажа до нпц/моба
Local $dis = Round(Sqrt(($x1 - $x2) ^ 2 + ($y1 - $y2) ^ 2), 1) ; формула получения дистанции из кординат цели и персанажа
Return $dis ; возвращаем дистанцию
EndFunc ;==>_GetDistance
Func _SW_TimeFormat($iTime)
Local $Count, $Time[3]
If IsString($iTime) Then
$Time = StringSplit(StringReplace(StringRegExpReplace($iTime, '[^:.0-9]', ''), '.', ':'), ':', 2)
If Not IsArray($Time) Then
Return '00:00.00'
EndIf
$Count = UBound($Time)
If $Count < 3 Then
ReDim $Time[3]
EndIf
For $i = 0 To 2
$Time[$i] = Number($Time[$i])
Switch $i
Case 0, 1
If $Time[$i] > 59 Then
$Time[$i] = 0
EndIf
Case Else
If $Time[$i] > 99 Then
$Time[$i] = 0
EndIf
EndSwitch
Next
Else
$Time[2] = Mod($iTime, 1000)
$iTime = ($iTime - $Time[2]) / 1000
$Time[1] = Mod($iTime, 60)
$Time[0] = ($iTime - $Time[1]) / 60
$Time[2] = Floor($Time[2] / 10)
EndIf
Return StringFormat('%02s:%02s.%02s', $Time[0], $Time[1], $Time[2])
EndFunc ;==>_SW_TimeFormat
Func WriteLog($text)
Local $date = StringTrimLeft(@YEAR, 2) & "." & @MON & "." & @MDAY & "_" & @HOUR & "." & @MIN & "." & @SEC
_ScreenCapture_Capture('Data\Log\Image\' & $date & '.jpg')
FileWrite($Log, '<a href="Image\' & $date & '.jpg">' & $date & '</a>' & " => " & $text)
Return
EndFunc ;==>WriteLog
Func StartOrStop()
If $StartOrStop = True Then Return
$StartOrStop = True
If $STOP = True Then
$STOP = False
Else
$STOP = True
$progres = False
EndIf
$StartOrStop = False
Return
EndFunc ;==>StartOrStop
Func _Exit()
HotKeySet("{F9}")
HotKeySet("{F10}")
HotKeySet("{PAUSE}")
HotKeySet("+{PAUSE}")
Sleep(1000)
_GDIPlus_Shutdown()
Exit
EndFunc ;==>_Exit
Func _ImageSearch($findImage, $resultPosition, ByRef $x, ByRef $y, $tolerance, $hwnd = 0)
Return _ImageSearchArea($findImage, $resultPosition, $x, $y, $tolerance, 0, 0, @DesktopWidth, @DesktopHeight, $hwnd)
EndFunc ;==>_ImageSearch
Func _ImageSearchArea($findImage, $resultPosition, ByRef $x, ByRef $y, $tolerance, $Left = 0, $Top = 0, $Right = @DesktopWidth, $Bottom = @DesktopHeight, $hwnd = 0)
;MsgBox(0,"asd","" & $left & " " & $top & " " & $right & " " & $bottom)
If $tolerance > 0 Then $findImage = "*" & $tolerance & " " & $findImage
Local $result = DllCall("Data\UDF\IS.dll", "str", "ImageSearch", "int", $Left, "int", $Top, "int", $Right, "int", $Bottom, "str", $findImage)
; If error exit
If $result[0] = "0" Then Return 0
; Otherwise get the x,y location of the match and the size of the image to
; compute the centre of search
Dim $array = StringSplit($result[0], "|")
$x = Int(Number($array[2]))
$y = Int(Number($array[3]))
If $resultPosition = 1 Then
$x = $x + Int(Number($array[4]) / 2)
$y = $y + Int(Number($array[5]) / 2)
EndIf
If $hwnd <> 0 Then
Local $wpos = _WinGetClientPos($hwnd)
$x = $x - $wpos[0]
$y = $y - $wpos[1]
EndIf
Return 1
EndFunc ;==>_ImageSearchArea
Func _WaitForImageSearch($findImage, $waitSecs, $resultPosition, ByRef $x, ByRef $y, $tolerance = 100, $Left = 0, $Top = 0, $Right = @DesktopWidth, $Bottom = @DesktopHeight, $hwnd = 0)
$waitSecs = $waitSecs * 1000
Local $startTime = TimerInit()
While TimerDiff($startTime) < $waitSecs
Sleep(100)
Local $result = _ImageSearchArea($findImage, $resultPosition, $x, $y, $tolerance, $Left, $Top, $Right, $Bottom, $hwnd)
If $result > 0 Then
Return 1
EndIf
WEnd
Return 0
EndFunc ;==>_WaitForImageSearch
Func _WinGetClientPos($hwnd)
Local $Size = WinGetClientSize($hwnd)
If Not IsArray($Size) Then
Return SetError(1, 0, 0)
EndIf
Local $tPOINT = DllStructCreate($tagPOINT)
For $i = 1 To 2
DllStructSetData($tPOINT, $i, 0)
Next
_WinAPI_ClientToScreen($hwnd, $tPOINT)
If @error Then
Return SetError(1, 0, 0)
EndIf
Local $pos[4]
For $i = 0 To 1
$pos[$i] = DllStructGetData($tPOINT, $i + 1)
Next
For $i = 2 To 3
$pos[$i] = $Size[$i - 2]
Next
Return $pos
EndFunc ;==>_WinGetClientPos
Func SetWindow()
Local $aPos, $aClientSize, $Win_Border[3]
$aClientSize = WinGetClientSize($SHK_Title)
$aPos = WinGetPos($SHK_Title)
$Win_Border[1] = ($aPos[2] - $aClientSize[0]) / 2
$Win_Border[2] = $aPos[3] - $aClientSize[1] - $Win_Border[1]
WinMove($SHK_Title, "", "-" & $Win_Border[1], "-" & $Win_Border[2], 1000, 835)
Return 'ok'
EndFunc ;==>SetWindow