IPB

Здравствуйте, гость ( Вход | Регистрация )

История благодарностей участнику DedMorozzz. Спасибо сказали: 25
Дата поста: В теме: За сообщение: Спасибо сказали:
05 Feb 2017, 00:06 Мод на ХотА
Выложил код в этой темке - http://forum.df2.ru/index.php?showtopic=36605
AlexSpl, Corkes, AlexejKa83
05 Feb 2017, 00:04 Джебус мод
баланс мод для шаблона джебус
Джебус баланс мод


Мод создавался со следующей идеей. Сделать игру более разнообразной. Что бы игра подстраивалась под выпадающие навыки и от них строить свою стратегию
А не как в СОДе/ХотЕ - многие навыки откровенно ужасные, которые не нужны никому и никогда. Т.е. основная цель - убрать бесполезные навыки или субъективно слабые усилить
То же самое касается для замков. Их и так было не слишком много конкурентных, а с нефром андедов и конфлюкса - стало ещё меньше, речь именно о джебусе
После этого возникла идея подправить баланс под текущие реалии. При этом не отходить от классической идеи
Т.е. всякие воскрешения палаткой, 3й апгрейд для 7х юнитов, командиры и прочее даже не рассматриваются
Мод тестировался исключительно на ХотЕ, хотя изменения проводились общего кода с СОДом. И на хот сите, игра по сети не тестировалась




Строения в замках:
- Люди. Для ангелов необходим ГМ2, для архов ГМ3
- Оплот. ГМ2 для драконов требовало, теперь ГМ1
- Инферно. Дьяволы не требуют пит лордов не улучшеных (изверги вроде) для постройки
- Темница. ГМ2 для драконов требовало, теперь ГМ1
- Варвары. Бегемоты требуют теперь циклопов. Циклопы - птиц, вместо огров

Специализация:
Специализацию по след. навыкам сделал по 2% за левел вместо 5%
- Логистика
- Нападение
- Защита
- Некромантия

Навыки:
- Мистицизм. 1-7-14-21ед
- Некромантия. 0-15-30-45%
- Сопротивление. 0-15-25-35%
- Колдовство. 0-10-20-30%
- Обучение. 0-15-30-45%

"Базовый" процент в 0-10-20-30
Джебус это только Исра и Ведомина. Остальные герои вне конкуренции...
Итого Исра на 20м левеле имел 70% некромантии без артов
С новым процентов (15-30-45) на 20м уровне будет 73% некромантии.
Другими словами процент сделал более сильным в начале но супер буста не получится
При этом такой герой как Тант теперь тоже более чем играбелен. Может в дальнейшем и добавлю других


Арты некромантии: 5%/10%/15% (шея, плечи, сапоги)

(Т) - значит изменения в текстовике. Только плагина будет недостаточно, необходимо подключить доп *.lod файл

Магия:
- Замедление. Теперь округляет в большую сторону. Т.е. у юнита со скоростью 5, после замедления будет скорость не 2, а 3. И манакост +2. Т.е. 8, но только для эксперта (манакост в текстовике)
- Молитва. Даёт 6 атаки/защита, 4 скорости и благо. Манакост уменшил до 8 на эксперте (манакост в текстовике)
- Взрыв теперь магия огня (Т)
- Огенный шар, базовый урон вместо 15/15/30/60 стал 20/30/50/80. СП вместо 10 сделал 20 (Т)
- Инферно, базовый урон вместо 20/20/40/80 стал 30/50/80/120. СП вместо 10 сделал 20 (Т)


Юниты в городах:
Инферно:
- инфриты (и улучшенные) на 100 голды дешевле (Т)
- дьяволы (и улучшенные) дешевле на 500 голды (Т)
- дьяволы -3к на постройку (12 теперь) (Т)

Темница:
- красные драконы (постройка) стоят 10к и 10 серы (Т)

Болото:
- Гидры 10 серы (Т)


Навыки:
1. Для всех навыков, которые работаю в тою но не действуют в бою в банках существ (далее банки), добавлен альтернативный бонус
2. Все навыки остались как есть, только добавлено новое, если в опиасании прямо не сказано обратного

- поиск пути
добавляет +1/2/3 к скорости юнита для пересчёта хода на начало дня
Т.е. при улучшеном поиске пути герой с вампиром-лордом (скорость 9) будет бегать так же как если бы начал ход с ангелом

