Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Мод на ХотА
DF2 :: ФОРУМЫ > Игровые форумы > Heroes of Might & Magic III > Моды
Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
DedMorozzz
Итого, получается если я захочу проверить есть ли атака без ответа, тогда я 1ю часть оставлю ту же (т.е. получить флаги существа) а вот маску другую буду использовать
Т.е. вида:
bool newVal = *(int*)(c->ecx + 0x84) & 0x*****;
DedMorozzz
Форум ожил!! smile.gif
Всех с прошедшим НГ!

У меня возникло несколько вопросов:
1. Нашел неприятный баг с кодом молитвы. Почему-то вылетало, играли 3м на хотсите. При атаке юнитов, без какой либо магии - вылетало
Только эльф стрелял в пирата - всё, игра вылетала. Закоментив код молитвы, стало всё ок
Используемый код:
Код
int __stdcall spellPrayBonus(LoHook* h, HookContext* c)
{
    int spellDuration = *(int*)(c->ecx + 0x258); // Prayer
    bool isUndead = *(int*)(c->ecx + 0x84) & 0x40000;
    if (spellDuration != 0 && !isUndead) { // проверяем Prayer и бит Undead
        c->eax = 1;
    }

    return EXEC_DEFAULT;
}


Код
_PI->WriteLoHook(0x442F6A, spellPrayBonus);

Что не так с кодом?

При этом повторить баг сейчас не удаётся (сейва нема того ): )

2. Как можно получить максимальные и текущие ХП юнита?
Я так понял что + 192 это максимальные. А текущие не нашел...
Что хочу сделать - палатка что бы кроме хила накидывала щит на левел юнита * 20
Т.е. делала так: текущиее хп = максимальное ХП + левел юнита * 20
На примере ангела получится 200+140 = 340. Но что бы максимальное ХП не менялось
AlexSpl
Цитата
Что не так с кодом?

При этом повторить баг сейчас не удаётся (сейва нема того ): )

Почему думаете, что проблема именно в этом коде? Он всего лишь решает, возвращать максимальный базовый урон или же рандомный.

Цитата
2. Как можно получить максимальные и текущие ХП юнита?
Я так понял что + 192 это максимальные. А текущие не нашел...

В структуре стека нет текущих HP, есть вот что:
Код
_int32_ lost_hp;  // +88 0x58 потери здоровья последнего монстра
DedMorozzz
Цитата(AlexSpl @ 20 Jan 2017, 00:54) *
Цитата
Что не так с кодом?

При этом повторить баг сейчас не удаётся (сейва нема того ): )

Почему думаете, что проблема именно в этом коде? Он всего лишь решает, возвращать максимальный базовый урон или же рандомный.

Цитата
2. Как можно получить максимальные и текущие ХП юнита?
Я так понял что + 192 это максимальные. А текущие не нашел...

В структуре стека нет текущих HP, есть вот что:
Код
_int32_ lost_hp;  // +88 0x58 потери здоровья последнего монстра



1. Почему думаю что проблем там - потому что был сейв перед нападением на мобов (это сомневаюсь что важно, но 1й день был). И игра вылетала
Пробовали убирать ПВП режим - всё равно вылетала. Закоментил эту строчку "_PI->WriteLoHook(0x442F6A, spellPrayBonus);" и вылетать перестало
Может совпадение, но суммарно 3 раза вылетело. А без этой строки за всю игру не вылетело ниразу, и на тех же мобах, на которых до этого выкидывало

2. Эх, тогда всё усложнится)
Надо будет попробовать задать отрицательное значение, вдруг заведётся, но слабо верю в это
Если не выйдет то вижу следующий алгоритм:
Пробовать буду задавая +100 всем и для простоты сделать так, что бы щит сбивался от любого урона. Иначе тяжело будет просчитать

1) Задать максимальное ХП = текущиее макс + 100
2) Отредачить ф-ю получения урона. К примеру юнит получает 300 урона, тогда беру макс ХП и отнимаю 100. От наносимого урона отнимаю тоже 100
Если наносимый урон 40. То скорее всего так: от макс хп отнимаю 100. наносимый урон делаю =1 (насколько я знаю меньше 1го нельзя)
Ну или просто перекинуть на адрес когда урон уже нанёсся. Тогда и с еденицей не будет проблем

Так же можно попробовать и без сбивания щита от любой атаки, если участь "_int32_ lost_hp; // +88 0x58",если корректно будет возвращать инфу. Но это явно на 2й этап оставить smile.gif
AlexSpl
Цитата
1. Почему думаю что проблем там - потому что был сейв перед нападением на мобов (это сомневаюсь что важно, но 1й день был). И игра вылетала
Пробовали убирать ПВП режим - всё равно вылетала. Закоментил эту строчку "_PI->WriteLoHook(0x442F6A, spellPrayBonus);" и вылетать перестало
Может совпадение, но суммарно 3 раза вылетело. А без этой строки за всю игру не вылетело ниразу, и на тех же мобах, на которых до этого выкидывало

