Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Мод на ХотА
DF2 :: ФОРУМЫ > Игровые форумы > Heroes of Might & Magic III > Моды
Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
DedMorozzz
Верно. И идея в том, что бы палатка была элементом тактики. Что бы можно было напасть на противника. Прокинуть щит на отряд и им ударить. С расчётом, что ответный урон будет поглощён щитом, ну или частично им поглощён
В противном случае если нажать всеми припас. А так всегда и происходит, то палатку можно будет использовать только на 2м кругу, что ощутимо снижает её ценность
С другой стороны это надо взять и попробовать, если будет слишком сильно - всегда можно будет отключить возможность прокидывания щита на целых юнитов. Ну иль уменьшить размер поглощения урона
К примеру если был хил то щит в полном объёме. Если целые хп, то щит в пол силы. Это будет совсем не трудно сделать
И это в целом даст тоже ещё элемент в бою, выбирай что лучше, пол щита но заранее. Или отхилить юнита после получения урона и более сильный щит. Может так и стоит сделать
DedMorozzz
хз какой-то бред...
Уменьшил бонус щита с 10 * левелНавыка, до 5 + 5*левелНавыка
Т.е. вместо 10/20/30 базовый коэфициент сделал 10/15/20
И добавил расчёт юнитов в стеке. Там где юнитов меньше щит слабее(доп бонус меньше), там где их больше - сильнее..

Формулу такую хочу использовать:
кол-во юнитов / 5 * левел
При этом кол-во / 5 округлить в большую сторону

Код:

Код
int countMonsters = *(int*)(c->esi + 0x4C);
    float countUnitsForShield = (countMonsters / 5) + 0.99;
    int countUnitBonus = floor(countUnitsForShield) * unitLevel;
        //float countUnitsForShield = (countMonsters / 5);
        //int countUnitBonus = ceil(countUnitsForShield) * unitLevel;

    *(int*)(c->esi + 0x94) = countUnitBonus;//unitLevel * firstAidBonus + countUnitBonus;

Не работает как надо
есть 2 пака. 1 арх и 24 арха
каунт верный. Я в виде щита кидал кол-во юнитов. Всё ок. Цифры были 1 и 24 соответсвенно
но вот получить щит 7 и 35 не выходит, по факту выходит 0 и 28. Т.е. округляет всегда в меньшую сторону
Где тут ошибка?
DedMorozzz
нагавнокодил, но сделал
Код
int __stdcall setFirstAidShield(LoHook* h, HookContext* c)
{
    int cmAddr =  *(int*)0x699420;
    int stackBonusModificator = 5;
    char firstAidLevel = *(char*)(*(int*)(cmAddr + 0x53CC) + 201 + 27);
    int firstAidBonus = 5 + firstAidLevel * 5;

    int unitLevel = *(int*)(c->esi + 0x78) + 1;
    int countMonsters = *(int*)(c->esi + 0x4C);

    float countUnitsForShield = int(countMonsters / stackBonusModificator);
    
    if (countMonsters > (countUnitsForShield * stackBonusModificator)) {
        countUnitsForShield += 1;
    }
    
    int countUnitBonus = countUnitsForShield * unitLevel;

    *(int*)(c->esi + 0x94) = unitLevel * firstAidBonus + countUnitBonus;
    
    return EXEC_DEFAULT;
}


Так и не удалось реализовать округление через floor или ceil
И даубл и флоат и добавление чисел делал, всегда, при любом раскладе получается округление в меньшую сторону
Потому переделал на просчёт от обратного и теперь работает как надо

Теперь возник вопрос - как получить специализацию героя? Нашел что айди специализация "первая помощь" это 27. А как получить теперь её что бы сравнить с этим значением?
AlexSpl
Цитата
Так и не удалось реализовать округление через floor или ceil

Всё потому, что "/" - это целочисленное деление, если делимое и делитель есть целые чиcла. Делить нужно так для float: ... / 5.0f; Разницы нет для целых чисел, т.е. можно просто написать 5.0, но если делите на дробное число, лучше указать тип прямо. 5.0 по умолчанию есть 5.0d (double).

