Что нового

[Stronghold Kingdoms] Разведка ресурсов. Готовый бот

Nelsy

Знающий
Сообщения
35
Репутация
8
Всем привет. Решил поделится тем что написал за время пока игра не надоела.
Особенность скрипта пожалуй в том что он открывает ресурсы только в пределах своей зоны чести, с распознанием уникальности ресурса(в плане были ли разведчики уже отправлены за ним). Из минусов пожалуй то что требуется активное окно игры и мышь(решается с помощью 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
 
Верх