Попробуйте поймать баг снова. В сообщении об ошибке будет указан адрес инструкции, которая привела к вылету. А крэш-лог в папке логов сохранился? Ещё можно поменять spellDuration != 0 на spellDuration > 0, но это вряд ли причина вылета.

Цитата
2. Эх, тогда всё усложнится)
Надо будет попробовать задать отрицательное значение, вдруг заведётся, но слабо верю в это

Почему нет? Должно работать.
DedMorozzz
Цитата(AlexSpl @ 20 Jan 2017, 17:39) *
Попробуйте поймать баг снова. В сообщении об ошибке будет указан адрес инструкции, которая привела к вылету. А крэш-лог в папке логов сохранился? Ещё можно поменять spellDuration != 0 на spellDuration > 0, но это вряд ли причина вылета.


Вроде он, но там не всё ясно) В аттаче логНажмите для просмотра прикрепленного файла
AlexSpl
Не похоже на эффект молитвы )

Такая ошибка только при стрельбе случается.

Цитата
.text:0043FB0D mov eax, [esi+1Ch]

Случаем, нет хуков в окрестности адреса 43FB0D?
DedMorozzz
Цитата(AlexSpl @ 20 Jan 2017, 22:25) *
Не похоже на эффект молитвы )

Такая ошибка только при стрельбе случается.

Цитата
.text:0043FB0D mov eax, [esi+1Ch]

Случаем, нет хуков в окрестности адреса 43FB0D?

Да вроде нема...
В общем раскоментил эту строку(функа с молитвой). Вчера партейку сыграли, всё ок. И молитва от джина кастанулась - тоже с корректными бонусами вышла smile.gif Хз почему падало
Сёня попробую с палаткой сделать, с отрицательным значением, а пока что решил изменить шансы выпадения минималок/максималок в банках
Было 30%-30%-30%-10%, переделал на 15%-35%-35%-15%, всё работает (для проверки ставил некоторым 100% на максималку, некоторым 100% на минималку и так далее)
Но вот для ХОТОвских объектов не могу задать, ибо в файлике они отсутствуют. Где их найти и отредачить? Аля консерва циклопов (волки охраняют циколопв), консерва гигантов и т.д.

----------------------------------------

С палаткой не вышло...
Ставил брейк поинты на +88. Как делал:
8002EF8h + 12708 + 88
134229752 + 12708 + 88 = 134242548 (80060F4)
На 80060F4 поставил брейк поинт. Настройки точки остановки - https://sc-cdn.scaleengine.net/i/b588218813...02e81107792.png

При наведении палаткой на юнита попадаю сюда - HD_HOTA.dll:02926811 jmp short loc_029267F2
в конце этой функи - HD_HOTA.dll:029267F2 loc_029267F2:

На врага то же самое. Не палаткой, а любым юнитом в то же место попадаю. Как всё же понять какой адресс отвечает за хил юнита, что бы изменить значение потеряного здоровья при хиле
AlexSpl
Всё правильно делаете. Только брейкпоинт на запись ставить нужно. Этот брейкпоинт будет срабатывать каждый раз, когда отряд будет получать урон или лечиться.

Цитата
Но вот для ХОТОвских объектов не могу задать, ибо в файлике они отсутствуют. Где их найти и отредачить? Аля консерва циклопов (волки охраняют циколопв), консерва гигантов и т.д.

Скорее всего, такие вещи хранятся в HotA.dat. Вот тут ещё почитайте.
DedMorozzz
Цитата(AlexSpl @ 22 Jan 2017, 16:24) *
Всё правильно делаете. Только брейкпоинт на запись ставить нужно. Этот брейкпоинт будет срабатывать каждый раз, когда отряд будет получать урон или лечиться.

Цитата
Но вот для ХОТОвских объектов не могу задать, ибо в файлике они отсутствуют. Где их найти и отредачить? Аля консерва циклопов (волки охраняют циколопв), консерва гигантов и т.д.

Скорее всего, такие вещи хранятся в HotA.dat. Вот тут ещё почитайте.

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

Насчёт HotA.dat - не помогло, там текстовик обычный. Не нашел процентов прока минималок-максималок
Причём файлик небольшой. Мб не тем открываю. Гуглю как дат файлы открыть ибо MM Archive ток текст показывает...
AlexSpl
Цитата
Ну да... то я тупанул, но не помогло. Брейк поинт срабатывает только перед началом боя. И всё. И получение урона и восстановление хп палаткой - не вызывает его

