Перейти к содержанию

Работа с игровыми таймерами.


Рекомендуемые сообщения

Выполнял этот запрос -  Assassin’s Creed Chronicles: India и решил написать заодно небольшую статейку для новичков.

Статья будет короткой, пояснения внутри скриптов, работа скриптов показана на видео.

Поиск самих значений таймера в этой статье не рассматривается. По поискам значений есть много статей и видео.

Варианты решения задачи с таймером (какой вариант использовать и где, решать Вам).

1. Заморозка таймера.

1.1. С помощь опкода NOP

пример скрипт "Timer Mission Freeze v. Nop":

Скрытый текст

[ENABLE]
aobscan(aob_timer,xx89xxxxxxxxc2xxxxxxxxxxxxxxxxxxxxxxxxxx8bxxxx85xx74xx8bxxxxxxxxxx8bxxffxxxxxxxxxx85)
registersymbol(aob_timer)
aob_timer:
db 90          // NOP

[DISABLE]
aob_timer:
db 40          // inc eax
unregistersymbol(aob_timer)

// Т.е. при активации вместо инструкции inc eax ничего не делаем

 

1.2.* С помощью опкода  DEC

пример скрипт "Timer Mission Freeze v. dec " 

Скрытый текст

[ENABLE]
aobscan(aob_timer,xx89xxxxxxxxc2xxxxxxxxxxxxxxxxxxxxxxxxxx8bxxxx85xx74xx8bxxxxxxxxxx8bxxffxxxxxxxxxx85)
alloc(newmem_timer,2048)
label(returnhere_timer)
registersymbol(aob_timer)

newmem_timer:

inc eax               // игровая инструкция - увеличения таймера на 1
dec eax               // инструкция нашей инъекции - ументшение таймера на 1
mov [ecx+08],eax
pop esi
jmp returnhere_timer

aob_timer:
jmp newmem_timer
returnhere_timer:

[DISABLE]
aob_timer:
db 40 89 41 08 5E

unregistersymbol(aob_timer)
dealloc(newmem_timer)

 

2. Обнуление таймера при достижении определённого значения

пример скрипт "Timer Mission v. Adding a limit to the timer":

Скрытый текст

[ENABLE]
aobscan(aob_TimerMission,xx89xxxxxxxxc2xxxxxxxxxxxxxxxxxxxxxxxxxx8bxxxx85xx74xx8bxxxxxxxxxx8bxxffxxxxxxxxxx85)
alloc(newmem_TimerMission,2048)
label(returnhere_TimerMission)
label(timer1)      // timer1 добавлен в скрипт и в таблицу для большей
                   // наглядности, в самом чите он не нужен.
registersymbol(timer1)
label(timer2)      // В данном случае timer2 - это значение, после которого
                   // игровой таймер будет обнулён. Вводиться
                   // вручную в таблице.
registersymbol(timer2)
registersymbol(aob_TimerMission)

newmem_TimerMission:
inc eax
mov [timer1],eax   // Записываем в timer1 значение игрового таймера.
cmp [timer2],0     // Сравниваем значение в timer2 c 0
je @f              // Если 0, то никакого изменения в игровом коде,
                   // прыгаем на метку @@.
                   // Если не 0, то
cmp [timer2],eax   // Сравниваем значение игрового таймера (eax) cо значением
                   // в timer2.
jne @f             // Если неравно, то никакого изменения в игровом коде,
                   // прыгаем на метку @@.
                   // Если равно, то
push 0             // выгружаем в стек 0
pop eax            // выгружаем из стека 0 в eax. ем самым обнуляя таймер.

@@:                // Оригинальные игровые инструкции.
mov [ecx+08],eax
pop esi
jmp returnhere_TimerMission

timer1:
dd 0
timer2:
dd 0

aob_TimerMission:
jmp newmem_TimerMission
returnhere_TimerMission:

[DISABLE]
aob_TimerMission:
db 40 89 41 08 5E

unregistersymbol(timer1)
unregistersymbol(timer2)
unregistersymbol(aob_TimerMission)
dealloc(newmem_TimerMission)

 

3. Замедление таймера

3.1. Вариант с добавлением дополнительного внутрискриптового таймера:

пример скрипт "Timer Mission v. timer slowdown v. Adding a timer inside the script":

