Что нового

[Автоматизация] Пиратия Онлайн - Мой первый эксперемент в создании своего бота

Hracid

Новичок
Сообщения
8
Репутация
2
Задача бота: Уничтожение монстров. Сбор выпавшего с них лута.
Алгоритм работы:
1. Каст заклинания которое поражает цели на небольшом отдалении от персонажа.
2. Сбор выпавшего с них лута.
3. Регенерация манны
На каждое из выше описанных действий в игре существует определенный HotKey. Было решено создать программу которая бы поочередно имитировала нажатие этих клавиш, тем самым производя все эти действия.
Далее код. Он подробно комментирован. Думаю у новичков вопросов не возникнет.
За интерфейс спасибо создателям KODA
Код:
#cs
* мой первый "БОТ" 
#ce
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

HotKeySet('{F9}',  'StartBot')
HotKeySet('{F10}', 'PauseBot')

; начало описаня GUI
$fmMain = GUICreate("Пиратия 2 - Бот", 349, 235, -1, -1)
$Label1 = GUICtrlCreateLabel("Время респа монстра (сек):", 16, 24, 146, 17)
$edRespTime = GUICtrlCreateInput("30", 160, 17, 121, 21)
$Edit1 = GUICtrlCreateEdit("", 16, 48, 321, 177)
GUICtrlSetData(-1, StringFormat("Простой бот для игры Пиратия онлайн.\r\nПараметром время респа вы можете\r\nрегулировать время до перерождения монстров\r\nвокруг вас.\r\nДля запуска бота нажмите "&Chr(34)&"F9"&Chr(34)&".\r\nДля приостановки нажмите "&Chr(34)&"F10"&Chr(34)&".\r\nСкил для убийства монстров поместите на клавишу "&Chr(34)&"F8"&Chr(34)&"\r\nв самой игре.\r\nВНИМАНИЕ!!! Игра уже должна быть запущена, \r\nи до места дислокации монстров вам прийдеться\r\nдобираться самостоятельно!"))
GUICtrlSetState(-1, $GUI_DISABLE)
GUICtrlSetCursor (-1, 4)
GUISetState(@SW_SHOW)
; конец описаня GUI

; вызов бесконечного цикла для ожидания команд пользователя
PauseBot()

; запуск бота
Func StartBot()
Local $edText   ; время респа
$edText = GUICtrlRead($edRespTime) ; считываем время респа
$edText = $edText * 1000           ; множим на 1000 что бы перевести в милисекунды или как их там...
While 1
	Send('{INS}')   ;встать
	Sleep(500)      ;тупим пол секунды, даем перму оторвать жопу от земли
	Send('{F8}') 	;кастануть 
	Sleep(2000)   	;подождать прежде чем собрать все что нападало
	Send('^A')      ;собрать все что выпало
	Sleep(500)      ;тупануть еще пол секунды 
	Send('{INS}')   ;сесть
	Sleep($edText)  ;ждать респа
WEnd
EndFunc

; приостановка бота
Func PauseBot() ; переводим бота в режим ожидания
Local $Char
While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd
EndFunc

На самом деле я ничего нового не изобрел. Такие боты распространены в Пиратии Онлайн. Просто хотелось создать своего собственного. И может быть развить его в нечто больше и более удобно.
В данный момент озадачился возможностью посылки все этих же HotKey в свернутое окно Пиратии Онлайн. Пробую через ControlSend… Но что то не выходит с неактивным окном. А то так бы занимался своими делами, а «бот» тем временем добывал бы мне игровые богатства!
Жду каментов и исправлений. И по возможности подсказок :whistle: .
так же знаю что лучше использовать ControlSend для подобных дияний, но пока не разберусь как посылать HotKey в неактивное окно с этим можно подождать.
Модеру: моя первая тема на этом форуме, если что не так. Скинь в личку я поправлю.

Скриншот экрана бота:
 
Автор
H

Hracid

Новичок
Сообщения
8
Репутация
2
Добавил настроек в программу. переписал хелп.
Теперь есть возможность бить более сильных монстров, задавая количество кастов подряд и промежуток межу кастами, т.е. время регенерации заклинания.