Попробуйте пересчитать адрес. Он меняется каждый раз. А старые брейкпоинты на память нужно удалять.

Цитата
Насчёт HotA.dat - не помогло, там текстовик обычный. Не нашел процентов прока минималок-максималок
Причём файлик небольшой. Мб не тем открываю. Гуглю как дат файлы открыть ибо MM Archive ток текст показывает...

Это бинарный файл. Почитайте ту темку. Там палатку тоже разбирали.


Ещё проценты могут быть в HotA.dll.
DedMorozzz
Ну да, само собой, под новые значения менял все. Сейчас ещё раз пересчитал. То же самое

А в теме вижу разбор смены кол-ва хила. Это не трудно изменить. По одинаковому принципу все навыки работают
Я то хочу логику изменить. Прочитал 6 страниц не нашел инфы никакой, какая функа отвечает за это
AlexSpl
Я знаю, почему у Вас не получается. Вы прибавляете не то число к адресу combatManager. Нужно 21708. Наверняка посмотрели мой пост с опечаткой.
DedMorozzz
Цитата(AlexSpl @ 23 Jan 2017, 21:12) *
Я знаю, почему у Вас не получается. Вы прибавляете не то число к адресу combatManager. Нужно 21708. Наверняка посмотрели мой пост с опечаткой.

Действительно! Не верное число прибавлял.

Но не помогло...
Для (G)699420, такое значение 7F02EF8
Его перевёл в инт. Получил 133181176. Далее так
133181176 + 21708 + 88 // 7F0841C
На 7F0841C поставил брейк поинт. Который срабатывает только в начале боя. единожды
Получение/нанесение урона, так же отхил палаткой - не вызывает точку остановки

PS: а как понять куда точку остановки ставить для героя на карте? К примеру хочу понять какая ф-я вызывается при посещении +1 к статам за 1к голды
Комбат менеджер не поможет тут, как я понимаю
AlexSpl
Цитата
Получение/нанесение урона, так же отхил палаткой - не вызывает точку остановки

Значит, у Вас где-то ошибка. Только что проверил - работает. Тестировать нужно на самом верхнем отряде атакующей стороны. Если проверяете на другом, нужно ставить брейкпоинт по другому адресу (см. полную формулу).

Цитата
К примеру хочу понять какая ф-я вызывается при посещении +1 к статам за 1к голды

Брейкпоинт на статы в структуре героя ставьте.

Структуры героев в ХотА перенесли. Особо не разбирался, но найти адрес героя с ID = heroID можно, например, так:

*(int*)0x699538 + *(int*)0x419440 + heroID * 0x492,
где *(int*) - двойное слово по указанному адресу ([G]o -> 699538h, [G]o -> 419440h).

* * *
Вот, например, восстановление здоровья палаткой:
Код
.text:00478552 mov     [esi+58h], ecx

Проверял на автохиле.
igrik
Цитата(DedMorozzz @ 24 Jan 2017, 21:17) *
PS: а как понять куда точку остановки ставить для героя на карте? К примеру хочу понять какая ф-я вызывается при посещении +1 к статам за 1к голды
Комбат менеджер не поможет тут, как я понимаю

Можно выйти и без брейкпоинта.
Функция посещения объекта героем 0x4A8160. Там большой свитч на номера объектов. Открываем ERM-help -> Таблицы -> Объекты: номера. Находим школу войны. Номер объекта =107. В Иде в ищем "case 107:" и выходим на sub_004A76B0. Вуаля.
DedMorozzz
Цитата
Вот, например, восстановление здоровья палаткой:

Код
int __stdcall setFirstAidShield(LoHook* h, HookContext* c)
{
    //c->eax = *(char*)(c->esi + 88) - 100;
    c->eax = 10;
    
    c->return_address = 0x47858F;
    return NO_EXEC_DEFAULT;
}

Код
_PI->WriteLoHook(0x478552, setFirstAidShield);


Хоть хардкодом задать недостающее хп (по крайней мере я так думаю, что это делаю smile.gif ) хоть уменьшив недостачу на сотку. При хиле - вылетает

Цитата
Функция посещения объекта героем 0x4A8160. Там большой свитч на номера объектов. Открываем ERM-help -> Таблицы -> Объекты: номера. Находим школу войны. Номер объекта =107. В Иде в ищем "case 107:" и выходим на sub_004A76B0. Вуаля.