Скрытый текст

[ENABLE]
aobscan(aob_TimerMission,xx89xxxxxxxxc2xxxxxxxxxxxxxxxxxxxxxxxxxx8bxxxx85xx74xx8bxxxxxxxxxx8bxxffxxxxxxxxxx85)
alloc(newmem_TimerMission,2048)
label(returnhere_TimerMission)
label(code)
label(timer1)             // timer1 добавлен в скрипт и в таблицу для большей
                          // наглядности, в самом чите он не нужен.
registersymbol(timer1)
label(timer2)             // timer2 внутрискриптовый таймер в таблицу для
                          // большей наглядности, в самом чите в таблице
                          // он не нужен.
registersymbol(timer2)
label(Coefficient)        // Coefficient - нужен и в таблице и в скрипте. Это
                          // во сколько раз нужно замедлить таймер. Вводиться
                          // вручную в таблице.
registersymbol(Coefficient)
registersymbol(aob_TimerMission)

newmem_TimerMission:
push ebx                  // Сохраняем регистр ebx перед использованием.
mov ebx,[Coefficient]     // Загружаем в него значение в Coefficient
cmp ebx,[timer2]          // Сравниваем это значение со значением в timer2.
pop ebx                   // Восстанавливаем регистр ebx.
je @f                     // Если значения равны, то прыгаем на метку @@.
                          // Если не равны, то
inc [timer2]              // увеличиваем внутрискриптовый таймер на 1.
jmp code                  // и прыгаем на метку code.

@@:
mov [timer2],1            // Записываем в timer2 1, для того, чтобы он заново
                          // начинал считать.
inc eax                   // Увеличиваем на 1 игровой таймер.

code:
mov dword ptr [timer1],eax // Записываем в timer1 значение игрового таймера.
mov [ecx+08],eax           // Далее идут Оригинальные игровые инструкции.
pop esi
jmp returnhere_TimerMission

timer1:
dd 0
timer2:
dd 1
Coefficient:
dd 1

aob_TimerMission:
jmp newmem_TimerMission
returnhere_TimerMission:

[DISABLE]
aob_TimerMission: // 016674EC
db 40 89 41 08 5E

unregistersymbol(timer1)
unregistersymbol(timer2)
unregistersymbol(Coefficient)
unregistersymbol(aob_TimerMission)
dealloc(newmem_TimerMission)

 

 

* - вариант скрипта может приводить в некоторых играх к вылету, в конце в видео я это показал. В этом случае нужно выяснять из-за чего происходит вылет (для данной игры я не делал этого). Но что-то подобное происходило у меня при написании скрипта на патроны для Fallout 3 и там я решил проблемы с вылетами и объяснил почему происходил вылет, если появиться желание можете почитать в той теме - 

Видео:

 

 

Ну и сама табличка со скриптами и уже назначенными адресами:

PS: Табличку выложил ниже.

Изменено пользователем Garik66
  • Плюс 8
Ссылка на комментарий
Поделиться на другие сайты

Продолжим.

Скрипт 3.1. имеет ограничение - мы можем замедлить таймер только в 2 раза, в 3, в 4 и т.д.

Т.е. можем использовать только целые (Integer) числа.

А что, если пользователю нужно замедлить таймер в полтора  раза, в 2.5, в 8,5 и т.д. В этом случае скрипт 3.1. нам не поможет, придётся  переписать его. 

В работе с нецелыми ;) числами (дробными, вещественными, числами с плавающей точкой - короче FLOAT) нам поможет математический сопроцессор, т.е. FPU.

Для изучения вопроса наберите например работа с вещественными числами в поисковике. Лично мне понравилась вот эта статья

Скрытый текст

часто к ней обращаюсь, если пишу что-нибудь для дробных чисел.

Как разберётесь не много, то уже задавайте более конкретный вопрос поисковику - например ассемблер fadd.

Выложу написанный скрипт, как всегда, для понимания - что он делает, прочтите комментарии внутри скрипта.

То, что уже комментировал раньше в скрипте не стал комментировать. Закомментировал, только что делают новые опкоды:

FLD1, FDIV, FADD, FSTP и FSUBR.

3.2. Вариант с делением шага игрового таймера:

пример скрипт "Timer Mission v. timer slowdown v. division step of the game timer".

