Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Мод на ХотА
DF2 :: ФОРУМЫ > Игровые форумы > Heroes of Might & Magic III > Моды
Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
DedMorozzz
Цитата(igrik @ 25 Nov 2016, 20:23) *
Вкратце, что такое patсher_x86 (тут)
Как создать dll для HD-мода. (тут)

Код
#include "patcher_x86.hpp"

Patcher* _P;
PatcherInstance* _PI;

// Замок
int BuildDepends_Castle[] =
{
0,                              -1,
1, 0,                           -1,
2, 1,                           -1,
3, 2,                           -1,
6,                              -1,
5,                              -1,
22, 5,                          -1,
14,                             -1,
15, 14,                         -1,
16,                             -1,
17, 6,                          -1,
7,                              -1,
8, 7,                           -1,
9, 8,                           -1,
11, 5,                          -1,
12, 11, 16, 0, 14,              -1,
13, 12, 9,                      -1,
30, 7,                          -1,
37, 30,                         -1,
31, 30,                         -1,
38, 31,                         -1,
33, 30, 16,                     -1,
40, 33,                         -1,
32, 33,                         -1,
18, 32,                         -1,
39, 32,                         -1,
19, 39,                         -1,
21, 33,                         -1,
35, 21,                         -1,
42, 35,                         -1,
34, 33, 0,                      -1,
41, 34,                         -1,
36, 34, 2,                      -1, // Ангелы требуют еще и ГМ3
43, 36, 3,                      -1, // Архангелы требуют еще и ГМ4
26,                             -1,
-100
};

// Инферно  
int BuildDepends_Inferno[] =
{
7,                              -1,
21, 7,                          -1,
8, 7,                           -1,
22, 8,                          -1,
9, 8,                           -1,
5,                              -1,
16,                             -1,
14,                             -1,
15, 14,                         -1,
0,                              -1,
23, 0,                          -1,
1, 0,                           -1,
2, 1,                           -1,
3, 2,                           -1,
4, 3,                           -1,
11, 5,                          -1,
12, 11, 16, 14, 0,              -1,
13, 12, 9,                      -1,
30, 7,                          -1,
18, 30,                         -1,
37, 30,                         -1,
19, 37,                         -1,
32, 30,                         -1,
24, 32,                         -1,
39, 32,                         -1,
25, 39,                         -1,
31, 30,                         -1,
38, 31,                         -1,
33, 31,                         -1,
40, 33,                         -1,
35, 33, 0,                      -1,
42, 35,                         -1,
34, 33,                         -1,
41, 34, 0,                      -1, // ул.Провал требует ГМ1 взамен ГМ2 (согласно описаниям HotA)
36, 33, 5,                      -1, // Дьяволы не требуют Провал для постройки (34 -> 33)
43, 36,                         -1,
26,                             -1,
-100
};


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    static _bool_ plugin_On = 0;
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        if (!plugin_On)
        {
            plugin_On = 1;        

            _P = GetPatcher();
            _PI = _P->CreateInstance("HD.Plugin.DedMorozzz");

            *(int*)0x4EB816 = (int)BuildDepends_Castle;
            *(int*)0x4EBA39 = (int)BuildDepends_Inferno;

        }
        break;

    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}



Создал ДЛЛку, а как её к героям прикрутить теперь то?
И у тебя в коде не инклудится .h файл. Так и надо?
igrik
Цитата(DedMorozzz @ 28 Nov 2016, 23:18) *
Создал ДЛЛку, а как её к героям прикрутить теперь то?

Т.к. этот файл для HD мода, то его нужно класть в "[папка с HotA]\_HD3_Data\Packs\DedMorozzz".
Потом его нужно подключить в плагинах HD лаунчера.

И естественно, он будет работать только с включенным HD.
Цитата(DedMorozzz @ 28 Nov 2016, 23:18) *
И у тебя в коде не инклудится .h файл. Так и надо?

Предварительно нужно еще закинуть "patcher_x86.hpp" в папку решения проекта (короче там, где остальные файлы *.hpp и *.h)
Тогда он будет компилироваться без ошибок и запросов на недостающие файлы.

upd:Также, ты не только можешь, а даже желательно все твои правки из exe перенести в dll
На примере 5% для специализаций (На счет правки навыков, оказалось не все так просто)
+ я что-то не смог получить адрес флоат переменной через С++, поэтому пришлось шить напрямую в пустое место в exe
Код
// правка интеллекта (2%)
*(int*)0x4E4B88 = 0x3ca3d70a;    // float 0.02f (записал в пустое место в exe)
*(int*)0x4DA596 = 0x4E4B88;      // при смерти героя
*(int*)0x4D917E = 0x4E4B88;      // при старте при настройке героя
*(int*)0x4DDACC = 0x4E4B88;      // процесс экшн в окне героя
*(int*)0x4E4B69 = 0x4E4B88;      // при открытии окна героя
*(int*)0x4E20EC = 0x4E4B88;      // в подневный расчет максимума маны

вышеуказанное можно вставить после строки *(int*)0x4EBA39 = (int)BuildDepends_Inferno;
DedMorozzz
Цитата(igrik @ 29 Nov 2016, 08:36) *
Предварительно нужно еще закинуть "patcher_x86.hpp" в папку решения проекта (короче там, где остальные файлы *.hpp и *.h)
Тогда он будет компилироваться без ошибок и запросов на недостающие файлы.

Да вроде и так без ошибок. Перенёс скомпилиную ДЛЛку в папку пакс. И всё завелось. Только вот дьяволы терь ифритов не требуют))
Отсюда вытекает вопрос - где подсмотреть айдишники зданий. Гуглануть не получилось ): Что бы, мог сам, для любого замка зависимости поменять

Цитата(igrik @ 29 Nov 2016, 08:36) *
upd:Также, ты не только можешь, а даже желательно все твои правки из exe перенести в dll
На счет правки навыков, оказалось не все так просто

