You are not logged in.
спасибо, по твоей ссылке нашёл как сделать собственные читы))
а вот на форуме ничего не нашёл, только такие же вопросы) если не сложно, всё таки напиши каким образом сделать автонажатие!
http://sannybuilder.com/forums/viewtopi … 8370#p8370
Alien там дальше писал
0ab0 - это совсем другое. Клавиши из опкода 00E1. Если нужны конкретные кнопки клавиатуры, то надо воспользоваться мэйновским способом "Проверка нажатия клавиш". Только вместо чтения памяти запись.
но у меня не получается что-либо сделать таким способом.
Last edited by Sergey81 (11-10-2010 16:25)
Offline
Вопрос: какая часть вышеописанного кода ответственна за сам сейв, а какая - за детектирование фейла миссии? Если я правильно понял, то "0AA5: call 0x619060 num_params 1 pop 0 6" - это сэйв, а каую роль играет :lbl?
Здесь при срабатывании опкода 00BA, записываются в переменные координаты актора. Чтобы они не записывались когда вылезает надпись "Миссия провалена", проверяем счётчик миссий(21@ == 20@).
И с-но else используется чтоб задетектить именно "не начало" миссии, там делаем сейв и проверяем нажатость клавиши для телепорта.
Last edited by Sergey81 (11-10-2010 16:26)
Offline
Понятно, а лэйбл с hex зачем?
Also known as HemiG
It's cool to Hate. It's cool to be a bloody guitarist.
Offline
Понятно, а лэйбл с hex зачем?
Такой способ предложил Seemann - http://sannybuilder.com/forums/viewtopi … 532#p12532
Offline
Кажется понял. Но уточню: если я захочу сдетектировать провал миссии, то этот лэйбл нужен или проверки кол-ва начатых и выполненных миссий в статистике будет достаточно?
Last edited by BullDogHEMI427 (11-10-2010 19:42)
Also known as HemiG
It's cool to Hate. It's cool to be a bloody guitarist.
Offline
Кажется понял. Но уточню: если я захочу сдетектировать провал миссии, то этот лэйбл нужен или проверки кол-ва начатых и выполненных миссий в статистике будет достаточно?
Ну такой код точно не нужен, Alien уже приводил пример: http://sannybuilder.com/forums/viewtopi … 598#p12598
Offline
Offline
Перехватывать 00BA, на мой взгляд, ошибочный способ. Начнем с того, что он используется повсеместно и не только при запуске миссии. Во-вторых, он не позволяет определить какая миссия будет запущена.
Я бы предложил перехват 0417 как наиболее надежного маркера запуска миссии. Но при этом возникает проблема - этот опкод сразу создает новый поток на базе кода миссии. При сохранении данные этого потока будут сохранены в сейв и впоследствии извлечены оттуда при загрузке. Но самого кода миссии после загрузки естественно в памяти не будет - отсюда и вылет.
Решение, которое я бы предложил:
1. Перехватывать опкод 0417, но не исполнять его (только прочитать параметр опкода и узнать какая миссия готовится к запуску).
2. Установить флаг сохранения в нашем скрипте по аналогии с автосейвом (переход из 0417 в асм и назад, но не на код опкода, а на конец --см п.1).
3. Виртуально выполнить опкод wait 0, чтобы игра по разу выполнила все скрипты в очереди ожидания, в т.ч. наш клео скрипт с кодом сохранения
4. После сохранения скрипт должен запустить нужную миссию. Два способа:
а) напрямую выполнить тот же код, который используется в опкоде 0417
б) просто запустить опкод 0417 с нужным номером миссии. При этом возникает зацикленность исполнения кода: перехватчик 0417 опять приведет нас в асм, опять будет выполнен опкод wait 0 и т.д. Поэтому необходимо ввести дополнительный флаг, который будет указывать коду асма о необходимой операции -- либо мы ничего не делаем и запускаем скрипты в очереди (п 2-3) либо мы выполняем опкод далее.
Получается примерно такая схема: скрипт приходит на опкод 0417. его адрес изменен и игра попадает в асм внутри скрипта. первоначально флаг установлен так, что асм только устанавливает флаг сохранения и выходит из кода опкода (миссия не стартует). После этого игра еще раз запускает все скрипты. Проверка флага сохранения в коде скрипта сбратывает, и происходит автосохранение. После этого устанавливается флаг опкода 0417 для асма в режим выполнения. Скрипт сам запускает миссию (0417: 3@). Перехватчик 0417 приводит нас опять в асм, но флаг уже другой, поэтому мы сразу переходим назад на код запуска миссии.
Примерно такая схема.
Offline
@Seemann - 00BA остался из за того, что мне было лень после тестов других опкодов переделывать на какой-либо другой
п.1 - а как собственно прочитать параметр опкода? Глобальный адрес опкода + какое-то смещение?
п.2 - Что то вроде
MOV DWORD PTR DS:[00000000], 1 MOV EAX, 0@ JMP EAX
?
п.3 - совсем не понял, каким образом такое делается?
+ в мейне же код такой:
:DESERT_320 00D6: if 0038: $Toreno_Total_Passed_Missions == 3 004D: jump_if_false @DESERT_372 0004: $ONMISSION = 1 00BA: show_text_styled GXT 'DESERT4' time 1000 style 2 // Verdant Meadows 0050: gosub @sub_CJ_goto_Toreno_House 0417: start_mission 78 // Verdant Meadows
т.е. перед start_mission 78 флаг $ONMISSION уже стоит 1, не получится ли снова сохранение в миссии?
PS. И посты наверно лучше перенести в тему обсуждения.
Offline
а как собственно прочитать параметр опкода? Глобальный адрес опкода + какое-то смещение?
Параметры опкодов обычно записываются по адресу _opcodeParameters (0x0A43C78) + смещение. Смещения можно узнать, посмотрев конкретный опкод в IDA.
Last edited by Den_spb (11-10-2010 23:38)
Offline
1. в памяти игры по фиксированному адресу (как подсказывает Ден это 0x0A43C78) есть массив из 32 DWORD. В первом хранится первый параметр опкода, по смещению +4 (0xA43C7C) - второй параметр и т.д.
Но это для случая, когда опкод уже прочитал параметры из SCM. В нашем случае мы переходим в асм еще до этого момента, поэтому нужно прочитать параметр самим.
Задачу облегчает тот факт, что в оригинальном SCM в опкоде 0417 используется только один вид параметра - короткое однобайтовое целое число. Его тип = 04 (тыц). Прочитать номер миссии через асм можно по адресу памяти равному текущей позиции скрипта + 1 (т.е. пропускаем data type).
Текущая позиция скрипта хранится в структуре потока по смещению 0x14. Адрес структуры текущего потока (когда мы попадаем в асм, текущим скриптом будет считаться поток-триггер с опкодом 0417, а не вызываемая миссия или сам клео-скрипт) хранится в регистре esi. Т.е. чтобы узнать текущую позицию скрипта надо к значению esi прибавить 0x14 и прочитать 4 байта по полученному адресу.
В scm опкод 0417 выглядит так: 17 04 04 05. Первые 2 байта опкод, потом тип данных, потом сам параметр (в примере 5). Так запускается 5 миссия. В момент перехода на асм, скрипт находится в позиции перед вторым 04 (т.к. сам опкод уже прочитан). Нас тип данных не интересует, поэтому пропускаем его, прибавив 1. Остается только прочитать один байт по полученному адресу и опять же через асм записать его в нужную переменную нашего клео-скрипта (также как мы записываем флаг сохранения в 1@).
Но в указанном способе есть один недостаток. В измененных main.scm и прочих скриптах типа Mission Loader номер миссии может передаваться в опкод через переменную. Тогда описанный способ работать не будет. Для решения проблемы можно вручную вызывать опкод чтения параметра (getOpcodeParam). Но в этом случае текущая позиция скрипта будет сдвинута к следующему опкоду. Впрочем это будет даже полезно, потому что по условиям задачи мы должны полностью пропустить опкод 0417, чтобы вызвать его потом вручную после того как сработает wait 0 и произойдет автосохранение.
Ввиду вышеуказанного, предлагаю первой же строчкой асм кода вызвать процедуру чтения параметра опкода. Как это делается, можно посмотреть в коде 0417 в IDA. Сам асм можно даже скопировать оттуда. После этого из адреса 0x0A43C78 можно прочитать номер миссии и скопировать его в локальную переменную.
2. Код будет такой же как сейчас
C705 00000000 01000000 // MOV DWORD PTR DS:[00000000], 1 B8 A79A4800 // MOV EAX, 00489AA7 FFE0 // JMP EAX
3. Скопируй сюда полностью код опкода 0001 и посмотрим как его можно вызвать самому. Насколько
я помню, там в структуру потока записывается время для ожидания и опкод возвращает в скриптовый обработчик единицу (mov al, 1). Обычные опкоды возвращают 0 (xor al, al). Единица в eax после выхода с опкода означает прерывание обработки опкодов и выполнение других игровых функций.
зы. вот что бывает, когда под рукой нет IDA, сани и санника хДД Иначе, я просто давно бы уже сам написал код и выложил его.
Last edited by Seemann (13-10-2010 00:41)
Offline
Offline
http://i10.fastpic.ru/thumb/2010/1013/4 … 4e44a.jpeg
Я правильно понимаю что процедура чтения параметра опкода начинается с .text:00489938 ? А асм копировать с вкладки Hex View? Data-формат использовать дефолтный или другой надо выставить?
тебе нужно реализовать код
push 1 // читаем один параметр mov ecx, esi // записываем адрес потока в регистр класса (поскольку вызываем не просто функцию, а метод) mov eax, xxxxx // тут прописываем адрес функции getNumberParams call eax
hex-код команд можно поискать тут
http://sannybuilder.com/dev/cleo.txt
вот вроде так:
6A 01 // push 1 8B CE // mov ecx, esi B8 80 40 46 00 // mov eax, 00464080 FF D0 //call eax 8B 05 78 3C A4 00 // mov eax, param1 A3 00 00 00 00 // MOV DWORD PTR DS:[00000000], eax
собственно нужно только чтобы клео-скрипт прописал в последнюю строчку адрес нужной локальной переменной (например, 2@). И мы получим, что асм читает параметр опкода 0417 и записывает его в переменную 2@. Потом после автосохранения в скрипте можно вызывать 0417: 2@
На твоем скрине опкод 0417 не весь, не видно на каком адресе он заканчивается.
Собственно поясню, чего мы хотим добиться . Нам нужно чтобы в зависимости от определенного флага (назовем его флаг выполнения опкода 0417), который будет все также храниться в локальной переменной скрипта, как и флаг сохранения, описанный и реализованный в текущей версии скрипта, опкод 0417 либо не работал, либо работал полностью. В первом случае мы добиваемся того, что делаем сохранение ПРИ ЕЩЕ НЕ ЗАПУЩЕННОЙ МИССИИ (поскольку опкод 0417 фактически является пустышкой, как на этом скрине). Мы вручную читаем параметр опкода, запоминаем его и используем впоследствии. Во-втором случае, мы ничего не делаем с опкодом, игра запускает миссию.
В простейшем виде код будет выглядеть так:
КЛЕО ЦИКЛ ЕСЛИ ФЛАГ_СОХРАНЕНИЯ = 1 ТО ДЕЛАЕМ_АВТОСОХРАНЕНИЕ ФЛАГ_СОХРАНЕНИЯ = 0 ФЛАГ_0417 = 1 0417: 2@ КОНЕЦ_ЕСЛИ КОНЕЦ_ЦИКЛА КОНЕЦ_КЛЕО АСМ ЕСЛИ ФЛАГ_0417 = 0 TO ЧИТАЕМ ПАРАМЕТР ОПКОДА ФЛАГ_СОХРАНЕНИЯ = 1 ВЫПОЛНЯЕМ ОПКОД WAIT 0 ПЕРЕХОДИМ НА КОНЕЦ ОПКОДА 0417 // 00489AA7 ИНАЧЕ ФЛАГ_0417 = 0 ПЕРЕХОДИМ НА НАЧАЛО ОПКОДА 0417 КОНЕЦ_ЕСЛИ КОНЕЦ_АСМА
Last edited by Seemann (13-10-2010 00:40)
Offline
http://pastebin.com/RyarJezE
0417 из иды.
.text:00465E90 ; __linkproc__ opcode_0001 .text:00465E90 @@opcode_0001: ; DATA XREF: .text:00466C54o .text:00465E90 028 push 1 ; wait %1d% ms .text:00465E92 02C mov ecx, esi .text:00465E94 02C call CScriptThread__getNumberParams .text:00465E99 028 mov eax, _opcodeParameters .text:00465E9E 028 mov ecx, _currentTime ; millisecond resolution .text:00465EA4 028 add ecx, eax .text:00465EA6 028 pop edi .text:00465EA7 024 mov [esi+CScriptThread.wakeTime], ecx .text:00465EAD 024 mov al, 1 .text:00465EAF 024 pop esi .text:00465EB0 020 mov ecx, [esp+20h+var_C] .text:00465EB4 020 mov large fs:0, ecx .text:00465EBB 020 add esp, 20h .text:00465EBE 000 retn 4
0001.
Получается весь этот код придётся исполнять внутри перехватчика 0417, который уже реализован для сейва после миссии?
Offline
Зачем весь?
.text:00465E90 ; __linkproc__ opcode_0001 .text:00465E90 @@opcode_0001: ; DATA XREF: .text:00466C54o .text:00465E90 028 push 1 ; wait %1d% ms .text:00465E92 02C mov ecx, esi .text:00465E94 02C call CScriptThread__getNumberParams
это чтение параметра. мы его и так знаем - 0
.text:00465E99 028 mov eax, _opcodeParameters .text:00465E9E 028 mov ecx, _currentTime ; millisecond resolution .text:00465EA4 028 add ecx, eax
к текущему времени прибавляется wait. будем считать результат равен _currentTime
.text:00465EA6 028 pop edi
насчет этой команды не уверен для чего она тут. нужно сравнить с опкодом 0002
.text:00465EA7 024 mov [esi+CScriptThread.wakeTime], ecx
в структуру опкода записывается время, когда проснуться. поскольку нас принципиально не интересует задержка для следующего срабатывания скрипта, можно этот момент опустить.
.text:00465EAD 024 mov al, 1
самая важная часть. прерывание обработки опкодов
.text:00465EAF 024 pop esi .text:00465EB0 020 mov ecx, [esp+20h+var_C] .text:00465EB4 020 mov large fs:0, ecx .text:00465EBB 020 add esp, 20h .text:00465EBE 000 retn 4
выход из опкода. код одинаков для всех последующих опкодов (0002, 0003...)
Поэтому для эмуляции wait 0 достаточно команды mov al, 1
Впрочем eax мы используем для команды перехода на конец опкода
B8 A79A4800 // MOV EAX, 00489AA7 FFE0 // JMP EAX
поэтому нужно для перехода использовать другой регистр (edx), либо посмотреть чему равен al после перехода (возможно что mov al, 1 и не понадобится). eax и al это по сути один регистр
Last edited by Seemann (13-10-2010 01:27)
Offline
Не, я имел в виду первоначально то что нужно сделать?
Вот допустим у нас есть скрипт автосейва, там мы меняем адреса с <непомню что там сейчас используется> на адреса 0417. Потом в то место, где собственно происходит сам сейв вставляем код сейва перед миссией?
Что-то я уже путаться начинаю, надо пойти выспаться.
Offline
шаблон всего скрипта приведен в сообщении 63
http://sannybuilder.com/forums/viewtopi … 806#p12806
Offline
шаблон всего скрипта приведен в сообщении 63
http://sannybuilder.com/forums/viewtopi … 806#p12806
Так я туда и смотрю, в обычном виде это что-то вроде этого будет?:
{$CLEO} while true //ЦИКЛ if // ЕСЛИ 0@ == 1 // ФЛАГ_СОХРАНЕНИЯ = 1 then// ТО 0AA5: call 0x619060 num_params 1 pop 0 7 // ДЕЛАЕМ_АВТОСОХРАНЕНИЕ 0@ = 0 // ФЛАГ_СОХРАНЕНИЯ = 0 1@ = 1 // ФЛАГ_0417 = 1 0417: 2@ end // КОНЕЦ_ЕСЛИ end //КОНЕЦ_ЦИКЛА hex //АСМ ЕСЛИ ФЛАГ_0417 = 0 TO ЧИТАЕМ ПАРАМЕТР ОПКОДА ФЛАГ_СОХРАНЕНИЯ = 1 ВЫПОЛНЯЕМ ОПКОД WAIT 0 ПЕРЕХОДИМ НА КОНЕЦ ОПКОДА 0417 // 00489AA7 ИНАЧЕ ФЛАГ_0417 = 0 ПЕРЕХОДИМ НА НАЧАЛО ОПКОДА 0417 КОНЕЦ_ЕСЛИ end //КОНЕЦ_АСМА
А где та часть, в которой перехватывается опкод 0417 и не исполняется до выполнения сейва?
Last edited by Sergey81 (13-10-2010 16:47)
Offline
Ну в начале клео скрипта должен стоять код, в котором будет заменяться переход на опкод 0417 на адрес асма (так же как в действующем скрипте). Тогда каждый вызов 0417 в main.scm будет приводить нас внутрь асма. Все остальное управляется асмом. Куски кода асма уже полностью готовы и выложены выше, нужно только собрать все воедино.
Offline
0A9F: 0@ = current_thread_pointer 0A8E: 10@ = 0@ + 0x10 0A8D: 10@ = read_memory 10@ size 4 virtual_protect 0 0A8F: 11@ = 10@ - @lbl 0A8C: write_memory 0x00469E2C size 4 value 11@ virtual_protect 1
469E2C - ссылка на 0417. И всё равно как записать ту часть кода, которая у тебя идёт между //АСМ и //КОНЕЦ_АСМА мне непонятно.
Offline
Примерно так:
// проверяем флаг_0417 (переменную 1@) MOV EAX, DWORD PTR DS:[1@] TEST EAX, EAX JNZ @START_MISSION // если 1@ = 0 то пропускаем запуск миссии //читаем параметр 0417 вручную PUSH 1 // 6A 01 MOV ECX, ESI // 8B CE MOV EAX, 00464080 // B8 80 40 46 00 CALL EAX // FF D0 // записываем его в 2@ MOV EAX, param1 // 8B 05 78 3C A4 00 MOV DWORD PTR DS:[2@], eax // A3 00 00 00 00 // устанавливаем флаг сохранения 0@ в 1 MOV DWORD PTR DS:[0@], 1 // C705 00000000 01000000 // выполняем WAIT 0 MOV AL, 1 //выходим из опкода MOV EDX, 00489AA9 // пропускам xor al, al JMP EDX // если флаг_0417 равен 1 то исполняем опкод как обычно :START_MISSION // сбрасываем флаг_0417 для следующего перехвата MOV DWORD PTR DS:[1@], 0 // переходим на начало опкода 0417 MOV EDX, 00489921 JMP EDX
Там где стоят DWORD PTR нужно подставлять четыре нуля 00 00 00 00 и прописыватьь реальный адрес соответствующей переменной при инициализации клео-скрипта.
Last edited by Seemann (13-10-2010 23:52)
Offline
Фиг знает, то или не то я делаю, но вобщем вот что вышло(переменные не сверял, они как попало идут):
{$CLEO} 0A9F: 25@ = current_thread_pointer 0A8E: 26@ = 25@ + 0x10 0A8D: 26@ = read_memory 10@ size 4 virtual_protect 0 0A8F: 27@ = 26@ - @ASM 0A8C: write_memory 0x0048A244 size 4 value 27@ virtual_protect 1 while true //ЦИКЛ if // ЕСЛИ 0@ == 1 // ФЛАГ_СОХРАНЕНИЯ = 1 then// ТО 0AA5: call 0x619060 num_params 1 pop 0 7 // ДЕЛАЕМ_АВТОСОХРАНЕНИЕ 0@ = 0 // ФЛАГ_СОХРАНЕНИЯ = 0 1@ = 1 // ФЛАГ_0417 = 1 0417: 2@ end // КОНЕЦ_ЕСЛИ end //КОНЕЦ_ЦИКЛА :ASM hex // проверяем флаг_0417 (переменную 1@) C705 ???????? 01000000 //MOV EAX, DWORD PTR DS:[1@] 85 C0 //TEST EAX, EAX 74 @START_MISSION //JNZ @START_MISSION ?? // если 1@ = 0 то пропускаем запуск миссии //читаем параметр 0417 вручную 6A 01 //PUSH 1 8B CE //MOV ECX, ESI B8 80 40 46 00 //MOV EAX, 00464080 FF D0 // CALL EAX // записываем его в 2@ 8B 05 78 3C A4 00 //MOV EAX, param1 A3 00 00 00 00 //MOV DWORD PTR DS:[2@], eax // устанавливаем флаг сохранения 0@ в 1 C705 00000000 01000000 //MOV DWORD PTR DS:[0@], 1 // выполняем WAIT 0 8A 00 01 //MOV AL, 1 ?? //выходим из опкода BA A9 9A 48 00 //MOV EDX, 00489AA9 // пропускам xor al, al ?? FF E2 //JMP EDX end // если флаг_0417 равен 1 то исполняем опкод как обычно :START_MISSION hex // сбрасываем флаг_0417 для следующего перехвата A3 00 00 00 00 //MOV DWORD PTR DS:[1@], 0 // переходим на начало опкода 0417 BA 21 99 48 00 //MOV EDX, 00489921 FF E2 //JMP EDX end
Last edited by Sergey81 (14-10-2010 00:47)
Offline
Апну темку что ли) Может кто-то поможет дописать код...
Offline
Кстати да, куда все профи то пропали?
Тут ещё одна проблема вырисовалась, в обычном автосейве идёт проверка выполненных миссий, т.е. если после конца их стало +1, миссия пройдена, сохраняемся. Так вот она срабатывает только 1 раз, если пройти одну миссию, за ней взять другую и провалить, в момент провала игра сохранится. Что там не так то? По всей видимости надо 20@ = integer_stat 147 объявлять при ONMISSION == 1, или не сработает?
Offline
А не проще ли вызывать функцию сохранения в коде асма.
Offline