Скрытый текст

[ENABLE]
aobscan(aob_TimerMission,xx89xxxxxxxxc2xxxxxxxxxxxxxxxxxxxxxxxxxx8bxxxx85xx74xx8bxxxxxxxxxx8bxxffxxxxxxxxxx85)
alloc(newmem_TimerMission,2048)
label(returnhere_TimerMission)
label(code)
label(timer1)
registersymbol(timer1)
label(timer2)
registersymbol(timer2)
label(NewStepTimer)
label(Coefficient)
registersymbol(Coefficient)
registersymbol(aob_TimerMission)

newmem_TimerMission:
fld1                   // Загружаем в стек (в st(0), при этом сдвигаем стек) 1,
                       // где 1 - это (шаг игрового таймера - 1 сек).
fdiv [Coefficient]     // Делим 1 (st(0)) на значение в Coefficient,
                       // тем самым получая новый шаг для внутрискриптового
                       // таймера [timer2].
                       // Результат заносится в st(0) не сдвигая стека.
fadd [timer2]          // Прибавляем st(0) к значению в [timer2].
                       // Результат также заносится в st(0) не сдвигая стека.
fstp [timer2]          // Выгружаем, полученную сумму в [timer2], при этом
                       // стек сдвигается, возвращаясь в первоначальное
                       // состояние.
cmp [timer2],(float)1  // Сравниваем это значение с 1.
jb code                // Если меньше 1, то прыгаем на метку code.
                       // Если больше 1, то
inc eax                // Увеличиваем игровой таймер на 1. И отнимем 1
                       // от внутрискриптового таймера [timer2].
fld1                   // Загружаем в стек (в st(0), при этом сдвигаем стек) 1
fsubr [timer2]         // Отнимаем от значения в [timer2] 1
                       // Результат также заносится в st(0) не сдвигая стека.
fstp [timer2]          // Выгружаем, полученное значение в [timer2], при этом
                       // стек сдвигается, возвращаясь в первоначальное
                       // состояние.

code:
mov dword ptr [timer1],eax
mov [ecx+08],eax
pop esi
jmp returnhere_TimerMission

timer1:
dd 0
timer2:
dd (float)0
Coefficient:
dd (float)1
NewStepTimer:
dd (float)0

aob_TimerMission:
jmp newmem_TimerMission
returnhere_TimerMission:

[DISABLE]
aob_TimerMission: // 016674EC
db 40 89 41 08 5E

unregistersymbol(timer1)
unregistersymbol(timer2)
unregistersymbol(Coefficient)
unregistersymbol(aob_TimerMission)
dealloc(newmem_TimerMission)

 

 

Скрипт 3.2. более универсальный подойдёт как для целых, так и для не целых ;) значений.  

 

На видео показана работа скрипта и половина видео посвящена, как отслеживать онлайн значения регистров FPU.

Видео:

 

 

Ну и табличка с 6 скриптами и нужными адресами:

Ниже залита табличка со всеми скриптами этой темы.

Изменено пользователем Garik66
  • Плюс 4
Ссылка на комментарий
Поделиться на другие сайты

Ну и для закрепления.

 

Мы написали скрипт, выложили его в паблик и нам пишет ну допустим "Несообразительный пользователь".

"Несообразительный пользователь" - "Я включил скрипт, а время не как в игре. Сделайте пожалуйста как в игре.

Из сообщения мы понимаем, что пользователь хочет, чтобы таймер был поделён на минуты и секунды.

И тут вмешиваетесь Вы, так как уже написали скрипт

2. Обнуление таймера при достижении определённого значения

пример скрипт "Timer Mission v. Adding a limit to the timer":

Вы - "Это просто, добавим ещё один таймер и каждые 60 секунд будем обнулять секундомер, а минутный таймер увеличивать на 1."

Немного подумав, Я - "И это всё? Вы точно всё учли?"

И через паузу - "А если "Несообразительный пользователь" ;) активирует скрипт не вначале миссии, когда таймер равен 0, а в середине, например после 10 минут?

В этом случае нам нужно разово сделать пересчёт секунд в минуты и остаток записать в секундомер."

Итак с первым заданием разобрались.

 