- тактика
во время боя в банке, на 1й ход даётся +1/2/3 скорости всем юнитам. Соотв. во 2м раунд бонус уже не действует

- артиллерия
во время боя в банке и при наличии балисты/пушки в инвентаре даёте +1/2/3 атаки (само собой при наличии навыка)

- первая помощь
во время боя в банке и при наличии палатке в инвентаре даёте +1/2/3 защиты
Теперь палатка при хиле накладывает и щит поглощающий урон. Чем выше левел юнита тем сильнее щит. Так же чем больше юнитов, тем щит сильнее
Формула (5 + левелНавыка*5)*левелЮнита + (кол-воЮнитов / 5 * левелЮнита)
Округляет в большую сторону.

Примеры:
1000 скелетов = 220хп
44 виверны = 174хп
10 титанов = 154хп
1 титан = 147хп

При накладывании щита на юнита с фул здоровьем - щит действует в пол силы. Кол-во поглощаемого урона пишется с квадратных скобках, рядом с текущим
Для этого переименовано было поле "Текущее здоровье" в "Текущее ХП", что бы поместилось значение

Для героя со специализацией на палатке левелЮнита в форуме увеличивается на 1. Так же щит всегда в полную силу действует


Дипломатия:
Навык переработан. Юниты более не присоединяются никогда. При этом снижение требования -2 левела при посещении либы за каждый уровень навыка дипломатии - осталось
Так же осталось снижение цены капитуляции
Теперь дипломатия увеличивает силу войск в глазах монстров на 10/20/30% при расчёте побега и на сколько стаков будет делиться при бое (так же корректно действует на предпросмотр ворами или магией)
Так же позволяет сдаваться нейтралам со скидкой в 70/80/90%
Посещение либы даёт бонусный +1 к статам. Т.е. +3 ко всему, вместо +2
Кроме того, после посещения либы даётся +1/2/3 морали до след. битвы

Арты дипломатии:
Каждый арт снижает стоимость откупа на 10%, действует на нейтралов тоже. Минимальная цена 0 голды
Каждый арт снижает требования левела для библиотеки на 1левел. Вне зависимости имеется навык или нет
Каждый арт повышает силу армии в глазах монстров на 10% при расчёте побега или деления на кол-во стаков

Орлиный глаз:
шанс выпадения всем героям (кроме причала ХотЫ) сделал = 0

Всем классическим банкам изменил процент выпадения минималок, максималок... (Т)
Был 30-30-30-10%
Стал 15-35-35-15%
Т.о. вероятность выпадения только минималок снижена. Смещено ближе к центру

Арты:
Сапоги скороходы теперь J (поднял по уровню)
Сумка + 1000 голды N. такой же уровень со всеми сумками голды



На данный момент пока что всё. В силу определённых причин уделять время в ближайшее время не выйдет. Потому выкладываю весь код который имеется и добавлю что хотелось бы видеть. Если кто это реализует - обязательно включу в мод =).gif
1. для дипломатии сделать +1 к выбраной хар-ке при посещении объектов за 1000 голды. При этом изменить стоимость до 1500/1000/500
2. орлиный глаз. Для лучников сделать +1/2/3 клетки к прямой стреле, возможность просмотра кол-ва юнитов и действие в случае нападения (как у воров) на основании СП
3. Арты, идея в следующем, если ты дрался за арт, то он должен давать бонус.
- Все бонусы к стрельбе что бы работали и без навыка
- Арты орлиного глаза добавляли +5 к радиусу превью (имеется ввиду дальность бонуса, как у воров)
- арты некромантии, если герой без этого навыка, что бы наносил х2 от бонуса арта по андедам, если противник не герой. Т.к. только по нейтральным войскам
4. Волшебное зеркало что бы было массовым, но основной эффект был только на изначальную цель. Остальные получали бы 10/15/20% сопротивления магии
5. Защите от магии выдать так же защиту от огня. Драконам тоже (что бы огненый щит не наносил огненого урона юнитам с иммунитетом к магии)
6. убрать баллистику или объеденить с артилерией
7. навык "убрать преграду", уменьшить в манакосте и что бы убиралась только 1 клетка под курсором. Убрать можно только граничащую с картой клетку (во избежание абуза, аля портануть лучника в недосягаемую точку и убивать милишников)
8. Для "плаща короля нечести" сделать следующий бонус - так же воскрешает на эксперте личей, но сам арт будет давать суммарно навык некромантии равный статическому проценту. Какой процент - надо тестить, но думаю 10+-. Т.е. был навык некромантии 60% с разобранным плащём, собрав получится только 10, но ресать вместо скелетов будет личей
9. Грамотность. Для героя у которого сумма статов выше чем 20 что бы грамотность давала +3/6/9 знания. Проблема в том, что не совсем понимаю куда это привязать и как делать корректный расчёт. Идея есть, но как реализовать понятия не имею. Так что этот пункт пока что на уровне идеи