Ну я навыки тоже правил... Но если получится, всё что можно перенести - перенесу
igrik
Цитата(DedMorozzz @ 29 Nov 2016, 21:21) *
Цитата(igrik @ 29 Nov 2016, 08:36) *
Предварительно нужно еще закинуть "patcher_x86.hpp" в папку решения проекта (короче там, где остальные файлы *.hpp и *.h)
Тогда он будет компилироваться без ошибок и запросов на недостающие файлы.

Да вроде и так без ошибок. Перенёс скомпилиную ДЛЛку в папку пакс. И всё завелось. Только вот дьяволы терь ифритов не требуют))
Отсюда вытекает вопрос - где подсмотреть айдишники зданий. Гуглануть не получилось ): Что бы, мог сам, для любого замка зависимости поменять

Качай ERM-help. Внутри него есть кнопка "CA", Да и вообще, там много полезных данных есть.
DedMorozzz
Скачать не получилось. Точнее как, получилось на файл пустой. Хоть и весит под 6 метров
http://www.wakeofgods.com/erm_help/receivers/receiver_ca.htm - вот тут нашел эту инфу, в онлайне
Итого. Каждый замок указан цепочкой что требуется для него. Айди постройки и через запятую какие ещё требуются для него...

Т.о. для дьяволов, что бы вернуть ифритов получается так:
36, 35, 33, 5, -1,
Вместо
36, 33, 5, -1,

Но всё равно получается. Что для другого замка в ручную прописывать все зависимости... Проверить не вышло, с только одой постройкой (может смёрджит) т.к. в дополнение ко всему не ясно на какой участок ссылаться с этим массивом (в смысле с массивом зависимостей, к примеру замка "оплот")

PS:
Ещё и изменить навык некромантии не получилось. В exe верные числа стоят. 0-10-20-30. Хотя в игре по факту 0-5-10-15 (в ХотА некромантию в 2 раза порезали)
Менял 0-10-20-30 на 0-100-100-100. Всё равно оставалось 0-5-10-15...
Как найти место где ещё раз переписывается процент для этого навыка?

PPS: как тут много то всего...
hippocamus
Цитата(DedMorozzz @ 30 Nov 2016, 21:12) *
PS:
Ещё и изменить навык некромантии не получилось. В exe верные числа стоят. 0-10-20-30. Хотя в игре по факту 0-5-10-15 (в ХотА некромантию в 2 раза порезали)
Естественно, потому что хотовские правки находятся не в экзешнике (который почти не изменён), а в hota.dll
DedMorozzz
Цитата(hippocamus @ 30 Nov 2016, 22:30) *
Естественно, потому что хотовские правки находятся не в экзешнике (который почти не изменён), а в hota.dll

Ну да, логично)
Соотв. надо в своей ДЛЛке переписать эти значения на нужные мне... заодно и остальные изменения перенесу туда
igrik
Цитата(DedMorozzz @ 30 Nov 2016, 21:12) *
Скачать не получилось. Точнее как, получилось на файл пустой. Хоть и весит под 6 метров
Сними галку "Спрашивать при открытии такого файла"
Цитата(DedMorozzz @ 30 Nov 2016, 21:12) *
Итого. Каждый замок указан цепочкой что требуется для него. Айди постройки и через запятую какие ещё требуются для него...
Да.
Можно было просто "36, 35, 5, -1,". Там все идет прицепом, ведь для 35 требуется "35, 33, 0, -1, " и т.д.
Цитата(DedMorozzz @ 30 Nov 2016, 21:12) *
Но всё равно получается. Что для другого замка в ручную прописывать все зависимости... к примеру замка "оплот"

Именно.
(0x4EB8B2+1)=оплот...
7, -1, 8, 7, -1, 9, 8, -1, 5, -1, 16, -1, 14, -1, 15, 14, -1, 0, -1, 1, 0, -1, 2, 1, -1, 3, 2, -1
4, 3, -1, 17, -1, 21, 17, -1, 11, 5, -1, 12, 11, 0, 16, 14, -1, 13, 12, 9, -1, 30, 7, -1, 37, 30
-1, 31, 30, -1, 18, 31, -1, 22, 18, -1, 38, 31, -1, 19, 38, -1, 32, 30, -1, 39, 32, -1, 34, 32, -1
24, 34, -1, 41, 34, -1, 25, 41, -1, 33, 32, -1, 40, 33, -1, 35, 33, 34, -1, 42, 35, -1, 36, 35, 1
-1, 43, 36, 2, -1, 26, -1, -100

Цитата(DedMorozzz @ 30 Nov 2016, 21:12) *
PPS: как тут много то всего...
Ну так....
DedMorozzz
Цитата(igrik @ 30 Nov 2016, 23:55) *
Сними галку "Спрашивать при открытии такого файла"

Да не, не в этом дело. Я даже скачал другую софтинку. Спец для просмотра такого рода файлов. И в ней выбрать открыть конкретный файл - всё равно пусто. Причём как на винде 10ке, как и на луинксе (минте). Всегда пусто

Цитата(igrik @ 30 Nov 2016, 23:55) *
(0x4EB8B2+1)=оплот...

Где все эти данные посмотреть? Для любого замка... Идея как менять зависимости ясна. Но вот где код замка взять - не понятно. И странный вид - "0x4EB8B2+1". +1 так и надо?
igrik
Цитата(DedMorozzz @ 01 Dec 2016, 12:29) *
Где все эти данные посмотреть? Для любого замка... Идея как менять зависимости ясна. Но вот где код замка взять - не понятно.

Посмотреть адреса можно в базе для IDA HoMM3 (© sergroj)
Открыть эту базу можно через IDA. Лично я пользуюсь пятой версией.
Вот ERM Help.zip
Цитата(DedMorozzz @ 01 Dec 2016, 12:29) *
И странный вид - "0x4EB8B2+1". +1 так и надо?

Ничего странного. Просто адрес указан со смещением, что эквивалентно 0x4EB8B3.
DedMorozzz
Ха! https://sc-cdn.scaleengine.net/i/fd84d33a46...b7d7a4c5d61.png
Ибо 2й файл так же не открылся, который в архиве. На стек оверфлоу нашел решение)
После этой галочки - всё завелось