Код:
#cs
* мой первый "БОТ" 
#ce
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

HotKeySet('{F9}',  'StartBot')
HotKeySet('{F10}', 'PauseBot')

; начало описаня GUI
$Form1 = GUICreate("Бот для пиратии", 352, 409, 327, 188)
$Group1 = GUICtrlCreateGroup("Настройки бота", 8, 8, 337, 97)
$Label1 = GUICtrlCreateLabel("Время респа(сек)", 16, 32, 94, 17)
$edRespTime = GUICtrlCreateInput("30", 166, 24, 121, 21)
$Label2 = GUICtrlCreateLabel("Количество кастов подряд", 16, 56, 140, 17)
$edCastCount = GUICtrlCreateInput("1", 166, 48, 121, 21)
$Label3 = GUICtrlCreateLabel("Таймаут между кастами(сек)", 16, 78, 153, 17)
$Input1 = GUICtrlCreateInput("6", 166, 72, 121, 21)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Group2 = GUICtrlCreateGroup("Инструкция", 8, 144, 337, 257)
$Edit1 = GUICtrlCreateEdit("", 16, 160, 321, 233)
GUICtrlSetData(-1, StringFormat("Простой бот для игры Пиратия онлайн.\r\nВремя респа - время необходимое для перерождения\r\nмонстра, в секундах.\r\nКоличество кастов подряд - если монстр не погибает от 1\r\nкаста вашего заклинания, а скажем от 2-3 и т.д.\r\nРегулируйте этот параметр. (по умолчанию "&Chr(34)&"1"&Chr(34)&")\r\nТаймаут между кастами - время перезарядки спела.\r\nF9   - старт бота\r\nF10 - остановка бота\r\nСпелу которым собераетесь крошить монстров\r\nназничить клавишу "&Chr(34)&"F8"&Chr(34)&" в игре.\r\nВНИМАНИЕ!!! Игра уже должна быть запущена.\r\nДо места дислокации монстров вам прийдеться\r\nдобираться самостоятельно."))
GUICtrlSetState(-1, $GUI_DISABLE)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Pic1 = GUICtrlCreatePic("C:\Program Files\AutoIt3\projects\Pause.gif", 8, 112, 100, 28)
$Pic2 = GUICtrlCreatePic("C:\Program Files\AutoIt3\projects\Work.gif", 8, 112, 100, 28)
GUICtrlSetState($Pic2, $GUI_HIDE)
GUISetState(@SW_SHOW)
; конец описаня GUI

; вызов бесконечного цикла для ожидания команд пользователя
PauseBot()

; запуск бота
Func StartBot()
Local $edText, $edCast, $edTimeOut  
Local $count 
GUICtrlSetState($Pic1, $GUI_HIDE)
GUICtrlSetState($Pic2, $GUI_SHOW)
$edText = GUICtrlRead($edRespTime)  ; считываем время респа
$edText = $edText * 1000            ; множим на 1000 что бы перевести в милисекунды или как их там...
$edCast = GUICtrlRead($edCastCount) ; считываем количество кастов
$edTimeOut = GUICtrlRead($Input1)   ; считываем количество кастов
$edTimeOut *= 1000 
While 1
	Send('{INS}')   ;встать
	Sleep(500)      ;тупим пол секунды, даем персу оторвать жопу от земли
	$count = 0
	do              ; кастив ровно то количество раз сколько указано в настройках
		$count += 1
		Send('{F8}') 	;кастануть 
		if $edCast = 1 or $edCast = $count then ; если каст всего 1 либо это последний каст, то сразу переходим к следующему шагу

		else
			Sleep($edTimeOut)
		endif
	until $count = $edCast
	Sleep(2000)   	;подождать прежде чем собрать все что нападало
	Send('^A')      ;собрать все что выпало
	Sleep(500)      ;тупануть еще пол секунды 
	Send('{INS}')   ;сесть
	Sleep($edText)  ;ждать респа
WEnd
EndFunc

; приостановка бота
Func PauseBot() ; переводим бота в режим ожидания
Local $Char
GUICtrlSetState($Pic1, $GUI_SHOW)
GUICtrlSetState($Pic2, $GUI_HIDE)
While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd
EndFunc