Цитата
Теперь возник вопрос - как получить специализацию героя? Нашел что айди специализация "первая помощь" это 27. А как получить теперь её что бы сравнить с этим значением?


Для спеца по First Aid (ID = 27):
Код
int heroID = *(int*)(heroAddr + 26);
int specInfoAddr = *(int*)0x679C80;
bool firstAidSpec = *(int*)(specInfoAddr + heroID * 40) == 0 && *(int*)(specInfoAddr + heroID * 40 + 4) == 27;


*(int*)(specInfoAddr + heroID * 40) - тип специализации (0 - спец по вторичному навыку, 1 - спец по юниту, 2 - спец по ресурсу, 3 - спец по заклинанию; другие значения - особые специализации героев кампаний),
*(int*)(specInfoAddr + heroID * 40 + 4) - ID вторичного навыка, юнита, ресурса, закла.

* * *
Цитата
Код
char firstAidLevel = *(char*)(*(int*)(cmAddr + 0x53CC) + 201 + 27);


Также не забывайте, что палатка может быть и у защищающейся стороны.

Код
_Hero_* hero[2]; // + 21452 // 0 - attacker, 1 - defender
_int32_ current_side; // +78528 0x132C0


Код
int currentSide = *(int*)(cmAddr + 0x132C0);
char firstAidLevel = *(char*)(*(int*)(cmAddr + currentSide * 4 + 0x53CC) + 201 + 27);
igrik
Цитата(AlexSpl @ 27 Jan 2017, 22:56) *
Я следил за темой не с самого начала и не припомню, чтобы кто-то раньше модифицировал HotA. Может, список изменений опубликовать? Вдруг кто заинтересуется? Ну и плагин в общий доступ, само собой.

Вы модифицируете основной код игры: участки кода, которые одинаковы и для HotA и для SoD и для WoG/ERA. Правки именно в хотовских фишек (которые в HotA.dll) я не увидел.
DedMorozzz
Действительно, забыл про палатку противника...
Итого: добавил проверку на сторону, сделал нормальное округление, добавил бонус для специализации (левел юнита увеличивается на 1, при расчёте силы щита)


Но всё же мне кажется верным решением дать возможность вешать щит на целых юнитов. Собсно щит для этого и нужен - даёт возможность избежать урона
Тут я вижу 2 проблемы:
1. необходимо разрешить хилять целых юнитов
2. при расчёте передаче хода палатке убрать условие проверки, что все юниты целые

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

Куда копать? Как это разрешить

PS: igrik, вроде ток логика сбегания связана с кодом хоты.. надо будет проверить. Но СОД не установлен)
AlexSpl
Поправил код получения heroID. Вы не учитывали текущую сторону currentSide.

DedMorozzz
Спс, добавил. А насчёт палатки есть идеи? Как разрешить хил целых юнитов?
AlexSpl
Задача комплексная smile.gif Поэтому разобьём её на несколько подзадач.

1) Вот возможность лечить любой дружественный юнит, даже если он не терял HP, при ручном управлении палаткой:

Код
_PI->WriteHexPatch(0x47609A, "9090");


Требования: хотя бы один отряд должен потерять HP, чтобы работало, иначе палатка просто пропустит свой ход. Это уже следующая подзадача.
AlexSpl
2) Делаем возможным лечение, даже если никто не получил урон:

Код
_PI->WriteHexPatch(0x4738B1, "EB");


Здесь есть подводный камень. Если лечение автоматическое, то на ходе палатки игра зависнет, так как не выбрана цель. Поэтому предлагаю сначала посмотреть, как работает теперь ручное лечение, а потом определить критерий, по которому будет выбираться отряд для автоматического лечения в случае, если никто не ранен smile.gif
DedMorozzz
Да, всё верно.. при этом хуке
Код
_PI->WriteHexPatch(0x4738B1, "EB");

палаткой могу управлять. Даже тогда когда фух хп у всех. Но хилять не могу
А без навыка игра виснет. Ну как виснет... музыка идёт, ожидается ход палатки, которая ничего не делает
AlexSpl
Цитата
палаткой могу управлять. Даже тогда когда фух хп у всех. Но хилять не могу

А этот патч прописали:
Код
_PI->WriteHexPatch(0x47609A, "9090");
?