Но "Несообразительный пользователь" не унимается - "Я поставил уровень сложности "Кошмар", а там интерфейса нет, как в Hitman: Absolution и таймера не видно, сделайте мне пожалуйста, чтобы скрипт хотя бы каждую минуту сообщал мне об этом."

Итак со вторым заданием тоже всё ясно - нужно добавить какой-нибудь звуковой сигнал и чтобы он звучал каждую минуту. Для этого уже ассемблера СЕ нам не хватит, придётся использовать вставки на LUA.

 

И снова "Несообразительный пользователь" - "И сделайте пожалуйста, чтобы таймер обнулился на 12 минутах, а потом каждые 2 минуты. (время подобрано, чтобы не удлинять видео)

Ну вот и третье задание.

 

Сам скрипт на этот раз комментировать не буду. После скрипта опишу некоторые новые опкоды и немного LUA.

 

4. Скрипт по заданию

"Timer Mission v. Sound"

Скрытый текст

[ENABLE]
{$LUA}
timer = createTimer(true)
timer:setInterval(5)
timer.OnTimer = function()
if getAddressList().getMemoryRecordByID("63").Value == "59" then
PlaySound(findTableFile([[Activate]]))
sleep "1000"
end
end
{$ASM}
aobscan(aob_TimerMission,xx89xxxxxxxxc2xxxxxxxxxxxxxxxxxxxxxxxxxx8bxxxx85xx74xx8bxxxxxxxxxx8bxxffxxxxxxxxxx85)
alloc(newmem_TimerMission,2048)
label(returnhere_TimerMission)
label(code)
label(code1)
label(code2)
label(timer1)
registersymbol(timer1)
label(timer2)
registersymbol(timer2)
label(timer3)
registersymbol(timer3)
label(once)
label(Coefficient)
label(Coefficient1)
registersymbol(aob_TimerMission)

newmem_TimerMission:
cmp [once],1
jne code1
mov dword ptr [timer2],eax
fild dword ptr [timer2]
fdiv [Coefficient]
fistp dword ptr [timer2]
push eax
push ebx
push ecx
mov ebx,[timer2]
mov ecx,0
imul ecx,ebx,#60
cmp eax,ecx
jb @f
sub eax,ecx
mov [timer3],eax
jmp code2

@@:
sub [timer2],1
add eax,#60
sub eax,ecx
mov [timer3],eax

code2:
pop ecx
pop ebx
pop eax
mov [once],0

code1:
inc eax
push ebx
mov ebx,[Coefficient1]
cmp [timer2],ebx
pop ebx
jne @f
mov [Coefficient1],2
mov [timer2],0
mov [timer3],0
mov eax,0
jmp code

@@:
inc [timer3]
cmp [timer3],#60
jne code
mov [timer3],0
inc [timer2]

code:
mov dword ptr [timer1],eax
mov [ecx+08],eax
pop esi
jmp returnhere_TimerMission

timer1:
dd 0
timer2:
dd 0
timer3:
dd 0
once:
dd 1
Coefficient:
dd (float)60
Coefficient1:
dd #12

aob_TimerMission:
jmp newmem_TimerMission
returnhere_TimerMission:

[DISABLE]
{$LUA}
timer:setEnabled(false)
{$ASM}
aob_TimerMission: // 016674EC
db 40 89 41 08 5E

unregistersymbol(timer1)
unregistersymbol(timer2)
unregistersymbol(timer3)
unregistersymbol(aob_TimerMission)
dealloc(newmem_TimerMission)

 

Новое на ассемблер:

1. fild dword ptr [timer2] - копируем значение в [timer2] в st(0), сдвигая стек, одновременно переводя значение из Integer во Float.

2. fistp dword ptr [timer2] - выталкиваем из st(0) в [timer2], восстанавливая стек, одновременно переводя значение из Float в Integer, но fistp при этом делает либо усечение (в нашем случае если остаток меньше 30 секунд), либо округление (если больше 30 секунд). На самом деле есть более подходящий для нас опкод fisttp (который отбрасывает дробную часть), но он почему то не компилируется СЕ, поэтому пришлось добавить дополнительные 6 строчек в код:

jb @f                //1
sub eax,ecx
mov [timer3],eax
jmp code2

@@:                  //2
sub [timer2],1       //3  
add eax,#60          //4  
sub eax,ecx          //5
mov [timer3],eax     //6

 