А базу скачал. Ща покурю её..
DedMorozzz
Цитата(igrik @ 01 Dec 2016, 19:20) *
Цитата(DedMorozzz @ 01 Dec 2016, 12:29) *
Где все эти данные посмотреть? Для любого замка... Идея как менять зависимости ясна. Но вот где код замка взять - не понятно.

Посмотреть адреса можно в базе для IDA HoMM3 (© sergroj)


Скачал базу. Открыл (кстати, 5я версия ругается, мол качай более новую версию, что бы открыть этот файл)
Руководствуюсь следующей логикой. Для инферно/замка/оплота я знаю уже адресса. Соотв пойму как для них он указывается, что бы для других замков по такому же принципу сделать...

Ищу инферно и ожидаемое значение 0x4EBA39 или 0EBA39
Вот что есть для инферно толкового:
https://sc-cdn.scaleengine.net/i/f3e8d729f4...c652988c3b3.png
https://sc-cdn.scaleengine.net/i/ff0b691a62...5d1b837dbd2.png
https://sc-cdn.scaleengine.net/i/7b758d014f...34e478acfea.png

Но нигде не нашел ожидаемых значение. Я так понимаю, что не там или не то ищу... как мне найти адресс памяти?
И заодно цепочки построек. Я так понимаю, ты откуда-то копировал их
igrik
Цитата(DedMorozzz @ 02 Dec 2016, 00:01) *
Руководствуюсь следующей логикой. Для инферно/замка/оплота я знаю уже адресса. Соотв пойму как для них он указывается, что бы для других замков по такому же принципу сделать...
Ищу инферно и ожидаемое значение 0x4EBA39 или 0EBA39
Но нигде не нашел ожидаемых значение. Я так понимаю, что не там или не то ищу... как мне найти адресс памяти?

Нет. Ты ищешь в 0x5CAFE2. А нужно смотреть по адресу 0x4EBA38+1, в котором содержится указатель на таблицу зависимостей Инферно.
Нажимаешь "G" и вбиваешь этот адрес.


И если уж ты правишь HotA, то учитывай ее нововедения. В данном случае п.III
DedMorozzz
Спасибо! Получилось!
К примеру вот для темницы

Код
int BuildDepends_Dungeon[] =
{
     7,                            -1,
     8, 7,                        -1,
     9, 8,                        -1,
     22,                        -1,
     23,                        -1,
     5,                            -1,
     16,                        -1,
     14,                        -1,
     15, 14,                    -1,
     17, 14,                    -1,
     0,                            -1,
     21, 0,                        -1,
     1, 0,                        -1,
     2, 1,                        -1,
     3, 2,                        -1,
     4, 3,                        -1,
     11, 5,                        -1,
     12, 11, 16, 14, 0,            -1,
     13, 12, 9,                    -1,
     30, 7,                        -1,
     18, 30,                    -1,
     37, 30,                    -1,
     19, 37,                    -1,
     32, 30,                     -1,
     39, 32,                     -1,
     31, 30,                     -1,
     38, 31,                     -1,
     33, 32, 31,                -1,
     40, 33,                    -1,
     34, 33,                    -1,
     41, 34,                    -1,
     35, 33,                    -1,
     42, 35,                    -1,
     36, 34, 35, 1,                -1,
     43, 36, 2,                    -1,
     26,                        -1,
     -100
};

Код
*(int*)0x4EBA5C = (int)BuildDepends_Dungeon;


Цитата(igrik @ 29 Nov 2016, 08:36) *
upd:Также, ты не только можешь, а даже желательно все твои правки из exe перенести в dll
На примере 5% для специализаций (На счет правки навыков, оказалось не все так просто)
+ я что-то не смог получить адрес флоат переменной через С++, поэтому пришлось шить напрямую в пустое место в exe
Код
// правка интеллекта (2%)
*(int*)0x4E4B88 = 0x3ca3d70a;    // float 0.02f (записал в пустое место в exe)
*(int*)0x4DA596 = 0x4E4B88;      // при смерти героя
*(int*)0x4D917E = 0x4E4B88;      // при старте при настройке героя
*(int*)0x4DDACC = 0x4E4B88;      // процесс экшн в окне героя
*(int*)0x4E4B69 = 0x4E4B88;      // при открытии окна героя
*(int*)0x4E20EC = 0x4E4B88;      // в подневный расчет максимума маны

вышеуказанное можно вставить после строки *(int*)0x4EBA39 = (int)BuildDepends_Inferno;


Вот тут немного не ясно:
1. Есть же 0.02 значение. Вот оно. Адресс в exe - 0023AC60. Там хранится значение 0AD7A33C => 3CA3D70A == 0,02
2. зачем столько значений. При смерти героя, повседневный расчёт и т.д. Где они используются? Ибо я менял только в 1м месте и всё верно пересчитывалось

И массивы навыков получилось перенести. Просто массив закинул и завелось:

Код
int SecondarySkills_Mysticism[] =
{
    1, 5, 10, 15
};

Код
*(int*)0x4E41C8 = (int)SecondarySkills_Mysticism;

DedMorozzz
И ещё момент с некромантией...
Сам навык изменить получилось. Вот как выглядит, может кому понадобится:


А вот вернуть процент для амулета гробовщика - не вышло
Как делал:

1)
*(int*)0x4E3FAE = 0x3d4ccccd;

2)
*(int*)0x4E3FAE = 0x63EAE4; //тут значение 0.05

3)
*(int*)0x63EAE4 = 0x3d4ccccd; //в явном виде указываю значение
*(int*)0x4E3FAE = 0x63EAE4;

Никакой из вариантов не подошел. Вылетает игра с ошибкой после конца боя


UPD:
"Поговори с уточкой" в действии. Только отправил сообщение, сразу пришла идея перепроверить адресс памяти
Цитата
004E3FAE: байт с номером Амулета Гробовщика
004E3FE7: указатель (на 63EAE4) на значение его бонуса (0.05)