Если вы считаете что некоторые значения не подходят, код ниже прилагаю. Его можете легко изменить и поднастроить всё именно так, как вам кажется более верно
Информация как редактировать имеется в этой теме: http://forum.df2.ru/index.php?showtopic=69...mp;#entry711673


Код:


CODE
#include "../../patcher_x86.hpp"
#include <cmath>
#include <stdio.h>

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, 1, -1,
43, 36, 2, -1,
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,
36, 35, 33, 5, -1,
43, 36, -1,
26, -1,
-100
};

int BuildDepends_Rampart[] =
{
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, 0, -1,
43, 36, 2, -1,
26, -1,
-100
};

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, 0, -1,
43, 36, 2, -1,
26, -1,
-100
};

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

int SecondarySkills_Mysticism[] =
{
1, 7, 14, 20
};

int SecondarySkills_Estates[] =
{
0, 250, 500, 750
};

float SecondarySkills_Necromancy[] =
{
0, 0.15, 0.30, 0.45
};

float SecondarySkills_Resistance[] =
{
0, 0.15, 0.25, 0.35
};

float SecondarySkills_Sorcery[] =
{
0, 0.1, 0.2, 0.3
};

float SecondarySkills_Learning[] =
{
0, 0.15, 0.3, 0.45
};



int __stdcall spellSlow(LoHook* h, HookContext* c)
{
float speed = (float)(*(int*)(c->ecx +196));
c->eax = floor( (speed * (*(float*)(c->ecx + 1224))) + 0.5 );

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

int __stdcall spellSlowMelee(LoHook* h, HookContext* c)
{
float speed = (float)(*(int*)(c->esi +196));
c->eax = floor( (speed * (*(float*)(c->esi + 1224))) + 0.5 );

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

int __stdcall libraryVisit(LoHook* h, HookContext* c)
{
if (*(char*)(c->esi + 201 + 4) > 0) {
char bonus = 1;

*(char*)(c->esi + 1142) += bonus; // атака
*(char*)(c->esi + 1143) += bonus; // защита
*(char*)(c->esi + 1144) += bonus; // колд. сила
*(char*)(c->esi + 1145) += bonus; // знания
}

if (*(char*)(c->esi + 201 + 4) > 0) {
char moreleBonus = *(char*)(c->esi + 201 + 4);
*(char*)(c->esi + 282) += moreleBonus;
}

return EXEC_DEFAULT;
}

float __stdcall getArtArmyValueModifier(int art[])
{
for (int i = 0; i < 19; ++i) {
if ( art[i] == 66 ) {
return 30;
}
}

return 0;
}

float __stdcall getArmyValueModifierOld(int diplomacyLevel, HookContext* c)
{
float armyModifier[4] = {0.00, 0.10, 0.15, 19.00};
float currentModifier = ( (diplomacyLevel >= 0) && (diplomacyLevel <= 3) ? armyModifier[diplomacyLevel] : 1 );

return currentModifier;
}

float __stdcall getArmyValueModifier(int baseHeroOffset)
{
int diplomacyLevel = (int)(*(char*)(baseHeroOffset + 201 + 4));
float armyModifier[4] = {0.00, 0.10, 0.2, 0.3};
float currentModifier = ( (diplomacyLevel >= 0) && (diplomacyLevel <= 3) ? armyModifier[diplomacyLevel] : 0 );

float armyArtModifier = 0;
for (int i = 0; i < 19; ++i) {
if ( *(int*)(baseHeroOffset + 301 + (i << 3)) == 66 ) {
armyArtModifier += 0.1;
}

if ( *(int*)(baseHeroOffset + 301 + (i << 3)) == 67 ) {
armyArtModifier += 0.1;
}

if ( *(int*)(baseHeroOffset + 301 + (i << 3)) == 68 ) {
armyArtModifier += 0.1;
}
}

return currentModifier + armyArtModifier;
}

int __stdcall setArmyValue(LoHook* h, HookContext* c)
{
int baseHeroOffset = c->edi;
float armyModifier = getArmyValueModifier(baseHeroOffset);
(int)c->eax *= (1 + armyModifier);

return EXEC_DEFAULT;
}


int __stdcall setArmyValuePreview(LoHook* h, HookContext* c)
{
int baseHeroOffset = c->esi;
float armyModifier = getArmyValueModifier(baseHeroOffset);
(int)c->eax *= (1 + armyModifier);

return EXEC_DEFAULT;
}

int __stdcall setArmyValueSplit(LoHook* h, HookContext* c)
{
int baseHeroOffset = *(int*)(c->ebp + 8);
float armyModifier = getArmyValueModifier(baseHeroOffset);
(int)c->eax *= (1 + armyModifier);

return EXEC_DEFAULT;
}

int __stdcall setSurrenderButton(LoHook* h, HookContext* c)
{
int heroOffset = *(int*)(c->esi + c->eax * 4 + 0x53CC);

if ( heroOffset == 0 ) {
return EXEC_DEFAULT;
}

char diplomacyLevel = *(char*)(*(int*)(c->esi + c->eax * 4 + 0x53CC) + 201 + 4);

if ( diplomacyLevel > 0 ) {
c->return_address = 0x477EB5;
return NO_EXEC_DEFAULT;
}

return EXEC_DEFAULT;
}

int __stdcall setSurrenderPrice(LoHook* h, HookContext* c)
{
//if ( *(int*)(*(int*)0x699420 + 0x132C0) == 0 ) {
int combatManager = *(int*)0x699420;
if ( *(int*)(combatManager + (0x14F4 - *(int*)(combatManager + 0x132C0)) * 4) == 0 ) {
switch ( (char)c->ecx ) {
case 1: *(float*)&c->edx = 0.7f; break;
case 2: *(float*)&c->edx = 0.8f; break;
case 3: *(float*)&c->edx = 0.9f; break;
default: c->edx = 0;
}
c->return_address = 0x4E480B;

return NO_EXEC_DEFAULT;
}

return EXEC_DEFAULT;
}

int __stdcall setSurrenderMinPrice(LoHook* h, HookContext* c)
{
int cmAddr = *(int*)0x699420; // адрес combatManager
int side = *(int*)(cmAddr + 0x132C0); // сторона в битве (0 - левая, 1 - правая)

float minimumPrice;
if ( *(int*)(cmAddr + (0x14F4 - side) * 4) == 0 ) minimumPrice = 1.0f; else minimumPrice = 0.9f;

if ( *(float*)(c->ebp - 4) > minimumPrice ) {
*(float*)(c->ebp - 4) = minimumPrice;
}

c->return_address = 0x4E493F;

return NO_EXEC_DEFAULT;
}

int __stdcall setLibraryVisitLevel(LoHook* h, HookContext* c)
{
int allLevelBonuses = 0;
if (*(short*)(c->esi + 85) < 10) {

for (int i = 0; i < 19; ++i) {
switch ( *(int*)(c->esi + 301 + (i << 3)) ) {
case 66: allLevelBonuses += 1; break;
case 67: allLevelBonuses += 1; break;
case 68: allLevelBonuses += 1; break;
}
}

if (*(char*)(c->esi + 201 + 4) > 0) {
allLevelBonuses += *(char*)(c->esi + 201 + 4) * 2;
}
}

int currentLevel = *(int*)(c->esi + 85);

c->eax = currentLevel + allLevelBonuses;
c->return_address = 0x4A2F55;

return NO_EXEC_DEFAULT;
}

int __stdcall setBaseHeroSpeed(LoHook* h, HookContext* c)
{
c->ecx += *(char*)(c->ebx + 201 + 0);
return EXEC_DEFAULT;
}

int __stdcall setBankUnitBonus(LoHook* h, HookContext* c)
{
int cmAddr = *(int*)0x699420;
int heroOffset = *(int*)(cmAddr + 0x53CC);

if (*(int*)(c->ebp + 16) != heroOffset) {
return EXEC_DEFAULT;
}

if ( *(char*)(*(int*)0x699420 + 0x53C5) == 1) { // проверка что бой в банке существ

if(*(char*)(heroOffset + 201 + 19) > 0) { // проверка на тактику
*(int*)(c->ebx + 196) += *(char*)(heroOffset + 201 + 19);
}

if(*(char*)(heroOffset + 201 + 20) > 0) { //проверка на артиллерию
if ( *(char*)(heroOffset + 301 + (13 << 3)) != -1 ) { //13 - слот на кукле для баллисты. -1 - пустой слот
*(int*)(c->ebx + 200) += *(char*)(heroOffset + 201 + 20);
}
}

if(*(char*)(heroOffset + 201 + 27) > 0) { //проверка на первую помощь
if ( *(char*)(heroOffset + 301 + (15 << 3)) == 6 ) { //15 - слот на кукле для палатки. 6 - айди палатки
*(int*)(c->ebx + 204) += *(char*)(heroOffset + 201 + 27);
}
}
}

return EXEC_DEFAULT;
}

int __stdcall resetTacticsUnitSpeedBonus(LoHook* h, HookContext* c)
{
int cmAddr = *(int*)0x699420;
if ( *(char*)(cmAddr + 0x53C5) == 1) { // проверка что бой в банке существ
char tacticLevel = *(char*)(*(int*)(cmAddr + 0x53CC) + 201 + 19);
int roundNumber = *(int*)(cmAddr + 0x132A0) - 30000;

if ((tacticLevel > 0) && (roundNumber == 1)) {
if ( c->ebx == cmAddr + 0x132A0 ) {
*(int*)(c->ecx + 196) -= tacticLevel;
}
}
}

return EXEC_DEFAULT;
}

int __stdcall spellPray(LoHook* h, HookContext* c)
{
c->ecx += 2;
c->ebx += 2;

int cmAddr = *(int*)0x699420;
char waterLevel = *(char*)(*(int*)(cmAddr + 0x53CC) + 201 + 16);

if (waterLevel > 1) {
*(int*)(c->esi + 0x458) = 1;
}

return EXEC_DEFAULT;
}

int __stdcall spellPrayEnd(LoHook* h, HookContext* c)
{
c->ecx -= 2;
c->ebx -= 2;

return EXEC_DEFAULT;
}

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;
}

int __stdcall preCalculateDmg(LoHook* h, HookContext* c)
{
int cmAddr = *(int*)0x699420;
int heroOffset = *(int*)(cmAddr + 0x53CC);

return EXEC_DEFAULT;
}

int __stdcall setFirstAidBonus(LoHook* h, HookContext* c)
{
int cmAddr = *(int*)0x699420;
int heroOffset = *(int*)(cmAddr + 0x53CC);

if(*(char*)(heroOffset + 201 + 27) > 0) { //проверка на первую помощь
if ( *(char*)(heroOffset + 301 + (15 << 3)) == 6 ) { //15 - слот на кукле для палатки. 6 - айди палатки
*(int*)(c->ebx + 204) += *(char*)(heroOffset + 201 + 27) * 2;
}
}

return EXEC_DEFAULT;
}

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;
}

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 ); // display left hp [shield]
} else {
return EXEC_DEFAULT;
}

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