Про вставку на LUA.

{$LUA} - выполнить LUA код.

{$ASM} - выполнить код на ассемблер СЕ.

timer = createTimer(true) - активируем таймер, обратите внимание на это, обязательно деактивируйте таймер при выключении скрипта:

[DISABLE]
{$LUA}
timer:setEnabled(false)

timer:setInterval(5) - устанавливаем интервал

timer.OnTimer = function() - функция таймера, т.е. что нужно проверять и делать.

getAddressList() - функция получающая данные с Вашей таблицы

getAddressList().getMemoryRecordByID("63").Value == "59" - проверяет равно ли, значение записи в таблице с ID=63, 59. (в нашем случае это Second Timer).

как узнать ID записи в таблице -> посмотрите эту тему - 

PlaySound(findTableFile([[Activate]])) - проигрывание встроенного звука активации скриптов в СЕ, если Вы хотите какой-нибудь другой звук, то посмотрите мой видео урок 

Скрытый текст

 

 

sleep "1000" - нужен для того, чтобы сигнал прозвучал один раз, уменьшая 1000 Вы можете добиться, чтобы сигнал прозвучал два раза, три и т.д.

Если убрать sleep "1000" совсем, то вместо сигнала будет тарахтение в течении 1 секунды.

Полностью прокомментировать, что делает скрипт попробуйте сами.

 

На видео показана работа скрипта:

 

 

И залил табличку со всеми скриптами этой темы. Добавил ещё один скрипт и перезалил табличку в следующем сообщении.

 

Изменено пользователем Garik66
  • Плюс 3
Ссылка на комментарий
Поделиться на другие сайты

Благодаря MasterGH  и этой теме -  было найдено решение  для использования  опкода fisttp в СЕ.

опкод fisttp  для нашего случая = 

push eax
lea eax,[timer2]
db DB 08
pop eax

Так что выложу новый скрипт:

4.1. Timer Mission v. fisttp

Скрытый текст

[ENABLE]
{$LUA}
timer = createTimer(true)
timer:setInterval(5)
timer.OnTimer = function()
if getAddressList().getMemoryRecordByID("63").Value == "59" then
PlaySound(findTableFile([[Activate]]))
sleep "1000"
end
end
{$ASM}
aobscan(aob_TimerMission,xx89xxxxxxxxc2xxxxxxxxxxxxxxxxxxxxxxxxxx8bxxxx85xx74xx8bxxxxxxxxxx8bxxffxxxxxxxxxx85)
alloc(newmem_TimerMission,2048)
label(returnhere_TimerMission)
label(code)
label(code1)
label(code2)
label(timer1)
registersymbol(timer1)
label(timer2)
registersymbol(timer2)
label(timer3)
registersymbol(timer3)
label(once)
label(Coefficient)
label(Coefficient1)
registersymbol(aob_TimerMission)

newmem_TimerMission:
cmp [once],1
jne code1
mov dword ptr [timer2],eax
fild dword ptr [timer2]
fdiv [Coefficient]
push eax
lea eax,[timer2]
db DB 08
pop eax
push eax
push ebx
push ecx
mov ebx,[timer2]
mov ecx,0
imul ecx,ebx,#60
cmp eax,ecx
sub eax,ecx
mov [timer3],eax
jmp code2

code2:
pop ecx
pop ebx
pop eax
mov [once],0

code1:
inc eax
push ebx
mov ebx,[Coefficient1]
cmp [timer2],ebx
pop ebx
jne @f
mov [Coefficient1],2
mov [timer2],0
mov [timer3],0
mov eax,0
jmp code

@@:
inc [timer3]
cmp [timer3],#60
jne code
mov [timer3],0
inc [timer2]

code:
mov dword ptr [timer1],eax
mov [ecx+08],eax
pop esi
jmp returnhere_TimerMission

timer1:
dd 0
timer2:
dd 0
timer3:
dd 0
once:
dd 1
Coefficient:
dd (float)60
Coefficient1:
dd #12

aob_TimerMission:
jmp newmem_TimerMission
returnhere_TimerMission:

[DISABLE]
{$LUA}
timer:setEnabled(false)
{$ASM}
aob_TimerMission: // 016674EC
db 40 89 41 08 5E