Цитата
А без навыка игра виснет.

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

------------------------------
Сделал такую штуку - вылетакт при попытке запуска игры:
Код
int cmAddr =  *(int*)0x699420;
            int currentSide = *(int*)(cmAddr + 0x132C0);
            int heroAddr = *(int*)(cmAddr + currentSide * 4 + 0x53CC); // адрес героя с учётом стороны
            char firstAidLevel = *(char*)(heroAddr + 201 + 27);

            if (firstAidLevel > 0) {
                _PI->WriteHexPatch(0x47609A, "9090");
                _PI->WriteHexPatch(0x4738B1, "EB");
            }


Этот код естесно там, где все хуки прописаны. Обёртку над хуком сделал, мол не нужен если навык отсутствует
AlexSpl
Цитата
А насчёт автохила достаточно сделать проверку на наличие навыка. Ибо щит без навыка не должен вешаться.

Так это вообще просто ) Удаляем патч 0x4738B1. Вместо него ставим LoHook на тот же адрес.

Цитата
Сделал такую штуку - вылетакт при попытке запуска игры:

Патчи прописывайте ВНЕ функций.
AlexSpl
Например, так:

Код
{
    int cmAddr = *(int*)699420;
    int currentSide = *(int*)(cmAddr + 0x132C0);
    int heroAddr = *(int*)(cmAddr + currentSide * 4 + 0x53CC); // адрес героя с учётом стороны
    
    if ( *(char*)(heroAddr + 201 + 27) == 0 ) return EXEC_DEFAULT;

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


Т.е. пишем первый патч ("9090"). Потом LoHook на 0x4738B1, и код выше.
DedMorozzz
Код
int __stdcall checkAllowHeal(LoHook* h, HookContext* c)
{
    int cmAddr = *(int*)699420;
    int currentSide = *(int*)(cmAddr + 0x132C0);
    int heroAddr = *(int*)(cmAddr + currentSide * 4 + 0x53CC); // адрес героя с учётом стороны
    
    if (*(char*)(heroAddr + 201 + 27) == 0) {
        return EXEC_DEFAULT;
    }

    c->return_address = 0x4738C3;

    return NO_EXEC_DEFAULT;
}

Код
_PI->WriteHexPatch(0x47609A, "9090");
            _PI->WriteLoHook(0x4738B1, checkAllowHeal);


вылетает когда ход переходит палатке
AlexSpl
Давайте выясним где. Закомментите вот это:
Код
c->return_address = 0x4738C3;
return NO_EXEC_DEFAULT;


Т.е. код хука:
Код
int __stdcall checkAllowHeal(LoHook* h, HookContext* c)
{
    int cmAddr = *(int*)699420;
    int currentSide = *(int*)(cmAddr + 0x132C0);
    int heroAddr = *(int*)(cmAddr + currentSide * 4 + 0x53CC); // адрес героя с учётом стороны
    
    // if (*(char*)(heroAddr + 201 + 27) == 0) {
        return EXEC_DEFAULT;
    // }

    // c->return_address = 0x4738C3;

    // return NO_EXEC_DEFAULT;
}
DedMorozzz
Код
int __stdcall checkAllowHeal(LoHook* h, HookContext* c)
{
    int cmAddr = *(int*)699420;
    int currentSide = *(int*)(cmAddr + 0x132C0);
    int heroAddr = *(int*)(cmAddr + currentSide * 4 + 0x53CC); // адрес героя с учётом стороны
    
    if (*(char*)(heroAddr + 201 + 27) == 0) {
        return EXEC_DEFAULT;
    }

    //c->return_address = 0x4738C3;

    //return NO_EXEC_DEFAULT;
    return EXEC_DEFAULT;

}


Вот так всё ок, но палатка не ходит. с NO_EXEC_DEFAULT вылетате

явно проблема тут - c->return_address = 0x4738C3;
AlexSpl
Интересно. А если хук поднять выше (на 4738ACh)?

Код
int __stdcall checkAllowHeal(LoHook* h, HookContext* c)
{
    int cmAddr = *(int*)699420;
    int currentSide = *(int*)(cmAddr + 0x132C0);
    int heroAddr = *(int*)(cmAddr + currentSide * 4 + 0x53CC); // адрес героя с учётом стороны
    
    if (*(char*)(heroAddr + 201 + 27) == 0) {
        return EXEC_DEFAULT;
    }

    c->return_address = 0x4738C3;

    return NO_EXEC_DEFAULT;
}


Код
_PI->WriteLoHook(0x4738AC, checkAllowHeal);


Патч "EB", естественно, должен быть удалён.
DedMorozzz
Не, вылетает. Патч удалил
AlexSpl
А если поправить
Код
int cmAddr = *(int*)699420;

на
Код
int cmAddr = *(int*)0x699420;
?

Хотя Вы вряд ли просто скопировали мой код с ошибкой...

* * *
Если не поможет, предлагаю проверить следующие два варианта на герое, у которого есть First Aid:

1-й вариант (патч):
Код
_PI->WriteHexPatch(0x4738B1, "EB");

Хук 0x4738B1 удаляем.

2-й вариант (хук):

Код
int __stdcall checkAllowHeal(LoHook* h, HookContext* c)
{
    c->return_address = 0x4738C3;
    return NO_EXEC_DEFAULT;
}

(в коде хука оставляем только джамп по адресу 0x4738C3).

Код
_PI->WriteLoHook(0x4738B1, checkAllowHeal);

Патч 0x4738B1 удаляем.
DedMorozzz
Скомпоновал оба варианта с постов выше. Получилось так:

Код
int __stdcall checkAllowHeal(LoHook* h, HookContext* c)
{
    int cmAddr = *(int*)0x699420;
    int currentSide = *(int*)(cmAddr + 0x132C0);
    int heroAddr = *(int*)(cmAddr + currentSide * 4 + 0x53CC); // адрес героя с учётом стороны
    
    if (*(char*)(heroAddr + 201 + 27) == 0) {
        return EXEC_DEFAULT;
    }

    c->return_address = 0x4738C3;

    return NO_EXEC_DEFAULT;
}


Код
_PI->WriteHexPatch(0x47609A, "9090");
_PI->WriteLoHook(0x4738AC, checkAllowHeal);


Что было не так, checkAllowHeal был ок. Но не работал потому что патча 0x47609A не было. В общем всё ок ща
Итого добавил щит в половину силы на целых юнитов. А у героя со специализацией фул щит всегда

Итого код расчёта щита получился таким:
Код
int __stdcall setFirstAidShield(LoHook* h, HookContext* c)
{
    int cmAddr =  *(int*)0x699420;
    float stackBonusModificator = 5.0f;
    

    int currentSide = *(int*)(cmAddr + 0x132C0);
    int heroAddr = *(int*)(cmAddr + currentSide * 4 + 0x53CC); // адрес героя с учётом стороны
    char firstAidLevel = *(char*)(heroAddr + 201 + 27);

    int heroID = *(int*)(heroAddr + 26);
    int specInfoAddr = *(int*)0x679C80;
    bool firstAidSpec = *(int*)(specInfoAddr + heroID * 40) == 0 && *(int*)(specInfoAddr + heroID * 40 + 4) == 27;


    int specBonus = 0;
    if (firstAidSpec) {
        specBonus += 1;
    }

    int unitLevel = *(int*)(c->esi + 0x78) + 1 + specBonus;

    int firstAidBonus = (5 + firstAidLevel * 5) * unitLevel;
    
    int countMonsters = *(int*)(c->esi + 0x4C);
    float countUnitsForShield = ceil(countMonsters / stackBonusModificator);
    int countUnitBonus = countUnitsForShield * unitLevel;

    int totalSheildCount = firstAidBonus + countUnitBonus;
    if (*(int*)(c->esi + 0x58) == 0 && !firstAidSpec) {
        totalSheildCount = totalSheildCount / 2;
    }

    *(int*)(c->esi + 0x94) = totalSheildCount;
    
    return EXEC_DEFAULT;
}


А вообще весь фул код переделанной первой помощи вот:
DedMorozzz
Выложил код в этой темке - http://forum.df2.ru/index.php?showtopic=36605
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2025 IPS, Inc.