return NO_EXEC_DEFAULT;
}

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;
}

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*)0x4EB8B3 = (int)BuildDepends_Rampart;
*(int*)0x4EBA39 = (int)BuildDepends_Inferno;
*(int*)0x4EBA5C = (int)BuildDepends_Dungeon;
*(int*)0x4EBA70 = (int)BuildDepends_Stronghold;

*(int*)0x4E41C8 = (int)SecondarySkills_Mysticism;
*(int*)0x4E461E = (int)SecondarySkills_Estates;
*(int*)0x4E4AC4 = (int)SecondarySkills_Learning;
*(int*)0x4E5B2C = (int)SecondarySkills_Sorcery;
*(int*)0x4E4967 = (int)SecondarySkills_Resistance;

//Necromancy
*(int*)0x4E3F59 = (int)SecondarySkills_Necromancy;
*(int*)0x4E3FE7 = 0x63EAE4; //amulet 0.05
*(int*)0x4E402D = 0x63B8D0; //cloak 0.10
*(int*)0x4E4074 = 0x63EB28; //boots 0.15
*(int*)0x4E4100 = 0x63B8D0; //amplifier 0.10

//specialization bonuses. Set 0.02
*(int*)0x4E3F92 = 0x63AC60; //Necromancy
*(int*)0x4E4F1E = 0x63AC60; //Logistic
*(int*)0x4E4569 = 0x63AC60; //Attack
*(int*)0x4E45C9 = 0x63AC60; //Defence