unregistersymbol(timer1)
unregistersymbol(timer2)
unregistersymbol(timer3)
unregistersymbol(aob_TimerMission)
dealloc(newmem_TimerMission)

 

 И перезалью табличку: 

перезалил ниже, добавив ещё один скрипт.

Изменено пользователем Garik66
  • Плюс 2
Ссылка на комментарий
Поделиться на другие сайты

Благодаря gmz и этой теме   было найдено ещё одно решение для пункта 3. Замедление таймера

3.3. Вариант с получением времени работы инструкции inc eax (Call GetTickCount64) и с созданием отдельного потока под неё.

пример скрипт "Timer Mission v. GetTickCount64".

Скрытый текст

[ENABLE]
aobscan(aob_TimerMission,xx89xxxxxxxxc2xxxxxxxxxxxxxxxxxxxxxxxxxx8bxxxx85xx74xx8bxxxxxxxxxx8bxxffxxxxxxxxxx85)
alloc(newmem_TimerMission,2048)
label(returnhere_TimerMission)
label(TimeCheck)
registersymbol(aob_TimerMission)

newmem_TimerMission:
newmem_TimerMission:
push eax
push ecx
push edx
call GetTickCount64
cmp [TimeCheck],0
jnz @f
mov [TimeCheck],eax
@@:
sub eax,[TimeCheck]
cmp eax,1000
jb @f
mov [TimeCheck],0
@@:
pop edx
pop ecx
pop eax

cmp [TimeCheck],0
jnz @f
inc eax
@@:
mov [ecx+08],eax
pop esi
jmp returnhere_TimerMission

TimeCheck:
dd 0

aob_TimerMission:
jmp newmem_TimerMission
returnhere_TimerMission:

[DISABLE]
aob_TimerMission:
db 40 89 41 08 5E

unregistersymbol(aob_TimerMission)
dealloc(newmem_TimerMission)

 

Подробности прочитайте в теме по ссылке.

 

Изменено пользователем Garik66
  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

Ну и напоследок (надеюсь :D, что напоследок).

3.4. Вариант с использованием функции Sleep.

пример скрипт "Timer Mission v. Sleep LUA".

Скрытый текст

[ENABLE]
{$LUA}
timer = createTimer(true)
timer:setInterval(5)
timer.OnTimer = function()
if getAddressList().getMemoryRecordByID("79").Value == "0" then
sleep "3000"
getAddressList().getMemoryRecordByID("79").Value = "1"
end
end

{$ASM}
aobscan(aob_TimerMission,xx89xxxxxxxxc2xxxxxxxxxxxxxxxxxxxxxxxxxx8bxxxx85xx74xx8bxxxxxxxxxx8bxxffxxxxxxxxxx85)
alloc(newmem_TimerMission,2048)
label(returnhere_TimerMission)
label(flag)
registersymbol(flag)
registersymbol(aob_TimerMission)

newmem_TimerMission:
cmp [flag],1
jne @f
mov [flag],0
inc eax

@@:
mov [ecx+08],eax
pop esi
jmp returnhere_TimerMission

flag:
dd 1

aob_TimerMission:
jmp newmem_TimerMission
returnhere_TimerMission:

[DISABLE]
{$LUA}
timer:setEnabled(false)

{$ASM}
aob_TimerMission:
db 40 89 41 08 5E

unregistersymbol(flag)
unregistersymbol(aob_TimerMission)
dealloc(newmem_TimerMission)

 

Этот метод всё-таки точнее, т.е. Sleep "3000" соответствует ровно 3 сек задержки таймера.  

Табличку перезалил ниже.

 

Изменено пользователем Garik66
  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

Наткнулся на урок от MasterGH на форуме СЕ. (Интересные возможности - автоподключение к процессу и хук в окно игры).

Ссылка на урок в видео и в таблице.

Комментировать скрипт не буду, попробуйте сами.

Скрипт

4.2. Timer Mission v. ShowMessageInGame

Скрытый текст

[ENABLE]
{$LUA}
processName = 'ACCGame-Win32-Shipping.exe'

isD3dhook_initializeHook = false
isTimerShowingMessageInGameMenu = false

autoAttachList = getAutoAttachList()
stringlist_add(autoAttachList, processName);