Итого надо юзать не 0x4E3FAE, а 0x4E3FE7. Тогда всё ок
XEPOMAHT
Цитата(DedMorozzz @ 03 Dec 2016, 15:53) *
И ещё момент с некромантией...


Проще затереть командами NOPS данный код в hota.dll начиная с адреса 1efd8 и не мучиться с компиляцией (тем более будет работать и без HD):

hippocamus
Цитата(XEPOMAHT @ 03 Dec 2016, 23:34) *
Проще затереть командами NOPS данный код в hota.dll начиная с адреса 1efd8 и не мучиться с компиляцией (тем более будет работать и без HD):
Что за nops? Может, nop? (90h)
tolich
Plural of nop, duh.
DedMorozzz
Цитата(XEPOMAHT @ 03 Dec 2016, 22:34) *
Проще затереть командами NOPS данный код в hota.dll начиная с адреса 1efd8 и не мучиться с компиляцией (тем более будет работать и без HD):


Да ладно уже. Всё наоборот в ДЛЛ вынес. В exe'шнике осталась мелочь, которую сегодня довыношу
В ДЛЛке намного проще, в случае чего править. Да и "ченжлог" будет перед глазами сразу)

Но я пока что так и не понял, зачем Игрик менял в стольких местах бонус прироста интеллекта (я его кстати не менял у себя smile.gif Он был у меня проверочным навыком, что бы понять что я лишнего не зацепил, когда менял логистов)
И может кто знает, как округление замедления сделать в большую сторону? Самый имбалансный навык сейчас
feanor
Цитата
И может кто знает, как округление замедления сделать в большую сторону? Самый имбалансный навык сейчас
А какое там округление же? Оно ведь урезает на фиксированную величину, которая забита в текстовике?
DedMorozzz
Цитата(feanor @ 04 Dec 2016, 11:51) *
Цитата
И может кто знает, как округление замедления сделать в большую сторону? Самый имбалансный навык сейчас
А какое там округление же? Оно ведь урезает на фиксированную величину, которая забита в текстовике?

нет. Там проценты замедления. И на эксперте 50%
Вот и получается что скорость в 5 едениц уменьшается на 50% и получается 2.5. И далее округляется до 2х.
Пробовал менять до 49%, что бы получилось 2.5+, в надежде что округлит до 3х, но нет, всё равно 2 вышло

PS: или ты о каком-то другом текстовике говоришь?
igrik
Цитата(DedMorozzz @ 03 Dec 2016, 12:38) *
2. зачем столько значений. При смерти героя, повседневный расчёт и т.д. Где они используются? Ибо я менял только в 1м месте и всё верно пересчитывалось

Я совершенно не вдупляю смысловую нагрузку зыз feanor'a, но уверен, что тут это сообщение будет уместно.

Цитата(DedMorozzz @ 03 Dec 2016, 15:53) *
И ещё момент с некромантией...
a) Сам навык изменить получилось. Вот как выглядит, может кому понадобится:
б) ...А вот вернуть процент для амулета гробовщика - не вышло

Говорю с гарантией, что п."а" работает некорректно (что легко проверить в ольке), отчего в следствии вытекает и п."б". (ибо флоат в инт так просто не запихнуть)

Цитата(DedMorozzz @ 04 Dec 2016, 13:08) *
Цитата(feanor @ 04 Dec 2016, 11:51) *
Цитата
И может кто знает, как округление замедления сделать в большую сторону? Самый имбалансный навык сейчас
А какое там округление же? Оно ведь урезает на фиксированную величину, которая забита в текстовике?

нет. Там проценты замедления. И на эксперте 50%
Пробовал менять до 49%
А чой то 49%? Попробуй 51%.
Там в функции идет result = x/100.0 (авось прокатит)

Цитата(DedMorozzz @ 04 Dec 2016, 12:37) *
В ДЛЛке намного проще, в случае чего править. Да и "ченжлог" будет перед глазами сразу)

«То-то и оно» ©
DedMorozzz
Цитата(igrik @ 04 Dec 2016, 17:13) *
А чой то 49%? Попробуй 51%.
Там в функции идет result = x/100.0 (авось прокатит)


Тогда базовый был бы не 25%. Т.е. на сколько замедляет. Соотв если сделать 51, то замедлять станет ещё сильнее и уж наверняка 2 получится, при базовой 5ке

И ещё в тему магии. Как раз закончил перенос всего и вся в ДЛЛку. Хочу чуть глубже копнуть:
Как молитве сделать не +4, а +6 ко всем статам (имеется ввиду атака+защита)?
А магия "неудача" что бы и минус мораль вешала...
DedMorozzz
I.
По поводу замедления, представляю себе что выглядит оно именно так. Безо всяких расчётов длительности и прочее. Это лишнее...
(напишу на PHP, но к языку не имеет никакого отношения. Просто на нём мне проще донести)



Как вижу себе решение я.. их 3. Нормальное одно
Я не уверен что там используется ООП. Но идея в целом такая. Сделать функцию которая всем делает +1 скорости юнитам, которые будут замедленные


2. То же самое, только проверять кратность скорость. Если остатка после деления нету - тогда игонрить. Ну это так. Более сложный вариант того же самого

3. именно залезть в ф-ю. И приведение типа заменить к нужному округлению

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


II.
Если с магией всё плохо и не получится внести изменения, то что насчёт навыков? Идея такая:
Для дипломатии убрать возможность присоединения юнитов, при этом оставив более дешевый откуп и т.д.
Но при посещении либы, для улучшеной дипломатии даётся +3 к статам. Эксперт +4. и некоторые бонусы от нового арта в ХотА (Мантия Дипломата). Что бы можно было откупаться от нейтральных войск (не супер важно). И что бы увеличивалась мощь армии в глазах монстров на 0-5-10-15%
Это если полностью. Но начать бы хотел по чуть чуть - каким образом настроить навык, что бы при наличии его библиотека давала больше характеристик?