_PI->WriteLoHook(0x448A1A, spellSlow);
_PI->WriteLoHook(0x441E19, spellSlowMelee);

_PI->WriteDword((0x417236 + 1), 3); // при ПКМ
_PI->WriteHexPatch((0x4A755D), "EB"); // проходим мимо бесплатного присоединения
_PI->WriteHexPatch((0x4A75A9), "EB"); // проходим мимо платного присоединения

_PI->WriteHexPatch(0x417234, "EB"); // проходим мимо бесплатного присоединения (preview)
_PI->WriteHexPatch(0x417246, "EB"); // проходим мимо платного присоединения (preview)


_PI->WriteLoHook(0x4A7441, setArmyValue);
_PI->WriteLoHook(0x4171E6, setArmyValuePreview);
_PI->WriteLoHook(0x4AC35E, setArmyValueSplit);
_PI->WriteLoHook(0x477EA9, setSurrenderButton);
_PI->WriteLoHook(0x4E4804, setSurrenderPrice);
_PI->WriteLoHook(0x4E4931, setSurrenderMinPrice);


_PI->WriteLoHook(0x4A2F92, libraryVisit);
_PI->WriteLoHook(0x4A2F47, setLibraryVisitLevel);

_PI->WriteLoHook(0x4E4ED9, setBaseHeroSpeed);