есть только пара вопросов:
1) пути к файлам картинок.. как сделать что бы картинки попадали в ресурсы скомпилированного exe файла? если удаляю картинки из папки уже после компеляции картинки из программы пропадают...
2) как послать нажатие клавиш неактивному окну?
 
Автор
H

Hracid

Новичок
Сообщения
8
Репутация
2
Появилось время и желание написать.
С нажатием клавиш в неактивном окне разобрался в тот же день. Бот работает и весьма успешно. По крайней мере бот за пол часа зарабатывает больше чем играющий племяш за час :smile:
Код:
#cs
* мой первый "БОТ" 
#ce
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

HotKeySet('{F9}',  'StartBot')
HotKeySet('{F10}', 'PauseBot')

; начало описаня GUI
$Form1 = GUICreate("Бот для пиратии", 352, 409, 327, 188)
$Group1 = GUICtrlCreateGroup("Настройки бота", 8, 8, 337, 97)
$Label1 = GUICtrlCreateLabel("Время респа(сек)", 16, 32, 94, 17)
$edRespTime = GUICtrlCreateInput("30", 166, 24, 121, 21)
$Label2 = GUICtrlCreateLabel("Количество кастов подряд", 16, 56, 140, 17)
$edCastCount = GUICtrlCreateInput("1", 166, 48, 121, 21)
$Label3 = GUICtrlCreateLabel("Таймаут между кастами(сек)", 16, 78, 153, 17)
$Input1 = GUICtrlCreateInput("6", 166, 72, 121, 21)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Group2 = GUICtrlCreateGroup("Инструкция", 8, 144, 337, 257)
$Edit1 = GUICtrlCreateEdit("", 16, 160, 321, 233)
GUICtrlSetData(-1, StringFormat("Простой бот для игры Пиратия онлайн.\r\nВремя респа - время необходимое для перерождения\r\nмонстра, в секундах.\r\nКоличество кастов подряд - если монстр не погибает от 1\r\nкаста вашего заклинания, а скажем от 2-3 и т.д.\r\nРегулируйте этот параметр. (по умолчанию "&Chr(34)&"1"&Chr(34)&")\r\nТаймаут между кастами - время перезарядки спела.\r\nF9   - старт бота\r\nF10 - остановка бота\r\nСпелу которым собераетесь крошить монстров\r\nназничить клавишу "&Chr(34)&"F8"&Chr(34)&" в игре.\r\nВНИМАНИЕ!!! Игра уже должна быть запущена.\r\nДо места дислокации монстров вам прийдеться\r\nдобираться самостоятельно."))
GUICtrlSetState(-1, $GUI_DISABLE)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Pic1 = GUICtrlCreatePic("C:\Program Files\AutoIt3\projects\Pause.gif", 8, 112, 100, 28)
$Pic2 = GUICtrlCreatePic("C:\Program Files\AutoIt3\projects\Work.gif", 8, 112, 100, 28)
GUICtrlSetState($Pic2, $GUI_HIDE)
GUISetState(@SW_SHOW)
; конец описаня GUI


; вызов бесконечного цикла для ожидания команд пользователя
PauseBot()

; запуск бота
Func StartBot()
	Local $edText, $edCast, $edTimeOut  
	Local $count 
	if WinExists('Пиратия II') then
		GUICtrlSetState($Pic1, $GUI_HIDE)
		GUICtrlSetState($Pic2, $GUI_SHOW)
		$edText = GUICtrlRead($edRespTime)  ; считываем время респа
		$edText = $edText * 1000            ; множим на 1000 что бы перевести в милисекунды или как их там...
		$edCast = GUICtrlRead($edCastCount) ; считываем количество кастов
		$edTimeOut = GUICtrlRead($Input1)   ; считываем количество кастов
		$edTimeOut *= 1000 
		$hWnd = WinGetHandle('Пиратия II') ; хендл окна игры
		While 1
			ControlSend($hWnd,'','','{INS}')   ;встать
			Sleep(500)      ;тупим пол секунды, даем персу оторвать жопу от земли
			$count = 0
			do              ; кастив ровно то количество раз сколько указано в настройках
				$count += 1
				ControlSend($hWnd,'','','{F8}') 	;кастануть 
				if $edCast = 1 or $edCast = $count then ; если каст всего 1 либо это последний каст, то сразу переходим к следующему шагу

				else
					Sleep($edTimeOut)
				endif
			until $count = $edCast
			Sleep(3000)   	;подождать прежде чем собрать все что нападало
			ControlSend($hWnd,'','','^A')      ;собрать все что выпало
			Sleep(500)      ;тупануть еще пол секунды 
			ControlSend($hWnd,'','','{INS}')   ;сесть
			Sleep($edText)  ;ждать респа
		WEnd
	Else
		MsgBox(48,'Ошибка','Игра не запущена. Запустите игру')
		PauseBot()
	EndIf