PS: Дофига написал, надеюсь кто-то да осилит)
AlexSpl
Цитата
Но моя проблема в том, что я понятия не имею куда лезть, что бы это сделать...

Поставь брейкпоинт (hardware/write) на значение скорости юнита и посмотри, какие функции её меняют.
DedMorozzz
Цитата(AlexSpl @ 05 Dec 2016, 11:58) *
Цитата
Но моя проблема в том, что я понятия не имею куда лезть, что бы это сделать...

Поставь брейкпоинт (hardware/write) на значение скорости юнита и посмотри, какие функции её меняют.


Вот... где и как это сделать?)
AlexSpl
Смотри в сторону combatManager.

Код
H3CMAddr: array[SV_Complete_RU..SV_HotA, 0..2] of DWORD =
      (($69CB70, $13360, $13364),
       ($6993D0, $132B8, $132BC),
       ($699420, $132B8, $132BC),
       ($6387BC, $132B8, $132BC),
       ($699420, $132B8, $132BC));


Адрес текущего отряда можно получить так: combatManager + 1352 * (dword ptr [combatManager + 132BCh] + 21 * dword ptr [combatManager + 132B8h]) + 21708.

Если развернуть, адрес отряда = dword ptr [699420h] + 1352 * (dword ptr [dword ptr [699420h] + 132BCh] + 21 * dword ptr [dword ptr [699420h] + 132B8h]) + 21708. Значения в скобках - координаты отряда на поле боя. Дальше смотрим структуру и ищем скорость. Здесь чисто интуитивно. Должны быть поля хитов, атаки и защиты и т.п. значения, которые помогут разобраться.
igrik
0x444A21 (замедление)
0x4A2EF0 (функция посещения библиотеки)

Цитата
Как молитве сделать не +4, а +6 ко всем статам (имеется ввиду атака+защита)?

Бонусы молитвы прописаны в "SPTRAITS.TXT".
Цитата
А магия "неудача" что бы и минус мораль вешала...

Нужен хук в 0x4449A7
*(int*)(c->esi + 1152) = c->edi;
feanor
Чо там искать-то, все есть

в структуре стека в битве есть поле множителя (SlowMul в вогобазе), которое устанавливается при касте скорости и потом используется как коэффициент для актуальной скорости в combatMonster_00448560 (что-то с определением достижимости цели, что ли) и combatMonster_GetSpeed (004489F0, собственно расчет скорости)
AlexSpl
2feanor: ) Рубишь энтузиазм на корню.

CreatureAddr = dword ptr [699420h] + 1352 * (dword ptr [dword ptr [699420h] + 132BCh] + 21 * dword ptr [dword ptr [699420h] + 132B8h]) + 21708.

Например,
CreatureAddr + 34h - тип монстра
CreatureAddr + 4Сh - кол-во монстров

Даю способ, как на лету поменять )

Ищем скорость, ставим брейкпоинт и выходим, надеюсь, на
Цитата
0x444A21 (замедление)


То, что известно всем, это хорошо, но человек хотел метод узнать, если я правильно понял.
DedMorozzz
Вот блин. Я понимаю что ответы на вопросы даны. Но я не знаю что с ними делать...
К примеру как ф-ии менять. Там же 16и ричный код. Т.е. как выглядит цифра - понятно. 8 символов. Массив значений умения - 4 по 8. А как ф-я выглядит. И как её менять - не понимаю.
К примеру в ф-ии либы как сделать проверку на наличие/уровень навыка дипломатии.

То же самое с замедлением. Вижу код. А куда его притулить. И зачем точки остановки нужны не ясно. Мне ж не выйти из ф-ии надо, а изменить её

PS: т.е. хочу решение не для конкретно замедления найти, а в целом понять логику. Что бы любую магию/постройку мог менять. Как по примеру с цепочкой городов. Для всех драконов убрал ГМ2 из требований ибо логика смены мне ясна
Вот такое же хочу понять для магии. А замедление или "неудача", как пример на котором хочу проследить логику
igrik
Цитата(DedMorozzz @ 06 Dec 2016, 17:22) *
Вот блин. Я понимаю что ответы на вопросы даны. Но я не знаю что с ними делать...
PS: т.е. хочу решение не для конкретно замедления найти, а в целом понять логику. Что бы любую магию/постройку мог менять. Как по примеру с цепочкой городов. Для всех драконов убрал ГМ2 из требований ибо логика смены мне ясна

Было бы все так просто. Универсальных способов нет. Каждую функцию приходится разбирать в коде и придумывать к ней велосипед.

Цитата(DedMorozzz @ 06 Dec 2016, 17:22) *
К примеру в ф-ии либы как сделать проверку на наличие/уровень навыка дипломатии.
Код
int __stdcall libraryVisit(LoHook* h, HookContext* c)
{
    // в данном случае esi хранит адрес структуры героя
    // откуда мы можем найти и дипломатию ( +201 это смещение до втор.навыков / +4 это смещение до дипломатии )
    // и выйти на прибавку к первичным параметрам ( +1142 это атака и т.д. )
    if (*(char*)(c->esi + 201 + 4) > 1) {                // проверка на продвинутую и выше дипломатию
        char bonnus = (*(char*)(c->esi + 201 + 4)) - 1; // уровень дипломатии -1 чтобы получить правильную прибавку
        *(char*)(c->esi + 1142) += bonnus;                // прибавка к атаке
        *(char*)(c->esi + 1143) += bonnus;                // прибавка к защите
        *(char*)(c->esi + 1144) += bonnus;                // прибавка к колд.силе
        *(char*)(c->esi + 1145) += bonnus;                // прибавка к знаниям
    }
    return EXEC_DEFAULT;  // после завершения хука выполняется затертый хуком код
}
Код
_PI->WriteLoHook(0x4A2F92, (void*)libraryVisit);    // низкоуровневый хук посещения библиотеки с дипломатией

