<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Серый форум &mdash; AHK: Скрипт для хелперов. Автоматические ответы на вопросы игроков.]]></title>
		<link>https://forum.script-coding.com/viewtopic.php?id=17911</link>
		<atom:link href="https://forum.script-coding.com/extern.php?action=feed&amp;tid=17911&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «AHK: Скрипт для хелперов. Автоматические ответы на вопросы игроков.».]]></description>
		<lastBuildDate>Sat, 12 Aug 2023 15:10:09 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Re: AHK: Скрипт для хелперов. Автоматические ответы на вопросы игроков.]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=158996#p158996</link>
			<description><![CDATA[<p>Ну у вас флудит ибо вы вечно получаете одни и те же строки на последующих итерациях.<br />Подумайте, как бы вы могли это обойти.</p>]]></description>
			<author><![CDATA[null@example.com (Phoenixxx_Czar)]]></author>
			<pubDate>Sat, 12 Aug 2023 15:10:09 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=158996#p158996</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: Скрипт для хелперов. Автоматические ответы на вопросы игроков.]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=158989#p158989</link>
			<description><![CDATA[<p>Есть прогресс. Подключил бд, но теперь скрипт постоянно флудит окном. Подскажите, что я делаю не так? <br />Постоянно выполняется 22 строчка кода. Пока что решил проблему через перезапуск скрипта (строкой Reload после MsgBox), но это решение явно не очень.<br /></p><div class="codebox"><pre><code>if(RegExMatch(msg1, key))</code></pre></div><p><span class="postimg"><img src="https://i.imgur.com/9rNslgs.png" alt="https://i.imgur.com/9rNslgs.png" /></span>/</p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header" data-lang-open="открыть спойлер" data-lang-close="скрыть спойлер"><strong>+</strong>&nbsp;открыть спойлер</div><div class="fancy_spoiler"><div class="codebox"><pre><code>#SingleInstance force ; Означает, что старый экземпляр скрипта будет замещён новым автоматически
#Persistent ; Делает скрипт постоянно выполняющимся
#Include tf.ahk ; Используется одна ф-я из библиотеки. Возможно вырежу ее от туда и вставлю внутрь своего скрипта.
; Запись расположений файлов в переменные
chatlog := &quot;D:\MultiMc\instances\1.20.1\.minecraft\logs\latest.log&quot;
database := &quot;C:\mine ahk\dbase.txt&quot;

; ВРЕМЕННАЯ ФУНКЦИЯ. Ее нужно вырезать, должны подгружаться ключевые слова и ответы из доп. файла.

f1::

fileread, read, % TF_Tail(chatlog, 2) ; Читает последнюю строку из чат-лога игры, записывает это в переменную lastline
lastline:= % TF_Tail(chatlog, 2) 
regExDict := Object()
initRegExepDict()
global regExDict
for key, value in regexdict 
{
    if RegExMatch(lastline, &quot;.*&gt;&gt;&gt;(.*)&quot;, msg) ; С помощью регулярных выражений отсекается лишняя информация, остается только сообщение игрока
    {
		for key in regExDict
                if(RegExMatch(msg1, key))
                {
                    Msgbox, % regExDict[key]
					break    
                }
    }
}
return

NumpadAdd::
Reload

initRegExepDict()
{
	global regExDict
	global database
	
	Loop, read, % database
		if(RegExMatch(A_LoopReadLine, &quot;^\s*(.+?)\s*:\s*(.+)\s*$&quot;, msg))
        {
            msg1 := RegExReplace(msg1, &quot;А|а&quot;, &quot;[Аа]&quot;)
			msg1 := RegExReplace(msg1, &quot;Б|б&quot;, &quot;[Бб]&quot;)
			msg1 := RegExReplace(msg1, &quot;В|в&quot;, &quot;[Вв]&quot;)
			msg1 := RegExReplace(msg1, &quot;Г|г&quot;, &quot;[Гг]&quot;)
			msg1 := RegExReplace(msg1, &quot;Д|д&quot;, &quot;[Дд]&quot;)
			msg1 := RegExReplace(msg1, &quot;Е|е&quot;, &quot;[Ее]&quot;)
			msg1 := RegExReplace(msg1, &quot;Ё|ё&quot;, &quot;[Ёё]&quot;)
			msg1 := RegExReplace(msg1, &quot;Ж|ж&quot;, &quot;[Жж]&quot;)
			msg1 := RegExReplace(msg1, &quot;З|з&quot;, &quot;[Зз]&quot;)
			msg1 := RegExReplace(msg1, &quot;И|и&quot;, &quot;[Ии]&quot;)
			msg1 := RegExReplace(msg1, &quot;Й|й&quot;, &quot;[Йй]&quot;)
			msg1 := RegExReplace(msg1, &quot;К|к&quot;, &quot;[Кк]&quot;)
			msg1 := RegExReplace(msg1, &quot;Л|л&quot;, &quot;[Лл]&quot;)
			msg1 := RegExReplace(msg1, &quot;М|м&quot;, &quot;[Мм]&quot;)
			msg1 := RegExReplace(msg1, &quot;Н|н&quot;, &quot;[Нн]&quot;)
			msg1 := RegExReplace(msg1, &quot;О|о&quot;, &quot;[Оо]&quot;)
			msg1 := RegExReplace(msg1, &quot;П|п&quot;, &quot;[Пп]&quot;)
			msg1 := RegExReplace(msg1, &quot;Р|р&quot;, &quot;[Рр]&quot;)
			msg1 := RegExReplace(msg1, &quot;С|с&quot;, &quot;[Сс]&quot;)
			msg1 := RegExReplace(msg1, &quot;Т|т&quot;, &quot;[Тт]&quot;)
			msg1 := RegExReplace(msg1, &quot;У|у&quot;, &quot;[Уу]&quot;)
			msg1 := RegExReplace(msg1, &quot;Ф|ф&quot;, &quot;[Фф]&quot;)
			msg1 := RegExReplace(msg1, &quot;Ц|ц&quot;, &quot;[Цц]&quot;)
			msg1 := RegExReplace(msg1, &quot;Ч|ч&quot;, &quot;[Чч]&quot;)
			msg1 := RegExReplace(msg1, &quot;Ш|ш&quot;, &quot;[Шш]&quot;)
			msg1 := RegExReplace(msg1, &quot;Щ|щ&quot;, &quot;[Щщ]&quot;)
			msg1 := RegExReplace(msg1, &quot;Ъ|ъ&quot;, &quot;[Ъъ]&quot;)
			msg1 := RegExReplace(msg1, &quot;Ы|ы&quot;, &quot;[Ыы]&quot;)
			msg1 := RegExReplace(msg1, &quot;Ь|ь&quot;, &quot;[Ьь]&quot;)
			msg1 := RegExReplace(msg1, &quot;Э|э&quot;, &quot;[Ээ]&quot;)
			msg1 := RegExReplace(msg1, &quot;Ю|ю&quot;, &quot;[Юю]&quot;)
			msg1 := RegExReplace(msg1, &quot;Я|я&quot;, &quot;[Яя]&quot;)
			regExDict[msg1] := msg2
        }
        
    if(!regExDict.Count())
        MsgBox, 48, Ошибка инициализации, Ошибка инициализации:`nФайл %database% не заполнен по форме/не найден
}</code></pre></div></div></div>]]></description>
			<author><![CDATA[null@example.com (zerguddd)]]></author>
			<pubDate>Sat, 12 Aug 2023 12:54:48 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=158989#p158989</guid>
		</item>
		<item>
			<title><![CDATA[AHK: Скрипт для хелперов. Автоматические ответы на вопросы игроков.]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=158982#p158982</link>
			<description><![CDATA[<p>Доброго времени. Имею AHK скрипт для GTA SAMP, со следующим функционалом:<br />Постоянно проверяет чат, если в чат пришел вопрос, он это видит, с помощью регулярных выражений отрезает лишнее, имея заданный игроком вопрос, обращается в отдельный файл, и ищет по ключевым словам ответ на этот вопрос. Помимо этого, есть возможность отключить автоматический ответ. Все вопросы игроков логируются в отдельный текстовый документ (это необходимо для пополнения базы данных ключевых слов вопросов и ответов), логируются так-же все действия скрипта с указанием нынешних параметров его работы. Скрипт так же проверяет, свернута-ли игра, а так-же изменяет регистр вопросов, чтобы он реагировал на вопрос &quot;как&quot;, &quot;КАК&quot;, &quot;КаК&quot;.<br />Прикладываю код, а так-же скриншоты, как выглядят файлы логирования и база данных ключевых слов и ответов. <em>(обратится к автору нет возможности, его оставленный контакт уже невалидный)</em></p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header"><strong>+</strong>&nbsp;Код скрипта</div><div class="fancy_spoiler"><div class="codebox"><pre><code>#SingleInstance force
#Persistent
#IfWinActive GTA:SA:MP
#Include UDFR18.ahk

SetBatchLines -1
ListLines Off

initFile := &quot;database&quot;

; Частота проверки чата на новый вопрос
SetTimer, myTimer, 500

; Инициализация объекта, хранящего пары типа {&quot;регулярное выражение&quot; : &quot;Ответ&quot;}
regExDict := Object()
initRegExepDict()

; Флаг автоотправки ответа (жмет Enter при ответе, или нет)
IniRead, autoSendEnabled, % A_Temp &quot;/aafa.ini&quot;, main, autoSendEnabled, % false


; оффсет памяти введенного в чат текста
chatInputoffsetsarr := [0x12D8F8, 0x12D8F8, 0x17FBB8]

~Enter::
while(isInChat())
	Sleep 1
writelog(&quot;Нажат Enter&quot;)
chatInput := readString(hGTA, dwSAMP + chatInputoffsetsarr[sampVersion], 256)
; парсим введенный в чат текст
if(RegExMatch(chatInput, &quot;^[\./](?P&lt;Command&gt;[^\s]+)\s+(?P&lt;Args&gt;.*?)\s*$&quot;, cmd))
{
    if(cmdCommand == &quot;autosend&quot;)
    {
        if(cmdArgs)
        {
            autoSendEnabled := true
            addChatMessage(&quot;[AHK-SFH] AUTOSEND = 1 (Автоотправка включена)&quot;)
            
            IniWrite, % autoSendEnabled, % A_Temp &quot;/aafa.ini&quot;, main, autoSendEnabled
        }
        else
        {
            autoSendEnabled := false
            addChatMessage(&quot;[AHK-SFH] AUTOSEND = 0 (Автоотправка выключена)&quot;)
            
            IniWrite, % autoSendEnabled, % A_Temp &quot;/aafa.ini&quot;, main, autoSendEnabled
        }
    }
}
return

writelog(ByRef str)
{
    FileAppend, % &quot;`n[&quot; A_Hour &quot;:&quot; A_Min &quot;:&quot; A_Sec &quot;] &quot; str, aafa_dbg.txt
}

myTimer()
{
    global regExDict
    global autoSendEnabled
    
    static lastAfkStatus
    
    if(lastAfkStatus != IsInAFK())
    {
        lastAfkStatus := IsInAFK()
        writelog(&quot;IsInAFK(): &quot; lastAfkStatus)
    }
    
    for k, v in getNewChatLines()
        if(regexmatch(v, &quot;^Вопрос от \S+?\[(\d+)\]: (.+)&quot;, parsedStr))
        {
            writelog(&quot;Пришел вопрос: &quot; v)
            writelog(&quot;autoSendEnabled=&quot; autoSendEnabled &quot; | isInChat()=&quot; isInChat())
            
            FileAppend, % parsedStr2 &quot;`n&quot;, % &quot;logfile.txt&quot;
            if(!autoSendEnabled)
            {
				KeyWait, NumpadAdd, D
				SendMessage, 0x50,, 0x4190419,, A
				sendInput, % &quot;{F6}/an &quot; parsedStr1 A_Space
            }
            
            for key in regExDict
                if(RegExMatch(parsedStr2, key))
                {
                    if(!autoSendEnabled)
                    {
                        SendInput, % regExDict[key]
                    }
                    else
                    {
                        addChatMessage(&quot;/an &quot; parsedStr1 &quot; &quot; regExDict[key])
                        ;~ sendChat(&quot;/an &quot; parsedStr1 &quot; &quot; regExDict[key])
                    }
                        
                }
        }
}

initRegExepDict()
{
	global regExDict
	global initFile
	
	Loop, read, % initFile
		if(RegExMatch(A_LoopReadLine, &quot;^\s*(.+?)\s*:\s*(.+)\s*$&quot;, parsedStr))
        {
            parsedStr1 := RegExReplace(parsedStr1, &quot;А|а&quot;, &quot;а&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Б|б&quot;, &quot;б&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;В|в&quot;, &quot;в&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Г|г&quot;, &quot;г&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Д|д&quot;, &quot;д&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Е|е&quot;, &quot;е&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Ё|ё&quot;, &quot;ё&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Ж|ж&quot;, &quot;ж&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;З|з&quot;, &quot;з&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;И|и&quot;, &quot;и&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Й|й&quot;, &quot;й&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;К|к&quot;, &quot;к&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Л|л&quot;, &quot;л&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;М|м&quot;, &quot;м&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Н|н&quot;, &quot;н&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;О|о&quot;, &quot;о&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;П|п&quot;, &quot;п&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Р|р&quot;, &quot;р&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;С|с&quot;, &quot;с&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Т|т&quot;, &quot;т&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;У|у&quot;, &quot;у&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Ф|ф&quot;, &quot;ф&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Ц|ц&quot;, &quot;ц&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Ч|ч&quot;, &quot;ч&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Ш|ш&quot;, &quot;ш&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Щ|щ&quot;, &quot;щ&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Ъ|ъ&quot;, &quot;ъ&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Ы|ы&quot;, &quot;ы&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Ь|ь&quot;, &quot;ь&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Э|э&quot;, &quot;э&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Ю|ю&quot;, &quot;ю&quot;)
			parsedStr1 := RegExReplace(parsedStr1, &quot;Я|я&quot;, &quot;я&quot;)
			regExDict[parsedStr1] := parsedStr2
        }
        
    if(!regExDict.Count())
        MsgBox, 48, Ошибка инициализации, Ошибка инициализации:`nФайл %initFile% не заполнен по форме/не найден
}

IsInAFK() {
    res := ProcessReadMemory(0xBA6748 + 0x5C, &quot;gta_sa.exe&quot;)
    if (res==-1)
        return -1
    WinGet, win, MinMax, GTA:SA:MP
    if ((res=0) and (win=-1)) or res=1
        return 1
    return 0
}
ProcessReadMemory(address, processIDorName, type := &quot;Int&quot;, numBytes := 4) {
    VarSetCapacity(buf, numBytes, 0)
    Process Exist, %processIDorName%
    if !processID := ErrorLevel
        return -1
        ;throw Exception(&quot;Invalid process name or process ID:`n`n&quot;&quot;&quot; . processIDorName . &quot;&quot;&quot;&quot;)
    if !processHandle := DllCall(&quot;OpenProcess&quot;, &quot;Int&quot;, 24, &quot;UInt&quot;, 0, &quot;UInt&quot;, processID, &quot;Ptr&quot;)
        throw Exception(&quot;Failed to open process.`n`nError code:`t&quot; . A_LastError)
    result := DllCall(&quot;ReadProcessMemory&quot;, &quot;Ptr&quot;, processHandle, &quot;Ptr&quot;, address, &quot;Ptr&quot;, &amp;buf, &quot;Ptr&quot;, numBytes, &quot;PtrP&quot;, numBytesRead, &quot;UInt&quot;)
    if !DllCall(&quot;CloseHandle&quot;, &quot;Ptr&quot;, processHandle, &quot;UInt&quot;) &amp;&amp; !result
        throw Exception(&quot;Failed to close process handle.`n`nError code:`t&quot; . A_LastError)
    if !result
        throw Exception(&quot;Failed to read process memory.`n`nError code:`t&quot; . A_LastError)
    if !numBytesRead
        throw Exception(&quot;Read 0 bytes from the`n`nprocess:`t&quot; . processIDorName . &quot;`naddress:`t&quot; . address)
    return (type = &quot;Str&quot;)
        ? StrGet(&amp;buf, numBytes)
        : NumGet(buf, type)
}

getNewChatLines()
{
    static prevChatLine
    static prevTimeStamp

    if(!checkHandles())
        return
    dwAddress :=    readDWORD(hGTA, dwSAMP + ADDR_SAMP_CHATMSG_PTR[sampVersion]) 
    if ErrorLevel
        return

    chat := []

    curChatLine :=    readString(hGTA, dwAddress + 0x62C6, 0xFC)
    curTimeStamp :=    readMem(hGTA, dwAddress + 0x62A6, 4, &quot;int&quot;)
    if(curTimeStamp != prevTimeStamp || curChatLine != prevChatLine)
    {
        if(prevTimeStamp != &quot;&quot;)
            Loop 100
            {
                chatLine :=        readString(hGTA, dwAddress + 0x152 + (100 - A_Index) * 0xFC, 0xFC)
                timestamp :=    readMem(hGTA, dwAddress + 0x132 + (100 - A_Index) * 0xFC, 4, &quot;int&quot;)
                if(timestamp &lt; prevTimeStamp || timestamp == prevTimeStamp &amp;&amp; chatLine == prevChatLine)
                    break
                else
                {
                    chat.push(chatLine)
                    writelog(&quot;getNewChatLines(): timestamp=&quot; timestamp &quot; | line=&quot; chatLine)
                }
            }
      
        prevChatLine :=        curChatLine
        prevTimeStamp :=    curTimeStamp
    }
    return chat
}

:?*:reload::
reload

comment = Автор скрипта - vk.com/arsh1234</code></pre></div></div></div><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header"><strong>+</strong>&nbsp;Скриншоты логов, бд</div><div class="fancy_spoiler"><p> <br />Каждая новая строка - ответ на новый вопрос. В качестве разделителя ключевых слов и ответов служит двоеточие &quot;:&quot;.<br /><span class="postimg"><img src="https://i.imgur.com/j8x3MBd.png" alt="https://i.imgur.com/j8x3MBd.png" /></span></p><p>Логирование вопросов без лишней информации.<br /><span class="postimg"><img src="https://i.imgur.com/CiSK6EZ.png" alt="https://i.imgur.com/CiSK6EZ.png" /></span></p><p>Тут сложновато разобрать, в виду того, что, видимо я на другой сервер подключался со включенным скриптом, и сообщения с другого сервера подтянулись в эти логи.<br /><span class="postimg"><img src="https://i.imgur.com/mIih4fQ.png" alt="https://i.imgur.com/mIih4fQ.png" /></span></p></div></div><br /><p>Сейчас у меня ситуация следующая: хочу перенести небольшую часть фукнционала скрипта в другую игру, в майнкрафт. <br />А именно, я хочу перекинуть из первого кода тот функционал, который меняет регистр сообщения, а затем обращается к файлу и достает от туда ответ. Только в этом мне нужна ваша помощь. <em>А с логированием всех вопросов игроков в отдельный документ я сделаю сам, думаю там все крайне легко будет.</em><br />Так-же хочу оставить работу скрипта только по кнопке, автоматизация тут не имеет большого смысла.<br />Сейчас я имею следующий код:</p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header"><strong>+</strong>&nbsp;Нынешний код</div><div class="fancy_spoiler"><div class="codebox"><pre><code>
#SingleInstance force ; Означает, что старый экземпляр скрипта будет замещён новым автоматически
#Persistent ; Делает скрипт постоянно выполняющимся
#Include tf.ahk ; Используется одна ф-я из библиотеки. Возможно вырежу ее от туда и вставлю внутрь своего скрипта
; Запись расположений файлов в переменные
chatlog := &quot;D:\MultiMc\instances\1.20.1\.minecraft\logs\latest.log&quot;
database := &quot;C:\mine ahk\dbase.txt&quot;

; ВРЕМЕННАЯ ФУНКЦИЯ. Ее нужно вырезать, должны подгружаться ключевые слова и ответы из доп. файла
RegExDict := {&quot;привет.*&quot;: &quot;привет&quot;, &quot;как дела.*&quot;: &quot;нормис&quot;} 

f1:: 
fileread, read, % TF_Tail(chatlog, 2) ; Читает последнюю строку из чат-лога игры, записывает это в переменную lastline
lastline:= % TF_Tail(chatlog, 2) 
RegExMatch(lastline, &quot;.*&gt;&gt;&gt;(.*)&quot;, msg) ; С помощью регулярных выражений отсекается лишняя информация, остается только сообщение игрока
for key, value in RegExDict 
{
    if (RegExMatch(msg1, key))
    {
		MsgBox, %value% ; До реализации скрипта, временное решение. По факту готовности переделаю, чтобы вместо окна с результатом, результат сам писался в чат.
    }
}

return

NumpadAdd::
Reload
</code></pre></div></div></div><p>9 строка, разумеется, временно находится там, и меня это не устраивает в виду неудобства добавления большого количества ключевых слов и ответов.</p>]]></description>
			<author><![CDATA[null@example.com (zerguddd)]]></author>
			<pubDate>Sat, 12 Aug 2023 10:44:48 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=158982#p158982</guid>
		</item>
	</channel>
</rss>