Хм... Захожу в 0x4A8160
Начинаю искать ниже "case 107"
Код
.text:004AA3C5; ---------------------------------------------------------------------------
.text:004AA3C5
.text:004AA3C5 loc_004AA3C5:                                              ; CODE XREF: Enter2ObjectMain+4Aj
.text:004AA3C5                                                            ; DATA XREF: .text:off_004AA454o
.text:004AA3C5                     mov     ecx, dword ptr [ebp+PosMixed+4]; jumptable 004A81AA case 107
.text:004AA3C8                     mov     edx, [ebp+Hero]
.text:004AA3CB                     push    ecx
.text:004AA3CC                     push    edi
.text:004AA3CD                     push    edx
.text:004AA3CE                     mov     ecx, esi
.text:004AA3D0                     call    sub_004A7A50                   ; Call Procedure
.text:004AA3D5                     pop     edi
.text:004AA3D6                     pop     esi
.text:004AA3D7                     pop     ebx
.text:004AA3D8                     mov     ecx, [ebp+var_C]
.text:004AA3DB                     mov     large fs:0, ecx
.text:004AA3E2                     mov     esp, ebp
.text:004AA3E4                     pop     ebp
.text:004AA3E5                     retn    10h                            ; Return Near from Procedure
.text:004AA3E8; ---------------------------------------------------------------------------


И ф-я sub_004A7A50 находится.. чёт не так делаю?
AlexSpl
Хук на 47854Dh:

Код
int __stdcall setFirstAidShield(LoHook* h, HookContext* c)
{
    c->eax += extra_hp; // палатка лечит обычное кол-во HP (eax), сверху добавляем extra_hp
    
    return EXEC_DEFAULT;
}


Но "щит" не получится так сделать: в следующем раунде (скорее всего так), избыток текущих HP будет пересчитан (получим воскрешение воинов в отряде).

DedMorozzz
так это получается усиление хила палатки. А не уменьшение недостающего здоровья у отряда?
AlexSpl
А тут без разницы. Дальше это значение вычитается из недостающих HP верхнего существа в стеке, потенциально делая значение отрицательным, что и должно давать щит. Но все алгоритмы предполагают, что текущее HP не может быть больше максимального. В итоге получаем пересчёт, причём довольно глючный.

Вот ещё нашёл:
Код
_int32_ full_hp;  // +108 0x6C полное здоровье (исп. как база для лечения)



Короче, чтобы нормально сделать такой щит, нужно завести ещё одно поле в структуре и корректно его обрабатывать при получении урона/лечении.
igrik
Цитата(DedMorozzz @ 25 Jan 2017, 23:03) *
И ф-я sub_004A7A50 находится.. чёт не так делаю?

Ну нажми ты "Tab" или "F5" в конце концов.

И да, ошибся я. Школа войны это функция sub_004A76B0.
109 это водяное колесо.
Код
    case 107:
      sub_004A76B0((void *)v6, (int)Hero, v5, SBYTE4(PosMixed));
      return;
    case 108:
      sub_004A78A0(Hero, (void *)v5, SBYTE4(PosMixed));
      return;
    case 109:
      sub_004A7A50((int)Hero, (void *)v5, SBYTE4(PosMixed));
      return;
    case 110:
      sub_004A7B10((void *)v6, (int)Hero, v5, SBYTE4(PosMixed));
      return;
    case 112:
      sub_004A7C30((int)Hero, (void *)v5, SBYTE4(PosMixed));
AlexSpl
Код
//_int_ cost_wood;  //+148 0x94
//_int_ cost_mercury;  //+152 0x98
//_int_ cost_ore;  //+156 0x9C
//_int_ cost_sulfur;  //+160 0xA0
//_int_ cost_crystal;  //+164 0xA4
//_int_ cost_jems;  //+168 0xA8

Такой вопрос. Понятно, что в бою вышеприведённые поля структуры _CreatureInfo_ стека не используются (перед боем, я полагаю, они просто копируются в _BattleStack_). А после боя? Копируются ли они обратно? Если нет, то у нас есть целых 6 полей, которые можно использовать для своих нужд. На тот же "щит здоровья".

Тогда реализация "щита здоровья" была бы элементарной (без визуальной части, естественно). Хук на хил. При соблюдении определённых условий (уровень First Aid и т.п.) пишем хп щита в одно из этих полей. Далее, второй хук на получение урона (или несколько, если дамаг в нескольких местах учитывается). Там просто вычитаем дамаг из щита. Единственное, нужна визуализация, иначе получится, что отряд ударили, а он не потерял HP. Нужно хотя бы в логе писать типа "%d hit points absorbed by Divine Shield" smile.gif
DedMorozzz
Не понятно ток как можно будет понять что на юните висит щит. И сколько он поглотит урона. Эти же хар-ки не пишутся в стеке юнита
Хоть это и не самая большая проблема, если в логе это отображать
AlexSpl
Можно в окне информации об отряде в скобках отображать (рядом с текущими хитами, например).