_PI->WriteLoHook(0x43D492, setBankUnitBonus);
_PI->WriteLoHook(0x475A3D, resetTacticsUnitSpeedBonus);

_PI->WriteLoHook(0x44493C, spellPray);
_PI->WriteLoHook(0x4443F1, spellPrayEnd);
_PI->WriteLoHook(0x442F6A, spellPrayBonus);

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

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

/*
----------------------------------------
--- CmManager. Base address = 699420 ---
----------------------------------------
*/


}
break;

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



Лод файлы выложу чуток позжее. Планирую завтра

Так же огромное спасибо AlexSpl, который помогал по огромному кол-ву моментов и тов-щу igrik

На этом пока что всё smile.gif Пользуйтесь
Bes, AlexSpl, hippocamus, Ben, lion-killer, Axolotl, Corkes, serovoy, KypaToP_HM, the_new_pirate, Lokos, Sandris, AlexejKa83
28 Jan 2017, 14:46 Новые идеи для HotA
Обсуждение идей участниками форума
Как раз доделываю палатку для своего кастомного мода smile.gif
Кому интересно вот - http://forum.df2.ru/index.php?showtopic=36...mp;#entry736557

Вижу варианты с воскрешением, леченим и прочим. Я руководстовался несколько другой логикой - боевые машины не должны использовать магию. И не должны выходить за рамки своей задачи. Т.е. к примеру что бы палатка не увеличивала урон

Как реализовано на данный момент:
хил не менял. Но кроме хила палатка вешает щит поглощающий урон. Размер поглощаемого урона напрямую зависит от количества юнитов в стеке и от уровня этих юнитов
Т.е. какие нить гноллы получат меньший щит чем ангел. Так же 1000 скелетов получит более сильный щит чем 20
В теме выше фул код имеется, но формула вышла такая:
(5 + 5*левелНавыка (имеется ввиду первая помощь)) * левел отряда
это базовый бонус. К нему добавляется бонус за кол-во юнитов:
кол-во / 5 * левелЮнита

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

PS: а для специализации на палатке, думаю сделать левелЮнита на 1н выше для любого отряда. Но пока что не знаю как узнать специализацию)
AKuHAK, Qed'Maen
27 Jan 2017, 23:53 Мод на ХотА
Вот такой код получился для первой помощи.
Код
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
27 Jan 2017, 23:11 Мод на ХотА
Вроде нашел чёт по теме - 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
26 Jan 2017, 01:11 Мод на ХотА
т.е. там строка а не число?
но в целом ок идея. По аналогии с макс хп, когда в скобках пишется текущее хп, после яда или старения
Да.. вполне информативно должно получится. Но для начала надо будет проверить как вообще этот щит сделать.
Вывод информации это уже самый последний этап

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