Цитата(DedMorozzz @ 06 Dec 2016, 17:22) *
То же самое с замедлением. Вижу код. А куда его притулить. И зачем точки остановки нужны не ясно. Мне ж не выйти из ф-ии надо, а изменить её.
Вот такое же хочу понять для магии. А замедление или "неудача", как пример на котором хочу проследить логику

Код
#include <cmath>      // для функции округления floor(value + 0.5)
int __stdcall new_SlowMul(LoHook* h, HookContext* c)
{
    // тут структура монстра лежит в ecx.
    // откуда мы и можем получить все интересующие нас параметры
    float speed = (float)(*(int*)(c->ecx +196));                   // получаем скорость монстра (структура +196)
    c->eax = floor( (speed * (*(float*)(c->ecx + 1224))) + 0.5 );  // функция правильного округления (скорость * коэфф.замедления)
    
    // а также приходится "обойти" часть оригинального кода
    c->return_address = 0x448A37;                                  // указываем новый адрес возврата
    return NO_EXEC_DEFAULT;                                        // после завершения хука не выполняется затертый хуком код
}
Код
_PI->WriteLoHook(0x448A1A, (void*)new_SlowMul);     // хук (замена оригинального куска функции расчета скорости)
Это правка только фукнции расчета скорости. Одна из тех двух, что показал feanor. Вторую можно подправить по этой же логике. Основной принцип floor(value + 0.5).
C магией потом покажу.
DedMorozzz
В обоих функах получаю ошибку:
Цитата
1>.\dllmain.cpp(275) : error C2664: 'PatcherInstance::WriteLoHook' : cannot convert parameter 2 from 'void *' to '_LoHookFunc_'
1> Conversion from 'void*' to pointer to non-'void' requires an explicit cast


Гугланул. Пишут что разные компиляторы, для С/С++. Мол валидный код для С это может быть. Переключил компилятор на С - ошибки синтаксиса...
Пробовал контент ифа убрать. Или замедление просто интом сделать. Всё равно та же ошибка

Заменив
_PI->WriteLoHook(0x4A2F92, (void*)libraryVisit);
На
_PI->WriteLoHook(0x4A2F92, libraryVisit);
Завелось. Но мб я лишнее убрал?

PS: проверил. Замедление работае корректно! Спасибо smile.gif Выходит не зря void убрал?
PPS: Либа работает тоже!
igrik
На счет void* - я не знаю. Баря знает, Сав и Феанор. Они программисты, а я так ... любитель. И Си узнал и использую ток в героях, хотя тут больше заслуга ERMa.
Для данной темы я использую С++ на студио 2008 + инклуд патчера.
И да, я обычно проверяю то что выкладываю. Поэтому и посещение библиотеки и округление скорости работают. Но для таких патчей обязательно нужна проверка на !мультиплеер.
feanor
Если что-то gcc-based, то там могут быть зловещие чудеса с сложным синтаксисом, да.
(точнее, это у студии зловещие чудеса, а гцц просто менее к ним терпим)
DedMorozzz
Попытался найти либу в idb файле. знаю адрес - 0x4A2F92. Но там вообще что попало. Никакого упоминания библиотеки. при этом ф-й которые содержат слово "library" уйма. В чём секрет?)
Вот к примеру для скорости есть такая функа "combatMonster_GetSpeed". Как по ней найти смещение? Знаю что искать надо 196, но ничего похожего не нашел

Туда же... Решил проверить на других эл-тах. Нашел метод "getMoraleBonus", как понять его смещение?

ЗЫ:
Вроде чёт нашел...
Код
int __stdcall changeMorale(LoHook* h, HookContext* c)
{
    float morale = (float)(*(int*)(c->ecx +114));
    c->eax = 2;
    return NO_EXEC_DEFAULT;
}

Код
_PI->WriteLoHook(0x4E3C3C, changeMorale);

Делает мораль = 2 всегда. В виде "временного бонуса"

Нашел его так:
в одном из мест вызывается "call GetMoralBonus"
Глянул там такая строка: mov ecx, Hero ; jumptable 004DB915 case 114
Предположил что 114 это сдвиг. Вроде завелось. Но могу предположить что на другой адрес надо ссылаться, если вешать минус мораль заклинанием. Но так хоть что-то нашел, что отработало)
В память об этом сделаю при посещении либы с дипломатией +1/2/3 морали, до след. битвы biggrin.gif
AlexSpl
Многие вопросы отпадают естественным образом, когда начинаешь разбираться, желательно с желанием smile.gif Вот это - "combatMonster_GetSpeed" и вот это - "call GetMoralBonus" - есть пример такой работы.

Цитата
Глянул там такая строка: mov ecx, Hero ; jumptable 004DB915 case 114

Естественно, это не оффсет. Это switch. Таблица как раз таки по адресу 004DB915 и расположена.

Нет универсальных решений. Поставьте брейкпоинт на входе известной Вам функции. Пройдите инструкции пошагово, обращая внимание на состояние регистров CPU, FPU, флаги и т.п. Попытайтесь разобраться, как она работает. Это же интересно smile.gif
feanor
Мне в реверсинге помогли:
1. Вузовский семестр архитектуры ЭВМ (т.е. х86 ассемблера).
2. Выцыганенная по случаю книжка В.Пирогова "Ассемблер и дизассемблирование". Не говорю, что она лучшая, но она неплоха и была доступна в бумаге. Сейчас есть на флибусте, точн.
3. Четыре года опыта по моддингу мобильников с применением реверс-инженеринга.
DedMorozzz
Цитата(AlexSpl @ 08 Dec 2016, 22:36) *
Многие вопросы отпадают естественным образом, когда начинаешь разбираться, желательно с желанием smile.gif Вот это - "combatMonster_GetSpeed" и вот это - "call GetMoralBonus" - есть пример такой работы.

Цитата
Глянул там такая строка: mov ecx, Hero ; jumptable 004DB915 case 114

Естественно, это не оффсет. Это switch. Таблица как раз таки по адресу 004DB915 и расположена.