Код палатки:
Код
int __stdcall setFirstAidShield(LoHook* h, HookContext* c)
{
    *(int*)(c->esi + 0x94) += hpShieldBonus;
    
    return EXEC_DEFAULT;
}


Код на дамаг посложнее будет. Ещё при инициализации стека сбрасывать древесину на 0 smile.gif
DedMorozzz
т.е. там строка а не число?
но в целом ок идея. По аналогии с макс хп, когда в скобках пишется текущее хп, после яда или старения
Да.. вполне информативно должно получится. Но для начала надо будет проверить как вообще этот щит сделать.
Вывод информации это уже самый последний этап

PS: код на дамаг, по сути то же самое. ток в начале добавися такой код:
1. получить значение щита
2. сравнить что больше щит или урон
2.1 если урон то из урона вычесть значение щита. Щит обнулить
2.2 если щит, то из щита вычесть значение урона. Значение урона сделать = 1
2.3 если одинаково, то обнулить щит и урон сделать = 1

урон = 1 для того что бы была анимация получения урона и избежать возможных проблем слогикой
AlexSpl
Попробуйте сначала этот хук. Посмотрите, не появилась ли у отряда стоимость в древесине после боя. Если нет, всё ОК, и можно продолжать smile.gif
DedMorozzz
Цитата(AlexSpl @ 26 Jan 2017, 00:16) *
Попробуйте сначала этот хук. Посмотрите, не появилась ли у отряда стоимость в древесине после боя. Если нет, всё ОК, и можно продолжать smile.gif

Проверил, хил на ангеле отработал. После боя никаких изменений не увидел

Пробовал этот код:
Код
int __stdcall setFirstAidShield(LoHook* h, HookContext* c)
{
    *(int*)(c->esi + 0x94) += 50;
    
    return EXEC_DEFAULT;
}


Хук на этот адрес:
Код
_PI->WriteLoHook(0x478552, setFirstAidShield);
AlexSpl
Значит, всё ОК. Юнитов, которые требуют дерево, нет. Даже если бы и были, можно сбрасывать стоимость на 0, но это уже второстепенно. Теперь ставьте брейкпоинт с предыдущей страницы и ловите урон.

Короче, вот: sub_443DB0.

Хук на 443DBBh. c->ecx - урон, c->esi - указатель на стек. Осталось только Ваш алгоритм реализовать smile.gif

Цитата
1. получить значение щита
2. сравнить что больше щит или урон
2.1 если урон то из урона вычесть значение щита. Щит обнулить
2.2 если щит, то из щита вычесть значение урона. Значение урона сделать = 1
2.3 если одинаково, то обнулить щит и урон сделать = 1

урон = 1 для того что бы была анимация получения урона и избежать возможных проблем слогикой


Это милишный урон, если есть разница. Но если есть, для тестов попробуйте пока это:

Код
int __stdcall absorbDamage(LoHook* h, HookContext* c)
{
    // code here
    
    return EXEC_DEFAULT;
}
AlexSpl
Ну и сразу мысли наперёд:
1. Нужно исключить abuse палатки. Она будет добавлять щит, пока у отряда есть потерянные HP, причём даже тогда, когда щит уже висит. Посему нужно исключить повторное наложение щита в предыдущем хуке (оставить только лечение, если щит > 0).
2. Аккуратно с этим:
Цитата
урон = 1 для того что бы была анимация получения урона и избежать возможных проблем слогикой

Эта единица должна отниматься и от текущих хп. Т.е. если щит толще, чем урон, урон отнимается от щита, а 1-ца - от текущих хитов отряда.

Код
if ( c->ecx <= *(int*)(c->esi + 0x94) ) {
    *(int*)(c->esi + 0x94) -= c->ecx;
    c->ecx = 1;
};
else {
    c->ecx -= *(int*)(c->esi + 0x94);
    *(int*)(c->esi + 0x94) = 0;
}
DedMorozzz
Круто, работает!
Терь надо силу щита менять в зависимости от левела юнитов. Что бы на 1е левела щит кидало слабее, на топ левела сильнее
Пока что думаю так 25*левел = щит
Какие нить гнолы получаю 25 абсорба. Ангел - 175
Нашел такую штуку - _int32_ creature_id; // +52 0x34 // тип монстра
Но это скорее всего айди юнита, аля гарпия, гнол, ифрит...
А как левел отряда получить?
Потенциально можно самому таблицу составить по ЕРМ хелперу, чёт думается можно и проще