урон = 1 для того что бы была анимация получения урона и избежать возможных проблем слогикой
AlexSpl
30 Dec 2016, 21:53 Мод на ХотА
Пока что так получилось:
Код
int __stdcall spellPray(LoHook* h, HookContext* c)
{
    c->ecx += 2;
    c->ebx += 2;

    return EXEC_DEFAULT;
}

int __stdcall spellPrayEnd(LoHook* h, HookContext* c)
{
    c->ecx -= 2;
    c->ebx -= 2;

    return EXEC_DEFAULT;
}


Код
_PI->WriteLoHook(0x44493C, spellPray);
_PI->WriteLoHook(0x4443F1, spellPrayEnd);


Вроде работает

PS:
А вот и смещения для благо:
//_int_ damage_min; //+208 0xD0
//_int_ damage_max; //+212 0xD4


-----------

хм... не пойму пока как сделать благо
Как оно работает- все атаки наносят максимальный урон. Если улучшеное и выше, то макс. урон +1.
т.е. урон 4-7, после улучшеного блага всегда 8

Соотв. Как сделать благо - понятно, а как вернуть?)
AlexSpl
29 Dec 2016, 19:46 Мод на ХотА
Силач! Всё работает, спасибо smile.gif

Итого финальный код, который будет давать +1/2/3 скорости для 1го хода, по уровням тактики, при нападении на банк существ, выглядит так:

Код
int __stdcall setBankUnitBonus(LoHook* h, HookContext* c)
{
    if ( *(char*)(*(int*)0x699420 + 0x53C5) == 1) { // проверка что бой в банке существ
        if(*(char*)(c->ecx + 201 + 19) > 0) { // проверка на тактику
            *(int*)(c->esi+80) += *(char*)(c->ecx + 201 + 19);
        }
    }

    return EXEC_DEFAULT;
}

int __stdcall resetTacticsUnitSpeedBonus(LoHook* h, HookContext* c)
{
    int cmAddr =  *(int*)0x699420;
    if ( *(char*)(cmAddr + 0x53C5) == 1) { // проверка что бой в банке существ
        char tacticLevel = *(char*)(*(int*)(*(int*)0x699420 + 0x53CC) + 201 + 19);
        int roundNumber = *(int*)(cmAddr + 0x132A0) - 30000;

        if ((tacticLevel > 0) && (roundNumber == 1)) {
            if ( c->ebx == cmAddr + 0x132A0 ) {
                *(int*)(c->ecx + 196) -= tacticLevel;
            }
        }
    }

    return EXEC_DEFAULT;
}


Ну или полная ф-я, которая даёт бонусы атаки/защиты при наличии навыков артиллерия и первая помощь + боевые машины что бы были

Код
int __stdcall setBankUnitBonus(LoHook* h, HookContext* c)
{
    if ( *(char*)(*(int*)0x699420 + 0x53C5) == 1) { // проверка что бой в банке существ
        if(*(char*)(c->ecx + 201 + 19) > 0) { // проверка на тактику
            *(int*)(c->esi+80) += *(char*)(c->ecx + 201 + 19);
        }

        if(*(int*)(c->ecx + 201 + 20) > 0) { //проверка на артиллерию
            if ( *(int*)(c->ecx + 301 + (13 << 3)) == 4 ) { //13 - слот на кукле для баллисты. 4 - айди баллисты
                *(int*)(c->esi + 84) += *(int*)(c->ecx + 201 + 20);
            }
        }

        if(*(int*)(c->ecx + 201 + 27) > 0) { //проверка на палатку
            if ( *(int*)(c->ecx + 301 + (15 << 3)) == 6 ) { //15 - слот на кукле для палатки. 6 - айди палатки
                *(int*)(c->esi + 88) += *(int*)(c->ecx + 201 + 27) * 2;
            }
        }
    }

    return EXEC_DEFAULT;
}

int __stdcall resetTacticsUnitSpeedBonus(LoHook* h, HookContext* c)
{
    int cmAddr =  *(int*)0x699420;
    if ( *(char*)(cmAddr + 0x53C5) == 1) { // проверка что бой в банке существ
        char tacticLevel = *(char*)(*(int*)(*(int*)0x699420 + 0x53CC) + 201 + 19);
        int roundNumber = *(int*)(cmAddr + 0x132A0) - 30000;

        if ((tacticLevel > 0) && (roundNumber == 1)) {
            if ( c->ebx == cmAddr + 0x132A0 ) {
                *(int*)(c->ecx + 196) -= tacticLevel;
            }
        }
    }

    return EXEC_DEFAULT;
}