Нет универсальных решений. Поставьте брейкпоинт на входе известной Вам функции. Пройдите инструкции пошагово, обращая внимание на состояние регистров CPU, FPU, флаги и т.п. Попытайтесь разобраться, как она работает. Это же интересно smile.gif

если это не оффсет, то я случайно угадал что сдвиг у бонуса морали 114?)

Ну вот опять спрашиваю - что такое брекпоинты (точки остановки), как их отслеживать, ставить...
Как я себе это вижу. Ставлю точку остановки на какой-то участок кода. Когда туда попадаем, я вижу все параметры какие у нас есть. И могу построчно пройти дальше
Но проблема в том, что я не код свой запускаю, а скомпилиную ДЛЛку. Выходит точки остановки нужно ставить в ДЛЛке...

И да. Игрик говорил что сделать что бы не ругалось на недостающие файлы. Я сразу не обратил внимание, но сейчас вижу что стабильно ругается
В самом верху прописано:
#include "..\..\patcher_x86.hpp"
Патчер на 2 уровня выше и лежит. Пробовал копировать в папку где h и hpp файлы лежат - не помогло
AlexSpl
Запись "case 114" предполагает наличие jumptable ("таблицы переходов"). Например, jumptable может выглядеть так:

dd 00402EA7h, 00402F15h, ..., 0DEADFADEh, ..., 00402F69h

Такая jumptable соответствует следующему псевдокоду высокого уровня:

switch ( Value ) {
case {A}: goto 0x402EA7;
case {B}: goto 0x402F15;
...
case {X}: goto 0xDEADFADE; smile.gif
...
default: goto 0x402F69;
}

, где {A}, {B}, {X} есть некоторые подмножества значений, которые может принимать Value.

* * *

Обычно в коде встречается что-то вроде этого:

Код
00402E8F   cmp  ecx, 1Ch; switch 29 cases
00402E92   ja   loc_402F69; jumptable 00402EA0 default case
00402E98   xor  edx, edx
00402E9A   mov  dl, ds:byte_402FE8[ecx]
00402EA0   jmp  ds:off_402FDC[edx*4]; switch jump


Здесь следующей после switch джампа jmp ds:off_402FDC[edx*4] будет выполнена инструкция по адресу из jumptable. 402FDCh есть адрес, по которому хранится jumptable, а значение регистра edx выступает в качестве индекса в этой таблице.

Индекс находится из таблицы типа такой (см. инструкцию mov dl, ds:byte_402FE8[ecx]):

Код
402FE8 (29 cases):
db      0,     0,     0,     0
db      0,     2,     2,     2
db      2,     2,     2,     2
db      2,     2,     2,     2
db      2,     1,     1,     1
db      1,     1,     2,     2
db      0,     0,     0,     0
db      0




Т.е. управление передаётся по адресу с соответствующим индексом:

Код
402FDC:
switch (byte ptr [402FE8h]) {
  case 0: dd offset loc_402EA7;
  case 1: dd offset loc_402F15;
  case 2: dd offset loc_402F69;
}


И jmp ds:off_402FDC[edx*4] превращается в:

jmp loc_402EA7 при edx = 0 (case 0);
jmp loc_402F15 при edx = 1 (case 1);
jmp loc_402F69 при edx = 2 (case 2, он же default).

Инструкции, на которые указывают такие джампы, комментируются в IDA следующим образом: "jumptable {адрес джампа} case {индекс}.
DedMorozzz
Цитата(AlexSpl @ 08 Dec 2016, 23:54) *
Индекс находится из таблицы типа такой (см. инструкцию mov dl, ds:byte_402FE8[ecx]):

Код
402FE8 (29 cases):
db      0,     0,     0,     0
db      0,     2,     2,     2
db      2,     2,     2,     2
db      2,     2,     2,     2
db      2,     1,     1,     1
db      1,     1,     2,     2
db      0,     0,     0,     0
db      0


Код
402FDC:
switch (byte ptr [402FE8h]) {
  case 0: dd offset loc_402EA7;
  case 1: dd offset loc_402F15;
  case 2: dd offset loc_402F69;
}


И jmp ds:off_402FDC[edx*4] превращается в:

jmp loc_402EA7 при edx = 0 (case 0);
jmp loc_402F15 при edx = 1 (case 1);
jmp loc_402F69 при edx = 2 (case 2, он же default).

Инструкции, на которые указывают такие джампы, комментируются в IDA следующим образом: "jumptable {адрес джампа} case {индекс}.

В данном примере, комментарий такой: "jumptable 00402EA0 cases 5-16,22,23"



Значить будут пройдены все кейсы с 5 по 16 и 22 и 23?
Но всё равно не ясно:

"]
Код
.text:00402FE8 byte_00402FE8       db      0,     0,     0,     0         ; DATA XREF: MouseClick_AdvMap+2Ar
.text:00402FE8                     db      0,     2,     2,     2         ; indirect table for switch statement
.text:00402FE8                     db      2,     2,     2,     2
.text:00402FE8                     db      2,     2,     2,     2
.text:00402FE8                     db      2,     1,     1,     1
.text:00402FE8                     db      1,     1,     2,     2
.text:00402FE8                     db      0,     0,     0,     0
.text:00402FE8                     db      0
.text:00403005                     align 10h


далее видим - jmp ds:off_00402FDC[edx*4]
Соотв взять 4й или 5й кейс. Если с 0 отсчёт. В данной таблице значение = 0 хоть для 4 хоть для 5.

Далее видим следующее:
Код
.text:00402FDC off_00402FDC        dd offset b402FDC_case15_19_39_43      ; DATA XREF: MouseClick_AdvMap+30r
.text:00402FDC                     dd offset b402FDC_case32_36            ; jump table for switch statement
.text:00402FDC                     dd offset b402FDC_caseOther

У нас кейс = 0. Значит берём 1й, т.е. b402FDC_case15_19_39_43. Но мне кажется тут у нас уже не кейсы...