И да.. как менять описание? Что бы к текущему хп добавить в скобках(в идеале квадратных []) размер щита? Понравилась эта идея)

PS: а насчёта абуза, то я думаю щит не прибавлять, а всегда делать новый. И хоть 100 раз на юнита кастануть щит, он больше не поглотит
DedMorozzz
---------------------------------------------
Придумал как. Юниты идут по порядку. Сперва замок, далее оплот и так далее
Взять айди юнита и разделить на 14 и взять целую часть.
Далее умножаем 14 на эту целую часть и это число вычитаем из айди отряда добавив еденицу. Еденица нужна т.к. начинается отсчёт с 0

Пример. айди = 16. Это гном
16 делим на 14 получаем 1+
Далее 16+1 - 14 = 3
Значит это 3й юнит по списку. Далее делю ещё раз на 2 (улучшеных и не улучшеных что бы пропустить) и округляю в большую сторону - это и есть левел отряда
в данном случа 3/2 = 1+. После округления = 2

Это конечно не будет работать как надо со спец юнитами, ну и чёрт с ними)
AlexSpl
Цитата
А как левел отряда получить?
Потенциально можно самому таблицу составить по ЕРМ хелперу, чёт думается можно и проще

Код
//_int_ level;  //+120 0x78

*(int*)(c->esi + 0x78).

Цитата
И да.. как менять описание? Что бы к текущему хп добавить в скобках(в идеале квадратных []) размер щита? Понравилась эта идея)

Тут брейкпоинт на чтение нужно ставить на потерянные HP (cmAddr + 21708 + 88).

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

Да. Наверное, это оптимальное решение.
AlexSpl
По поводу отображения щита. Хук на 5F64AFh. Для начала проверьте, будет ли работать такой код:

Код
{
    sprintf((char*)0x697428, "%d [%d]", *(int*)(c->ebp + 8), *(int*)(c->ebp + 8));

    c->return_address = 0x5F64C2;
    return NO_EXEC_DEFAULT;
}


Должен отображать остаток здоровья. Например, 300 [300]. Адрес щита из combatManager получить можно.

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

Код
{
    int unitAddr = *(int*)(c->ebp - 0x20);    
    sprintf( (char*)0x697428, "%d [%d]", *(int*)(c->ebp + 8), *(int*)(unitAddr + 0x94) );

    c->return_address = 0x5F64C2;
    return NO_EXEC_DEFAULT;
}
AlexSpl
Можно сделать, чтобы когда щита нет, здоровье отображалось, как обычно:

Код
{
    int unitAddr = *(int*)(c->ebp - 0x20);    // получаем адрес отряда, чьё информационное окно смотрим
    int hpShieldValue = *(int*)(unitAddr + 0x94);    // получаем значение щита

    if ( hpShieldValue > 0 ) {
        sprintf( (char*)0x697428, "%d [%d]", *(int*)(c->ebp + 8), hpShieldValue );    // отображаем остаток_здоровья [щит]
    };
    else return EXEC_DEFAULT;    // отображаем по умолчанию: остаток_здоровья

    c->return_address = 0x5F64C2;
    return NO_EXEC_DEFAULT;
}
DedMorozzz
Цитата
1>.\dllmain.cpp(578) : error C3861: 'sprintf': identifier not found

такая штука. Как я понял разные форматы в вижуал студии юзаются. Пробую плфиксать
AlexSpl
Попробуйте добавить инклуд #include "stdafx.h"
DedMorozzz
то же самое

Не хватало - #include <stdio.h>

PS: но вылетет при просмотре юнита после хила
AlexSpl
A если sprintf закомментить?
DedMorozzz
всё равно вылетает.
Попробова задать hpShieldValue = 10. Вылетет тоже. Походу из-за c->return_address = 0x5F64C2;
AlexSpl
Я на SoD смотрел. Счас HotA гляну.

А так вылетает?
Код
{
    int unitAddr = *(int*)(c->ebp - 0x20);    // получаем адрес отряда, чьё информационное окно смотрим
    int hpShieldValue = *(int*)(unitAddr + 0x94);    // получаем значение щита

    sprintf( (char*)0x697428, "%d", *(int*)(c->ebp + 8) );
    
    c->return_address = 0x5F64C2;
    return NO_EXEC_DEFAULT;
}
AlexSpl
Посмотрел. Дело в указателе на стек esp. Так пробуйте:

Код
{
    int unitAddr = *(int*)(c->ebp - 0x20);    // получаем адрес отряда, чьё информационное окно смотрим
    int hpShieldValue = *(int*)(unitAddr + 0x94);    // получаем значение щита

    if ( hpShieldValue > 0 ) {
        sprintf( (char*)0x697428, "%d [%d]", *(int*)(c->ebp + 8), hpShieldValue );    // отображаем остаток_здоровья [щит]
    };
    else return EXEC_DEFAULT;    // отображаем по умолчанию: остаток_здоровья

    с->esp -= 12;    // adjust esp*
    c->return_address = 0x5F64C2;
    return NO_EXEC_DEFAULT;
}


* Посмотрите этот код, а именно последнюю инструкцию:
Код
mov     eax, [ebp+arg_0]
push    eax
push    offset aD    ; "%d"
push    offset Text; char *
call    _sprintf
push    50h    ; unsigned int
call    operator new(uint)
add     esp, 16


Заметьте, что непосредственно _sprintf стек не освобождает, как и operator new(uint). Это делает инструкция add esp, 16 за обе(!) функции (3 аргумента dword функции _sprintf и один аргумент dword оператора new: 3 * 4 + 4 = 16. Поэтому если мы скипуем оригинальный код, мы должны поправить и указатель стека esp, чтобы инстукция add esp, 16 отрабатывала корректно.
DedMorozzz
Цитата
Заметьте, что непосредственно _sprintf стек не освобождает, как и operator new(uint). Это делает инструкция add esp, 16 за обе(!) функции (3 аргумента dword функции _sprintf и один аргумент dword оператора new: 3 * 4 + 4 = 16. Поэтому если мы скипуем оригинальный код, мы должны поправить и указатель стека esp, чтобы инстукция add esp, 16 отрабатывала корректно.

ух.. вроде понятно. Но только после объяснения. Да и то, как-то не очевидно)

Подправлю текст "Текущее здоровье" на что нить поменьше, аля "текущее хп", ибо не влазит) Текст друг на друга налазит. Как раз в ММ архиве пытаюсь найти где он лежит (а я надеюсь он именно там) и постараюсь до конца осознать почему и как выше происходит smile.gif
AlexSpl
Цитата
ух.. вроде понятно. Но только после объяснения. Да и то, как-то не очевидно)

Есть функции, которые сами "чистят" стек от аргументов, а есть такие, которые этого не делают. Вышеприведённый код равносилен следующему:

Код
mov     eax, [ebp+arg_0]
push    eax
push    offset aD   ; "%d"
push    offset Text; char *
call    _sprintf
add     esp, 12; почистили за _sprintf
push    50h   ; unsigned int
call    operator new(uint)
add     esp, 4; почистили за operator new(uint)


Но компилятор оптимизирует. Так, инструкция add esp, x необязательно следует непосредственно за функцией и может корректировать указатель на стек сразу для нескольких функций.
DedMorozzz
другими словами инструкция add гооврит что надо свободить в переменной(?) esp стек аргументов и сместить указатель назад на кол-во освобождённых аргументов (умноженных на 4). Верно?
И да, переименовал "Текущее здоровье", в "Текущее хп". Теперь и кол-во здоровья и щит в скобках корректно влазит в поле
Текстовка находится тут - HotA_lng.lod
файл - GENRLTXT.txt
AlexSpl
Если интересно, почитайте про __cdecl, __stdcall, __fastcall.
AlexSpl
Я следил за темой не с самого начала и не припомню, чтобы кто-то раньше модифицировал HotA. Может, список изменений опубликовать? Вдруг кто заинтересуется? Ну и плагин в общий доступ, само собой.
DedMorozzz
Вроде нашел чёт по теме - http://natalia.appmat.ru/c&c++/dll.html
Но картина не складывается...
Во всех свои ф-ях на С++ я использую только _stdcall
Цитата
При использовании соглашения о вызовах _fastcall первые два параметра, размер которых не больше двойного слова, передаются через регистры ECX и EDX. Остальные параметры передаются через стек.

Я так понимаю что использую только регистры. Но их больше чем 2. И eax есть и прочее, это получеается тоже регистры же? Тогда что такое стек...

Да и в целом пока что не понял что именно надо о этих соглашениях почитать. Слишком много разной инфы)

--------------------------------------------------------------------------------------------------------------------------------------

Цитата(AlexSpl @ 27 Jan 2017, 21:56) *
Я следил за темой не с самого начала и не припомню, чтобы кто-то раньше модифицировал HotA. Может, список изменений опубликовать? Вдруг кто заинтересуется? Ну и плагин в общий доступ, само собой.

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

Но текущая цель такая, что бы под выпавшие навыки подстраивалась игра. Другими словами что бы всё было полезным.