EndFunc

; приостановка бота
Func PauseBot() ; переводим бота в режим ожидания
Local $Char
GUICtrlSetState($Pic1, $GUI_SHOW)
GUICtrlSetState($Pic2, $GUI_HIDE)
While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd
EndFunc


есть только одна проблема в строке:
Код:
ControlSend($hWnd,'','','^A')      ;собрать все что выпало

Здесь сочетании клавиш Ctrl+A (собрать все что выпало) работает не всегда корректно. Иногда что-то переглючивает и выпавшие трофеи бот перестает собирать, а в место этого печатает в чат символ A. Как с этим разобраться пока не придумал. Если кто подскажет буду очень благодарен.
 

lirikmel

Продвинутый
Сообщения
225
Репутация
84
Здесь сочетании клавиш Ctrl+A (собрать все что выпало) работает не всегда корректно
ну как вариант попробуй ctrl предварительно нажимать

Код:
ControlSend($hWnd, "", "","{CTRLDOWN}")
sleep (100)
ControlSend($hWnd,'','','{a}')  
ControlSend($hWnd, "", "","{CTRLUP}")
 
Автор
H

Hracid

Новичок
Сообщения
8
Репутация
2
перебрал массу вариантов. от предложенного lirikmel, и еще своих несколько штук.
попробовал:
Код:
; 1й вариант
ControlSend($hWnd, "", "","{CTRLDOWN}")
sleep(100)
ControlSend($hWnd,'','','{a down}')  
sleep(100)
ControlSend($hWnd,'','','{a up}')  
ControlSend($hWnd, "", "","{CTRLUP}")  

; 2й вариант
ControlSend($hWnd, "", "","{CTRLDOWN}")
sleep(100)
ControlSend($hWnd,'','','{ASC 065}')  ; 065 ASCII код символа A
ControlSend($hWnd, "", "","{CTRLUP}")  

; 3й вариант
ControlSend($hWnd,'','','^{ASC 065}')

сразу скажу что предложенные выше варианты не работают совсем...

и лишь только:
Код:
Send('^A')

работает стабильно и безотказно, но окно игры должно быть активным. что лично мне не подходит, потому что бот создавался для заработка в игре в то время пока я зарабатываю на чай с плюшками в реале.

благо выход нашелся. если включить в игре автосбор ресурсов(Ctrl+Shift+A), все выпавшее будет собираться автоматически. этот функционал конечно не подойдет для движущегося бота, т.к. собирает он их с задержкой, а вот для нашего сидящего на месте более чем годен.

собственно я думаю из этого кликер-бота для пиратии выжать больше нечего... думаю на этом тему можно будет закрыть.
 

lirikmel

Продвинутый
Сообщения
225
Репутация
84
Код:
#include-once
Func ControlSendPlus($title, $text, $className, $string, $flag)
;VERSION 2.0.3 (06/13/2004)
Local $ctrl=0,$alt=0,$upper,$start,$end,$i,$char,$and,$Chr5Index,$isUpper,$ret
If $flag = 2 OR $flag = 3 Then $ctrl = 1
If $flag = 2 OR $flag = 4 Then $alt = 1
If $flag <> 1 Then $flag = 0;set the flag to the default function style
$upper = StringSplit('[email protected]#$%^&*()_+|{}:"<>?ABCDEFGHIJKLMNOPQRSTUVWXYZ', "")