function onOpenProcess(processid)
    if not isD3dhook_initializeHook then
        reinitializeSymbolhandler()
        d3dhook_initializeHook()
        isD3dhook_initializeHook = true
        ShowMessageInGame('d3dhook initialize Hook!', 400, 100, 2)
        createHotkey(OnKeyPressSomeActivate,VK_HOME)
    end
end

function OnTickTimerShowingMessageInGameMenu(senderTimer)
    timer_setEnabled(senderTimer, false)
    object_destroy(senderTimer)
    object_destroy(displayedTextObject)
    object_destroy(fontmap)
    object_destroy(font)
    isTimerShowingMessageInGameMenu = false
end

function ShowMessageInGame(stringMessage, fontWidthTextContainer, fontHeightTextContainer, timeShowing)
    font = createFont()
    font_setSize(font, 24)
    font_setColor(font,0x0000ff) --red rgb

    fontmap = d3dhook_createFontmap(font)

    displayedTextObject = d3dhook_createTextContainer(fontmap, fontWidthTextContainer, fontHeightTextContainer, stringMessage )

    d3dhook_renderobject_setY(displayedTextObject, -1)
    d3dhook_renderobject_setX(displayedTextObject, -1)


    messageTimer = createTimer(nil, false)
    timer_setInterval(messageTimer, timeShowing * 1000)
    timer_onTimer(messageTimer, OnTickTimerShowingMessageInGameMenu)
    timer_setEnabled(messageTimer, true)
    isTimerShowingMessageInGameMenu = true
end

function OnKeyPressSomeActivate()
    if not isTimerShowingMessageInGameMenu then
        Seconds = getAddressList().getMemoryRecordByID("82").Value
        Minute = getAddressList().getMemoryRecordByID("83").Value
        ShowMessageInGame('Have passed'..Minute..'minutes'..Seconds..'seconds!', 400, 100, 2)
    end
end

{$ASM}
aobscan(aob_TimerMission,xx89xxxxxxxxc2xxxxxxxxxxxxxxxxxxxxxxxxxx8bxxxx85xx74xx8bxxxxxxxxxx8bxxffxxxxxxxxxx85)
alloc(newmem_TimerMission,2048)
label(returnhere_TimerMission)
label(code)
label(code1)
label(code2)
label(timer1)
registersymbol(timer1)
label(timer2)
registersymbol(timer2)
label(timer3)
registersymbol(timer3)
label(once)
label(Coefficient)
registersymbol(aob_TimerMission)

newmem_TimerMission:
cmp [once],1
jne code1
mov dword ptr [timer2],eax
fild dword ptr [timer2]
fdiv [Coefficient]
push eax
lea eax,[timer2]
db DB 08
pop eax
push eax
push ebx
push ecx
mov ebx,[timer2]
mov ecx,0
imul ecx,ebx,#60
cmp eax,ecx
sub eax,ecx
mov [timer3],eax
jmp code2

code2:
pop ecx
pop ebx
pop eax
mov [once],0

code1:
inc eax
inc [timer3]
cmp [timer3],#60
jne code
mov [timer3],0
inc [timer2]

code:
mov dword ptr [timer1],eax
mov [ecx+08],eax
pop esi
jmp returnhere_TimerMission

timer1:
dd 0
timer2:
dd 0
timer3:
dd 0
once:
dd 1
Coefficient:
dd (float)60

aob_TimerMission:
jmp newmem_TimerMission
returnhere_TimerMission:

[DISABLE]
{$LUA}

{$ASM}
aob_TimerMission: // 016674EC
db 40 89 41 08 5E

unregistersymbol(timer1)
unregistersymbol(timer2)
unregistersymbol(timer3)
unregistersymbol(aob_TimerMission)
dealloc(newmem_TimerMission)

 

 

Видео:

 

 

 

Табличка

Залил ниже

Изменено пользователем Garik66
  • Плюс 3
Ссылка на комментарий
Поделиться на другие сайты

По запросу ( ) пользователя Razi  написал ещё один скрипт.

Скрипт Timer Mission v. long timer:

Скрытый текст