Или попадаем в caseOther. т.к. для 0 нет кейса. Но всё равно не ясно как для 0 тогада он выглядил бы (ибо сейчас подгоняю под результат скорее)

Код
.text:00402F69; ---------------------------------------------------------------------------
.text:00402F69
.text:00402F69 b402FDC_caseOther:                                         ; CODE XREF: MouseClick_AdvMap+22j
.text:00402F69                                                            ; MouseClick_AdvMap+30j
.text:00402F69                                                            ; DATA XREF: ...
.text:00402F69                     push    eax                            ; default
.text:00402F69                                                            ; jumptable 00402EA0 cases 5-16,22,23
.text:00402F6A                     mov     ecx, esi
.text:00402F6C                     call    ParseMouseClickItem_AdvMap     ; Call Procedure
.text:00402F71                     test    eax, eax                       ; Logical Compare
.text:00402F73                     jge     short loc_00402F80             ; Jump if Greater or Equal (SF=OF)
.text:00402F75                     pop     edi
.text:00402F76                     pop     esi
.text:00402F77                     xor     al, al                         ; Logical Exclusive OR
.text:00402F79                     pop     ebx
.text:00402F7A                     mov     esp, ebp
.text:00402F7C                     pop     ebp
.text:00402F7D                     retn    4                              ; Return Near from Procedure
.text:00402F80; ---------------------------------------------------------------------------


Тут джамп тейбл с нужными нам кейсами. Но что дальше происходит - не ясно, кроме как возврат 4ки
AlexSpl
Сложно как-то прокомментировать написанное выше.

Цитата
Но что дальше происходит - не ясно, кроме как возврат 4ки


Это не возврат 4-ки smile.gif retn 4 "выталкивает" из стека адрес возврата и 4 байта, которые занимает аргумент, переданный функции через стек, после чего передаёт управление инструкции, которая находится по адресу возврата.

Например,

Код
push    edi
.text:004089B5                 call    sub_402E70
.text:004089BA                 test    al, al


Здесь функции sub_402E70 передаётся аргумент через стек (edi, 4 байта). Иструкция call sub_402E70 помещает в стек адрес возврата (в данном случае 4089BAh) и передаёт управление по адресу 402E70h. retn 4, соответственно, выталкивает адрес возврата и аргумент из стека и передаёт управление по адресу возврата (инструкция test al, al).
DedMorozzz
Пока что ещё запутано как-то выглядит)

Лано, вопрос конкретный появился. Не могу сделать +1/2/3 морали для след. битвы после посещения либы с дипломатией. Точнее просто если есть дипломатия - сделать +2 морали. Цифры сам подправлю
Сделать постоянно +2 - выше показал как. (но только при return NO_EXEC_DEFAULT; с вызовом дефолтного метода, не работает +2)
А вот после посещения - не получается... делал так, 2 варианта:

это всегда есть
Код
int __stdcall changeMorale(LoHook* h, HookContext* c)
{
    c->eax += 2;
    return EXEC_DEFAULT;
}


Код
_PI->WriteLoHook(0x4A2F92, libraryVisit);


1.

libraryVisit code:
Код
int __stdcall libraryVisit(LoHook* h, HookContext* c)
{
/// library code here
        
        *(int*)0x4E3C3C = (int)changeMorale;
    }
    return EXEC_DEFAULT;
}



2.
libraryVisit code:
Код
int __stdcall libraryVisit(LoHook* h, HookContext* c)
{
/// library code here
        
_P = GetPatcher();
_PI = _P->GetInstance("HD.Plugin.DedMorozzz");
_PI->WriteLoHook(0x4E3C3C, changeMorale);

    }
    return EXEC_DEFAULT;
}



Игра вылетает при любом раскладе, после посещения/открытия окна героя

Как сделать временный бонус к морали?
AlexSpl
Значение морали не может быть больше +3 или меньше -3.

Я не знаю, корректен ли код выше вообще, но это

Код
c->eax += 2;

точно неправильно.
DedMorozzz
не в этом дело. Герой которым посещая либу с нулевой моралью..
Да и "рабочий" вариант, всегда +2 морали делает +5 у героя в сумме(в бою ещё больше). Просто учитывается только 3.
Банальный пример. Эксперт лидерство и архангел. Уже больше 3х. Просто в бою не важно +3 или +15 морали

В чём у меня ошибка. Как задать +2 морали при посещении либы?
AlexSpl
Насколько я помню, бонусы морали хранятся отдельно от значения морали в структуре героя. И есть функция (типа GetMorale), которая каждый раз считает мораль (проходит по артам, бонусам от объектов).
AlexSpl
Костыль, или решение в лоб. Т.к. бонус морали от посещения Библиотеки предполагается сделать временным, то этот бонус можно добавить к бонусу за посещение Фонтана Молодости, например. Коду, который обнуляет временные бонусы, пофиг.

P.S. Это в случае, если подобные бонусы не хранятся в битовом поле. Нужен, как минимум байт, чтобы работало. Ну и, естественно, по правому клику не увидишь, что была посещена именно Библиотека.
igrik
Цитата(DedMorozzz @ 11 Dec 2016, 17:59) *
Лано, вопрос конкретный появился. Не могу сделать +1/2/3 морали для след. битвы после посещения либы с дипломатией. Точнее просто если есть дипломатия - сделать +2 морали. Цифры сам подправлю
Как сделать временный бонус к морали?

Просто добавь в ту функцию хука в библиотеке
Код
*(char*)(c->esi + 1145) += bonnus;        // прибавка к знаниям
*(char*)(c->esi + 282) += 2;                // +2 временно до следующей битвы


upd: упсс, подправил *(int*) y на *(char*).
AlexSpl
Цитата
Код
*(int*)(c->esi + 282) += 2;                // +2 временно до следующей битвы

Прокомментируйте, пожалуйста. +2 к чему добавляется?
igrik
к морали

Вот структура героя, указанная feanor'om, если че.
Ах блин, там же байт. Исправил.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2025 IPS, Inc.