Палатку как причешу, хочу вернутся к дипломатии... сколько раз играли и она выпадала - ниразу не брали. Слишком сомнительные бонусы получились.
Обсудили такую идею, на все повышалки за 1к годы, при наличии навыка дипломатии сделать цену 1.5/1/0.5к голды и получить +2 к статам, а не +1
После этого думается навык станет ощутимо привлекательнее

И забегая на перёд имеется идея сделать грамотность
для героя сумма статов которого выше некого числа, к примеру 15-20 что бы давалось +3/6/9 знания
Почему сумму статов учитывать, что бы левак не бегал и не спамил молниями. Да и леваку это и так норм навык, если надо что нить мейну передать
А вот если это получит меин... уже будет досадно, особено когда преследую цель убрать бесполезные навыки
Но тут загвоздка, я понятия не имею как построить логику которая при повышении статов пересчитывать бонус от уже полученого вторичного навыка
AlexSpl
MSDN почитайте. __stdcall. Там же и остальные соглашения описаны.

Например, __stdcall функция сама освобождает стек от переданных ей аргументов (например, retn szArgs, где szArgs - суммарный размер аргументов). Аргументы, разумеется, передаются через стек: push arg_{N}, push arg_{N-1}, ..., push arg_0.

За __cdecl функцию стек освобождает вызывающая функция (например, add esp, szArgs).

__fastcall функция тоже освобождает стек самостоятельно. Отличается от __stdcall тем, что первые 2 аргумента DWORD (или меньшего размера) передаются через регистры ecx и edx, а остальные через стек.
DedMorozzz
Вот такой код получился для первой помощи.
Код
int __stdcall setFirstAidShield(LoHook* h, HookContext* c)
{
    int cmAddr =  *(int*)0x699420;
    char firstAidLevel = *(char*)(*(int*)(cmAddr + 0x53CC) + 201 + 27);
    int unitLevel = *(int*)(c->esi + 0x78) + 1;
    *(int*)(c->esi + 0x94) = unitLevel * firstAidLevel * 10;
    
    return EXEC_DEFAULT;
}

int __stdcall absorbDamage(LoHook* h, HookContext* c)
{
    if ( c->ecx <= *(int*)(c->esi + 0x94) ) {
        *(int*)(c->esi + 0x94) -= c->ecx;
        c->ecx = 1;
    } else {
        c->ecx -= *(int*)(c->esi + 0x94);
        *(int*)(c->esi + 0x94) = 0;
    }
    
    return EXEC_DEFAULT;
}

int __stdcall getStackHp(LoHook* h, HookContext* c)
{
    int unitAddr = *(int*)(c->ebp - 0x20);    // получаем адрес отряда, чьё информационное окно смотрим
    int hpShieldValue = *(int*)(unitAddr + 0x94);    // получаем значение щита

    if ( hpShieldValue > 0 ) {
        sprintf( (char*)0x697428, "%d [%d]", *(int*)(c->ebp + 8), hpShieldValue );    // отображаем остаток_здоровья [щит]
    }
    else return EXEC_DEFAULT;    // отображаем по умолчанию: остаток_здоровья

    c->esp -= 12;    // adjust esp*
    c->return_address = 0x5F64C2;

    return NO_EXEC_DEFAULT;
}

Код
_PI->WriteLoHook(0x478552, setFirstAidShield);
            _PI->WriteLoHook(0x443DBB, absorbDamage);
            _PI->WriteLoHook(0x5F64AF, getStackHp);

Цифры мб надо будет подправить, но это уже донастройка. Мб так же учесть кол-во отрядов в стеке. Аля кол-во/5*уровень = бонусный щит
Т.е. для 1000 скелетов бонусный щит будет в 200 едениц. Или для 45 виверн будет 54 бонусного поглощения
Ибо если скелеты основное войско, то эти 25 едениц щита что андеду припарка..
Но это надо будет прикинуть, посчитать, что бы не сделать слишком сильным навык

Но прямо сейчас другая проблема. Если у юнита фул хп, я не могу на него щит кинуть. Даже если его атаковали уже. К примеру ударили пачку кентавров но так что убили ровно по кол-ву хп. Я не могу повесть щит
Как убрать ограничение для хила, что только юниты с не фул здоровьем могут быть вылечены палаткой?
AlexSpl
Цитата
Как убрать ограничение для хила, что только юниты с не фул здоровьем могут быть вылечены палаткой?

Это можно сделать, но я бы не стал. Думайте не о стеке в целом, а о индивидуальном воине в нём. Ударили так, что погиб - лечить некого. Иначе палатка будет накладывать щит уже на другого воина в стеке. Понимаете идею? Палатка не воскрешает, а лечит и накладывает щит на ещё живого воина в стеке.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2025 IPS, Inc.