[ENABLE]
{$LUA}
timer = createTimer(true)
timer:setInterval(100)
timer.OnTimer = function()
  Second = getAddressList().getMemoryRecordByID("91").Value
  Minute = getAddressList().getMemoryRecordByID("92").Value
  Hour = getAddressList().getMemoryRecordByID("93").Value
  Daily = getAddressList().getMemoryRecordByID("94").Value
  control_setCaption(UDF1_CEEdit1,Second)
  control_setCaption(UDF1_CEEdit2,Minute)
  control_setCaption(UDF1_CEEdit3,Hour)
  control_setCaption(UDF1_CEEdit4,Daily)
end
{$ASM}
aobscan(aob_TimerMission,xx89xxxxxxxxc2xxxxxxxxxxxxxxxxxxxxxxxxxx8bxxxx85xx74xx8bxxxxxxxxxx8bxxffxxxxxxxxxx85)
alloc(newmem_TimerMission,2048)
label(returnhere_TimerMission)
label(code)
label(code1)
label(timer_address)             // Ввёл для того, чтобы изменить количество
registersymbol(timer_address)    // в игре в ручную в таблице.
label(timer1)                    // Игровой таймер в сек.
registersymbol(timer1)
label(timer2)                    // Таймер в сек.
registersymbol(timer2)
label(timer3)                    // Таймер в мин.
registersymbol(timer3)
label(timer4)                    // Таймер в часах.
registersymbol(timer4)
label(timer5)                    // Таймер в днях.
registersymbol(timer5)
label(once)                      // Чтобы пересчёт происходил один раз.
label(Coefficient)               // Для пересчёта сек в минуты.
label(Coefficient1)              // Для пересчёта сек в часы.
label(Coefficient2)              // Для пересчёта сек в дни.
registersymbol(aob_TimerMission)

newmem_TimerMission:
mov [timer_address],ecx
cmp [once],1
jne code1

mov dword ptr [timer5],eax  // Расчёт дней.
fild dword ptr [timer5]
fdiv [Coefficient2]
push eax
lea eax,[timer5]
db DB 08
pop eax
push eax
push ebx
push ecx
mov ebx,[timer5]
mov ecx,0
imul ecx,ebx,#86400
cmp eax,ecx
sub eax,ecx
mov [timer4],eax

fild dword ptr [timer4]     // Расчёт часов.
fdiv [Coefficient1]
push eax
lea eax,[timer4]
db DB 08
pop eax
mov ebx,[timer4]
mov ecx,0
imul ecx,ebx,#3600
cmp eax,ecx
sub eax,ecx
mov [timer3],eax

fild dword ptr [timer3]     // Расчёт минут.
fdiv [Coefficient]
push eax
lea eax,[timer3]
db DB 08
pop eax
mov ebx,[timer3]
mov ecx,0
imul ecx,ebx,#60
cmp eax,ecx
sub eax,ecx
mov [timer2],eax

pop ecx
pop ebx
pop eax
mov [once],0

code1:
inc eax
inc [timer2]
cmp [timer2],#60
jne code
mov [timer2],0
inc [timer3]
cmp [timer3],#60
jne code
mov [timer3],0
inc [timer4]
cmp [timer4],#24
jne code
mov [timer4],0
inc [timer5]

code:
mov dword ptr [timer1],eax
mov [ecx+08],eax
pop esi
jmp returnhere_TimerMission

timer_address:
dd 0
timer1:
dd 0
timer2:
dd 0
timer3:
dd 0
timer4:
dd 0
timer5:
dd 0
once:
dd 1
Coefficient:
dd (float)60    // в 1 минуте 60 сек
Coefficient1:
dd (float)3600  // в 1 часе 3600 сек
Coefficient2:
dd (float)86400 // в 1 дне 86400 сек

aob_TimerMission:
jmp newmem_TimerMission
returnhere_TimerMission:

[DISABLE]
{$LUA}
timer:setEnabled(false)
{$ASM}
aob_TimerMission: // 016674EC
db 40 89 41 08 5E

unregistersymbol(timer_address)
unregistersymbol(timer1)
unregistersymbol(timer2)
unregistersymbol(timer3)
unregistersymbol(timer4)
unregistersymbol(timer5)
unregistersymbol(aob_TimerMission)
dealloc(newmem_TimerMission)

 

Видео:

 

Табличка:

ACCGame-Win32-Shipping-for-Gamechacklab.CT

  • Плюс 2
Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

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