If $flag <> 1 Then;don't replace special chars if it's raw mode
;replace {{} and {}} with +[ and +] so they will be displayed properly
  $string = StringReplace($string, "{{}", "+[")
  $string = StringReplace($string, "{}}", "+]")
;replace all special chars with Chr(5)
;add the special char to an array.  each Chr(5) corresponds with an element
  Local $Chr5[StringLen($string) / 2 + 1]
  For $i = 1 To StringLen($string)
    $start = StringInStr($string, "{")
    If $start = 0 Then ExitLoop;no more open braces, so no more special chars
    $end = StringInStr($string, "}")
    If $end = 0 Then ExitLoop;no more close braces, so no more special chars
;parse inside of braces:
    $Chr5[$i] = StringMid($string, $start, $end - $start + 1)
;replace with Chr(5) leaving the rest of the string:
    $string = StringMid($string, 1, $start - 1) & Chr(5) &_
     StringMid($string, $end + 1, StringLen($string))
  Next
;take out any "!", "^", or "+" characters
;add them to the $Modifiers array to be used durring key sending
  Local $Modifiers[StringLen($string) + 1]
  For $i = 1 To StringLen($string)
    $char = StringMid($string, $i, 1)
    $and = 0
    If $char = "+" Then
      $and = 1
    ElseIf $char = "^" Then
      $and = 2
    ElseIf $char = "!" Then
      $and = 4
    ElseIf $char = "" Then
      ExitLoop
    EndIf
    If $and <> 0 Then
      $Modifiers[$i] = BitOR($Modifiers[$i], $and)
      $string = StringMid($string, 1, $i - 1) &_
       StringMid($string, $i + 1, StringLen($string))
      $i = $i - 1
    EndIf
  Next
Else;it is raw mode, so set up an all-0 modifier array
  Local $Modifiers[StringLen($string) + 1]
EndIf

;now send the chars
$Chr5Index = 1
For $i = 1 To StringLen($string)
  $char = StringMid($string, $i, 1)
  If $char = Chr(5) Then
    $char = $Chr5[$Chr5Index]
    $Chr5Index = $Chr5Index + 1
  EndIf
  $isUpper = 0
  For $j = 1 To UBound($upper) - 1
    If $char == $upper[$j] Then $isUpper = 1
  Next
;1 SHIFT, 2 CTRL, 4 ALT (programmer note to keep the bits straight)
  If $isUpper = 1 OR BitAND($Modifiers[$i], 1) = 1 Then Send("{SHIFTDOWN}")
  If BitAND($Modifiers[$i], 4) = 4 AND NOT $alt Then $char = "!" & $char
  If BitAND($Modifiers[$i], 2) = 2 AND NOT $ctrl Then $char = "^" & $char
  If BitAND($Modifiers[$i], 4) = 4 AND $alt Then Send("{ALTDOWN}")
  If BitAND($Modifiers[$i], 2) = 2 AND $ctrl Then Send("{CTRLDOWN}")
  $ret = ControlSend($title, $text, $className, $char, $flag)
  If BitAND($Modifiers[$i], 4) = 4 AND $alt Then Send("{ALTUP}")
  If BitAND($Modifiers[$i], 2) = 2 AND $ctrl Then Send("{CTRLUP}")
  If $isUpper = 1 OR BitAND($Modifiers[$i], 1) = 1 Then Send("{SHIFTUP}")
  If NOT $ret Then return 0;window or control not found
Next
return 1
EndFunc
 
Автор
H

Hracid

Новичок
Сообщения
8
Репутация
2
поменя код для сбора лута на следующий:
Код:
;собрать все что выпало
Send("{CTRLDOWN}")             ;зажимаем Ctrl
ControlSend($hWnd,'','','A')      ;посылаем в окно символ А
Send("{CTRLUP}")                   ;отпускаем Ctrl

теперь все работает как надо!

lirikmel, спасибо! функция очень удобная. но целиком я её использовать не стал.
видимо моя проблема была в том что ControlSend как-то не корректно отрабатывает при передачи нажатия "Ctrl", а именно {CTRLDOWN} и {CTRLUP}.
 
Верх