Лоу хуки всегда одинаковые:
Код
_PI->WriteLoHook(0x4E666A, setBankUnitBonus);
_PI->WriteLoHook(0x475A3D, resetTacticsUnitSpeedBonus);
AlexSpl
23 Dec 2016, 01:55 Мод на ХотА
Не нравится когда много дубликата кода, привожу к более вменяемому виду. не финал, но уже почти:
Код
float __stdcall getArmyValueModifier(int baseHeroOffset)
{
    int diplomacyLevel = (int)(*(char*)(baseHeroOffset + 201 + 4));
    float armyModifier[4] = {0.00, 0.10, 0.15, 19.00};
    float currentModifier = ( (diplomacyLevel >= 0) && (diplomacyLevel <= 3) ? armyModifier[diplomacyLevel] : 1 );

    float armyArtModifier = 0;
    for (int i = 0; i < 19; ++i) {
        if ( *(int*)(baseHeroOffset + 297 + (i << 3) + 4) == 66 ) {
            armyArtModifier += 40.05;
        }
    }

    return currentModifier + armyArtModifier;
}

int __stdcall setArmyValue(LoHook* h, HookContext* c)
{
    int baseHeroOffset = c->edi;
    float armyModifier = getArmyValueModifier(baseHeroOffset);
    (int)c->eax *= (1 + armyModifier);

    return EXEC_DEFAULT;
}


int __stdcall setArmyValuePreview(LoHook* h, HookContext* c)
{
    int baseHeroOffset = c->esi;
    float armyModifier = getArmyValueModifier(baseHeroOffset);
    (int)c->eax *= (1 + armyModifier);

    return EXEC_DEFAULT;
}

int __stdcall setArmyValueSplit(LoHook* h, HookContext* c)
{
    int baseHeroOffset = *(int*)(c->ebp + 8);
    float armyModifier = getArmyValueModifier(baseHeroOffset);
    (int)c->eax *= (1 + armyModifier);

    return EXEC_DEFAULT;
}


Всё работает и почти не дублирую код)
AlexSpl
18 Dec 2016, 22:37 Мод на ХотА
Цитата(AlexSpl @ 18 Dec 2016, 21:26) *
Цитата
Да! Так работает. Вообще не ясна логика когда что юзать... кроме как наугад менять

Ставь брейкпоинт на 4171E6h и смотри в каком регистре хранится указатель на героя. Т.е. G[o] -> 4171E6, F2, кастуем Visions, ПКМ, срабатывает брейкпоит, анализируем код.

https://sc-cdn.scaleengine.net/i/fbe739dbe6...02d39ddd287.png
Прошелся по коду. Там этих edi/esi уйма. И все подряд идут)

Цитата(AlexSpl @ 18 Dec 2016, 21:26) *
Попробуй так:

Код
_PI->WriteHexPatch(0x417234, "EB");  // проходим мимо бесплатного присоединения
_PI->WriteHexPatch(0x417246, "EB");  // проходим мимо платного присоединения

Работает smile.gif Круто

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


Код
float __stdcall getArmyValueModificator(int diplomatyLevel)
{

    float armyModificator = 1;

    if (diplomatyLevel > 0) {
        switch (diplomatyLevel) {
            case 1: {
                armyModificator = 1.1;
                break;
            }
            
            case 2: {
                armyModificator = 1.15;
                break;
            }
            
            case 3: {
                armyModificator = 20;
                break;
            }
        }
    }

    return armyModificator;

}

int __stdcall setArmyValue(LoHook* h, HookContext* c)
{
    int diplomatyLevel = (int)(*(char*)(c->edi + 201 + 4));
    float armyModificator = getArmyValueModificator(diplomatyLevel);
    (int)c->eax *= armyModificator;

    return EXEC_DEFAULT;
}


int __stdcall setArmyValuePreview(LoHook* h, HookContext* c)
{
    int diplomatyLevel = (int)(*(char*)(c->esi + 201 + 4));
    float armyModificator = getArmyValueModificator(diplomatyLevel);
    (int)c->eax *= armyModificator;

    return EXEC_DEFAULT;
}
AlexSpl

Текстовая версия Сейчас: 25 April 2024 - 19:32
Copyright by Алексей Крючков
Strategy Gamez by GrayMage
Programming by Degtyarev Dmitry
  Яндекс.Метрика