Здравствуйте, гость ( Вход | Регистрация )
25 Jul 2012, 11:30
(Сообщение отредактировал Iv - 10 Nov 2015, 21:49)
Сообщение
#1
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Эта тема предназначена для небольших модов, не требующих оформления отдельной темы.
Все обсуждения - в соседней теме. При выкладке указывайте:
Замена воговского таймера для Эры Всегда убивали воговские таймеры (которые TM, не TL). Их мало (сто, из них изрядная часть зарезервирована), они перегружены и вообще мастдай. В дллках оно еще более усугубляется - совершенно не хочется делать лишний хэндл для инициализации таймера, долбаться с его резервированием etc etc.. Поэтому для удобства написания дллок я набросал простенькую библиотеку, которая хукает RunTimer и посылает сообщение плагинам и ERM'у. Требует Бараторчевский патчер, ибо он трушный. Плагин: timerevent.era Проект: eratimer_code.rar Интерфейс: Простой как топор. Для ерм: функция !?FU4074700, в x1 - номер игрока (0..7), в x2 - день (1,2,3,4,5,6,7,8..) Для эры: событие OnGlobalTimer с двумя аналогичными параметрами. См. пример ниже. Повторю еще раз, требует patcher_x86.dll в корне папки с героями!! Пример (Си) Код void __stdcall TimerTest (PEvent e) { char buf[128]; int i = *(int*)(e->Data); sprintf(buf,"IF:L^%i %i^;",*(int*)(e->Data), *(1+(int*)(e->Data))); ExecErmCmd(buf); } .. RegisterHandler(TimerTest,"OnGlobalTimer"); Код: <div class="sp-wrap"><div class="sp-body" title="Код"> Код #include <windows.h> </div></div>#include <stdio.h> #include "....includeera.h" #include "....includeheroes.h" #include "....includepatcher_x86_commented.hpp" Patcher * globalPatcher; PatcherInstance *patcher; int __cdecl OnAnyTimer(HiHook* h, int owner) { ErmX[1]=owner; ErmX[2]=CALL_0(int, __cdecl ,0x7103D2); FireErmEvent(4074700); int param[2] = {owner,CALL_0(int, __cdecl ,0x7103D2)}; FireEvent("OnGlobalTimer",(void*)param,8); return EXEC_DEFAULT; } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { globalPatcher = GetPatcher(); patcher = globalPatcher->CreateInstance("timerwrapper"); ConnectEra(); patcher->WriteHiHook(0x74DC74, SPLICE_, EXTENDED_, CDECL_, (void*)OnAnyTimer); } return TRUE; } Просьба здесь особо не обсуждать. Мне куда более доставляет складывать добро в чистую тему. Спасибо сказали: |
|
|
|
![]() |
18 Aug 2012, 22:10
(Сообщение отредактировал feanor - 24 Aug 2012, 01:45)
Сообщение
#2
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Обработка копания (granite.dll)
Плагин: granite.era Проект: granite.rar Интерфейс: только для ERM. События: !?FU4074001 - происходит до раскопок (сразу после нажатия на "D") x1 - номер героя x2 - указатель на флаг отмены раскопок. !!UN:Cx2/4/0; для запрета, !!UN:Cx2/4/1; для разрешения (вариант по умолчанию) !?FU4074003 - происходит при показе какого-либо сообщения в процессе раскопок. x1 - номер героя x2 - указатель на флаг отмены показа сообщения (действие типа появления ямы не отменится!). Работа с ним опять же, через UN:C x3 - тип сообщения: 0 - "раскопки займут целый день. Приходите завтра." 1 - "инвентарь полон и раскопки будут бесполезны" (при собстна забитом инвентаре) 2 - "ищите Грааль на суше!" (при попытке выкопать яму в море) 3 - "ищите Грааль в чистом поле" (при поиске на каком-либо объекте) 4 - "поздравляем! вы нашли Грааль" (первое сообщение при успешной находке) 5 - "принесите Грааль в город.." (второе сообщение) 6 - "ничего нет. Куда подевалось?" !?FU4074002 - происходит после раскопок x1 - номер героя x2 - результат. Аналогичен x3 для FU4074003, но c добавлением варианта -1 - "раскопки отменены в 4074001" Пример (ERM) Код !?FU4074003;
!!if&x3=6:; !!UN:Cx2/4/0; !!IF:M^Держитесь подальше от торфяных болот!^; !!HE-1:Tv998/v999/v1000/47/1; !!el:; !!en:; Спасибо сказали: |
|
|
|
18 Aug 2012, 22:41
(Сообщение отредактировал feanor - 24 Aug 2012, 01:45)
Сообщение
#3
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Работа с датой (malachite.dll)
Плагин: malachite.era Дает возможность устанавливать внутригровую дату (экспортируемая функция SetDate(short day, short week, short month)), изменять анимацию нового дня/недели. При загрузке анимации нового дня/недели запускается событие OnNewDayAnimation с первым параметром - указателем на строку с именем анимации и ERM-функция 4074218, которой передаются день/неделя/месяц в x1-x3 и имя анимации в z1. Пример (ERM) Код !?FU4074218; !!VRz1&x2=4/x3=6:S^midsumm.def^; Пример (Си) Код void __stdcall Testt (PEvent e) { if (EventParams[1]==4 && EventParams[2]==6) strcpy((char*)(e->Data),"midsumm.def"); } RegisterHandler(Testt,"OnNewDayAnimation"); Код // dllmain.cpp: определяет точку входа для приложения DLL. #include <windows.h> #include <stdio.h> #include "..\..\include\era.h" #include "..\..\include\heroes.h" #include "..\..\include\patcher_x86_commented.hpp" Patcher * globalPatcher; PatcherInstance *patcher; extern "C" __declspec(dllexport) void SetDate(short day, short week, short month) { *(short*)(0x1F63E+*(int*)0x699538) = day; *(short*)(0x1F640+*(int*)0x699538) = week; *(short*)(0x1F642+*(int*)0x699538) = month; } void* __fastcall BuildAndLoadNewDayDef(void* _this, int edx, int posX, int posY, int sizeX, int sizeY, int itemId, char *defname, int cadre, int group, int mirror, int closeDialog, int flags) { short day = *(short*)(0x1F63E+*(int*)0x699538); short week = *(short*)(0x1F640+*(int*)0x699538); short month = *(short*)(0x1F642+*(int*)0x699538); strncpy(ErmZ[1],defname,512); EventParams[0]=day; EventParams[1]=week; EventParams[2]=month; FireEvent("OnNewDayAnimation",(void*)(ErmZ+1),4); ErmX[1]=day; ErmX[2]=week; ErmX[3]=month; FireErmEvent(4074218); return CALL_12(void*, __thiscall, 0x4EA800,_this, posX, posY, sizeX, sizeY, itemId, ErmZ[1], cadre, group, mirror, closeDialog, flags); } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { //инит Эры, инит патчера globalPatcher = GetPatcher(); patcher = globalPatcher->CreateInstance("malachite"); ConnectEra(); patcher->WriteHiHook(0x450CB7,CALL_,DIRECT_,THISCALL_,(void*)BuildAndLoadNewDayDef); } return TRUE; } |
|
|
|
19 Oct 2012, 20:35
Сообщение
#4
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Контроль восьмого слота (obsidian.dll) Плагин: obsidian.era События: !?FU4074810 (OnAdditionalMonsterAvailable) - происходит при каждой проверке на доступность восьмого слота. x1 - номер замка x2 - адрес его структуры x3 - указатель на флаг наличия/отсутствия оного слота. Ну, как обычно. !?FU4074811 (OnAdditionalMonsterSetting) - происходит после установки обитателей в жилище. В этом событии можно записать этих самых обитателей. x1 - номер замка x2 - адрес его структуры x3 - указатель на тип монстров x4 - указатель на количество монстров. Количество монстров записывается в два байта!! (пояснение: при помощи последних двух полей можно установить "постояльцев", не прибегая к экспортируемым функциям) Экспортируемые функции: extern "C" __declspec(dllexport) void SetAdditionalMonster(int castle_id, int type, int amount) - устанавливает в замок castle_id монстров type числом amount extern "C" __declspec(dllexport) int GetAdditionalMonsterType(int castle_id) - возвращает индекс монстра из восьмого слота замка castle_id extern "C" __declspec(dllexport) int GetAdditionalMonsterAmount(int castle_id) - возвращает количество монстров из восьмого слота замка castle_id Ну понятно по сигнатурам, да. Пример (ERM) Во всех Инферно можно нанимать 5 Монахов Баа каждую неделю. Код ZVSE !?FU4074811; !!CA0/x1:T?y10; !!SN&y10=3:L^obsidian.era^/?y10 Ay10/^SetAdditionalMonster^/?y20 Ey20/1/x1/169/5; !?FU4074810; !!CA0/x1:T?y10; !!UN&y10=3:Cx3/4/1; !?PI; !!MA:O169/3; !!VRz47:S^Монах Баа^; !!VRz48:S^Монахи Баа^; !!UN:G1/169/0/47 G1/169/1/48; Другой вариант первого триггера: Код !?FU4074811; !!CA0/x1:T?y10; !!UN&y10=3:Cx3/4/169; !!UN&y10=3:Cx4/2/5; ![]() Код // dllmain.cpp: определяет точку входа для приложения DLL. #include <windows.h> #include <stdio.h> #include "..\..\include\era.h" #include "..\..\include\heroes.h" #include "..\..\include\patcher_x86_commented.hpp" Patcher * globalPatcher; PatcherInstance *patcher; extern "C" __declspec(dllexport) void SetAdditionalMonster(int castle_id, int type, int amount) { CASTLE *cstl = ((CASTLE*)(*(int*)((*(int*)0x699538) + 0x21614) + sizeof(CASTLE) * castle_id)); cstl->EightMonsterAmount = amount; cstl->EightMonsterType = type; } extern "C" __declspec(dllexport) int GetAdditionalMonsterType(int castle_id) { CASTLE *cstl = ((CASTLE*)(*(int*)((*(int*)0x699538) + 0x21614) + sizeof(CASTLE) * castle_id)); return cstl->EightMonsterType; } extern "C" __declspec(dllexport) int GetAdditionalMonsterAmount(int castle_id) { CASTLE *cstl = ((CASTLE*)(*(int*)((*(int*)0x699538) + 0x21614) + sizeof(CASTLE) * castle_id)); return cstl->EightMonsterAmount; } int IsEighthSlotAvailable(CASTLE* cstl) { int ret = false; if (cstl->Type == 5 && cstl->Built[2]&64) ret = true; EventParams[0]=cstl->Number; EventParams[1]=(int)cstl; EventParams[2]=(int)&ret; FireEvent("OnAdditionalMonsterAvailable",0,0); ErmX[1]=cstl->Number; ErmX[2]=(int)cstl; ErmX[3]=(int)&ret; FireErmEvent(4074810); return ret; } int __stdcall hook_5BDCBF(LoHook* h, HookContext* c) { CASTLE *cstl = (CASTLE*)c->ecx; EventParams[0]=cstl->Number; EventParams[1]=(int)cstl; EventParams[2]=0x3C+(int)cstl; EventParams[3]=0x40+(int)cstl; FireEvent("OnAdditionalMonsterSetting",0,0); ErmX[1]=cstl->Number; ErmX[2]=(int)cstl; ErmX[3]=0x3C+(int)cstl; ErmX[4]=0x40+(int)cstl; FireErmEvent(4074811); return EXEC_DEFAULT; } int __stdcall hook_4C8B39(LoHook* h, HookContext* c) { CASTLE *cstl = (CASTLE*)c->ecx; if (!IsEighthSlotAvailable(cstl)) c->return_address = 0x4C8B62; else c->return_address = 0x4C8B5D; return NO_EXEC_DEFAULT; } int __stdcall hook_51D2AE(LoHook* h, HookContext* c) { CASTLE *cstl = (CASTLE*)c->esi; if (!IsEighthSlotAvailable(cstl)) c->return_address = 0x51E79B; else c->return_address = 0x51D2DB; return NO_EXEC_DEFAULT; } int __stdcall hook_5C651F(LoHook* h, HookContext* c) { CASTLE *cstl = (CASTLE*)c->esi; if (!IsEighthSlotAvailable(cstl)) c->return_address = 0x5C66D9; else c->return_address = 0x5C654D; return NO_EXEC_DEFAULT; } int __stdcall hook_5D8BD8(LoHook* h, HookContext* c) { CASTLE *cstl = (CASTLE*)c->ecx; if (!IsEighthSlotAvailable(cstl)) c->return_address = 0x5D8C08; else c->return_address = 0x5D8BFE; return NO_EXEC_DEFAULT; } int __stdcall hook_5D8C11(LoHook* h, HookContext* c) { CASTLE *cstl = (CASTLE*)c->edx; if (!IsEighthSlotAvailable(cstl)) c->return_address = 0x5D8C95; else c->return_address = 0x5D8C37; return NO_EXEC_DEFAULT; } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { //инит Эры, инит патчера globalPatcher = GetPatcher(); patcher = globalPatcher->CreateInstance("obsidian"); ConnectEra(); patcher->WriteLoHook(0x4C8B39,(void*)hook_4C8B39); //JNE SHORT 004C8B62 patcher->WriteLoHook(0x51D2AE,(void*)hook_51D2AE); //JNE 0051E79B patcher->WriteLoHook(0x5C651F,(void*)hook_5C651F); //JNE 005C66D9 patcher->WriteLoHook(0x5D8BD8,(void*)hook_5D8BD8); //JNE SHORT 005D8C08 patcher->WriteLoHook(0x5D8C11,(void*)hook_5D8C11); //JNE SHORT 005D8C08 patcher->WriteLoHook(0x5BDCBB,(void*)hook_5BDCBF); //после записи в новый день //RegisterHandler(TimerTest,"OnGlobalTimer"); } return TRUE; } Спасибо сказали: |
|
|
|
03 Jan 2013, 00:10
(Сообщение отредактировал Iv - 19 Feb 2018, 10:02)
Сообщение
#5
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Отрицательная удача (badluck.dll) (с) Sav, feanor
Плагин (SoD, Era): badluck.era, зеркало ![]() Чуть-чуть информации о функционировании удачи вообще: "удачливость" стека определяется во время атаки (собстна, немногим ранее проигрывания анимации) и записывается в структуру стека, в поле со смещением +0x70 (1 - удача, 0 - обычная атака, добавляемое плагином -1 - неудача). Проверять через ERM, соответственно, можно пресловутой командой !!BM:G, подсунув ей в качестве номера заклинания индекс -74. Потом, при нанесении ущерба это поле проверяется и уже подсчитывается собственно ущерб. Спасибо сказали: Bes, Vadim_FVE, Iv, hippocamus, Sar, Nestor, Algor, Vade Parvis, XEPOMAHT, dik X.B., StasPV, packa, Berserker, SerAlexandr, totkotoriy, Sav, DrSlash, Orzie, Ethereal |
|
|
|
08 Feb 2013, 15:55
(Сообщение отредактировал Iv - 19 Feb 2018, 10:04)
Сообщение
#6
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Настраиваемые имена классов (turquoise.dll)
Плагин: turquoise.zip, зеркало Позволяет настраивать индивидуальное имя класса для каждого героя (аналогично Джем из стандартных кампаний SoD), как с помощью конфигурационного файла (приложен в архиве), так и динамически, с помощью SN:W-переменных с именем hero_class_name_<hero_id>. Иллюстрация: ![]() Код Patcher * globalPatcher; PatcherInstance *patcher; _ptr_ GetClassNameDefault; char* GetClassName(HERO* hero) { char tmp[64]; sprintf(tmp,"SN:W^hero_class_name_%i^/?z1;", hero->Number); ExecErmCmd(tmp); if(ErmZ[1][0]!=0) { return ErmZ[1]; } return CALL_1(char*, __thiscall, GetClassNameDefault, hero); } void __stdcall InitNames(PEvent e) { char tmp[1024]; char tmp_erm[1024]; for(int i=0; i!=256;i++) { sprintf(tmp,"Hero%i",i); ReadStrFromIni(tmp, "Classnames", "turquoise.ini", (char*)tmp); if (*tmp) { sprintf(tmp_erm,"SN:W^hero_class_name_%i^/^%s^;", i, tmp); ExecErmCmd(tmp_erm); } } } char* __stdcall GetClassName_hook(HiHook* h, HERO* hero) { return GetClassName(hero); } int __stdcall hook_4E1(LoHook* h, HookContext* c) { c->ecx = (int)GetClassName((HERO*)(c->eax)); return EXEC_DEFAULT; } int __stdcall hook_4DB(LoHook* h, HookContext* c) { c->eax = (int)GetClassName((HERO*)(c->ecx)); return EXEC_DEFAULT; } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { //инит Эры, инит патчера globalPatcher = GetPatcher(); patcher = globalPatcher->CreateInstance(PINSTANCE_MAIN); ConnectEra(); RegisterHandler(InitNames, "OnBeforeErmInstructions"); RegisterHandler(InitNames, "OnAfterCreateWindow"); HiHook *h = patcher->WriteHiHook(0x4D91E0,SPLICE_,EXTENDED_,THISCALL_,(void*)GetClassName_hook); GetClassNameDefault = h->GetDefaultFunc(); patcher->WriteLoHook(0x4E1DE6, (void*)hook_4E1); patcher->WriteLoHook(0x4DB980, (void*)hook_4DB); patcher->WriteLoHook(0x4DBDF7, (void*)hook_4DB); } return TRUE; } Спасибо сказали: |
|
|
|
28 Mar 2013, 14:27
Сообщение
#7
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Вызовы элементалей (summoniots.dll)
Плагин: summoniots.dll Позволяет подменять результаты заклинаний вызова элементалей. Помимо этого, отключает невозможность применения более чем одного заклинания вызова. События: !?FU4074520 - попытка вызова. x1 - указатель на флаг того, сработает ли заклинание (не сработавшее заклинание тратит ману и магический ход, но ничего не делает) x2 - указатель на номер заклинания x3 - указатель на номер существа x4 - указатель на уровень колдовской силы, используемый при расчете количества вызванных. Пример (ERM): Вызов чародеев вместо любого из элементалей. Код ZVSE !?FU4074520; !!UN:Cx3/4/?y1; --кого вызываем !!BG:H?y3; !!IF:L^Hero %Y3 trying to summon %Y1..^; !!UN:Cx3/4/136; !!UN:Cx4/4/999; !!UN:Cx3/4/?y1; !!IF:L^..but summons horde of %Y1^; Код Patcher * globalPatcher; PatcherInstance *citrine; int __stdcall SummonHook(HiHook* h, _BattleMgr_ *combatman, int spell, int creature, int spellpower, int unk) { int flag = 1; ((int*)0x91DA34)[1] = (int)(&flag); ((int*)0x91DA34)[2] = (int)(&spell); ((int*)0x91DA34)[3] = (int)(&creature); ((int*)0x91DA34)[4] = (int)(&spellpower); ((int*)0x91DA34)[5] = (int)(&unk); ((int*)0x91DA34)[6] = (int)combatman+combatman->current_side*4+0x132C0; CallERM(4074520); return flag?CALL_5(int, __thiscall, h->GetDefaultFunc(), (int)combatman, spell, creature, spellpower, unk):-1; } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { globalPatcher = GetPatcher(); citrine = globalPatcher->CreateInstance("summon_elems"); citrine->WriteHiHook(0x5A7390, SPLICE_, EXTENDED_, THISCALL_, (void*)SummonHook); citrine->WriteByte(0x59F887,0xEB); citrine->WriteWord(0x5A96D0, 0x9090); } return TRUE; } Спасибо сказали: |
|
|
|
17 Jul 2013, 18:31
(Сообщение отредактировал feanor - 17 Jul 2013, 18:31)
Сообщение
#8
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Гильдия воров вместо "Братства меча" в Замке.
Надстройка над таверной теперь исполняет функции представительства Гильдии Воров: при её постройке соответствующее меню в таверне будет показывать полную информацию о противниках и союзниках. Цена строения - прежняя, 500 золота и 5 дерева. Автор: feanor Язык: русский (изменена одна строчка в bldgspec.txt) Формат: zip-архив с папкой мода. thiefguild.zip (3,32 Кб) |
|
|
|
18 Jul 2013, 13:31
(Сообщение отредактировал Iv - 18 Jul 2013, 13:33)
Сообщение
#9
|
|
![]() Immortal Сообщений: 6 287 Спасибо сказали: 12723 раза |
Другие флаги игроков
![]() Автор: Iv (с участием Algor) Язык: нет Формат: pac-файл для Era 2.*. Кинуть в папку любого мода http://sites.google.com/site/hommfun/files...ive%20flags.pac (390 кб) -------------------- Спасибо сказали: |
|
|
|
25 Jul 2013, 08:00
(Сообщение отредактировал feanor - 25 Jul 2013, 16:18)
Сообщение
#10
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Несколько небольших патчей.
Автор: feanor Язык: нет Формат: bin-файлы. Установка через копирование в eraplugins/afterwog любого мода. Нет подземелий в подземельях. Тип поля боя на подземном уровне будет определяться типом почвы. В оригинале все бои в подземке проходили на подземной почве. no_underground_at_underground.bin Исправление вылета при проигрыше битвы в ERM-событии При проигрыше битвы, вызванной в триггере !?HM, игра вылетала. Теперь - нет. fix_encounter_crash.bin Отключение исключений при старте карты При рестарте карты OllyDbg отвлекается на какое-то исключение, что вынуждает переключаться между игрой и отладчиком. Теперь - нет. Плагин нужен лишь при анализе игры! Не уверен в отсутствии побочных эффектов. no_raise_exception_at_map_loading.bin |
|
|
|
25 Jul 2013, 16:02
Сообщение
#11
|
|
![]() Immortal Сообщений: 6 287 Спасибо сказали: 12723 раза |
Зомбивод (39 б)
Автор: Master of puppets Язык: нет Формат: bin-арник для Эры. Кинуть в папку eraplugins/afterwog Описание: Стракер поднимает не скелетов, а зомби -------------------- |
|
|
|
01 Aug 2013, 14:30
(Сообщение отредактировал feanor - 01 Aug 2013, 14:32)
Сообщение
#12
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Часы реального времени.
![]() ПКМ по дате на экране карты выведет реальное время и заряд батареи (при наличии таковой). Для играющих в полноэкранном режиме. Автор: feanor Язык: английский Формат: erm-скрипт. Установка через копирование в data/s любого мода. clock.erm (1,13 Кб) Спасибо сказали: Bes, Iv, hippocamus, GORynytch, Nestor, Algor, Starseeker, Throutle, packa, Etoprostoya, Berserker, SerAlexandr, Orzie, Ethereal |
|
|
|
16 Sep 2013, 00:59
Сообщение
#13
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Еженедельная газета "Голос из-под стойки".
![]() В начале каждой недели в чат выводятся текущие слухи и имена героев-наемников. Автор: feanor Язык: русский. Формат: zip-архив с папкой мода. daily_event.zip (5.36 кб) Спасибо сказали: Vadim_FVE, Iv, fireman, hippocamus, Algor, Adept, dik X.B., Berserker, SerAlexandr, Арысь-Поле, Orzie, Ethereal, Samail |
|
|
|
19 Sep 2013, 23:55
(Сообщение отредактировал Iv - 10 Nov 2015, 21:46)
Причина редактирования: Дополнил описание
Сообщение
#14
|
||
![]() Immortal Сообщений: 6 287 Спасибо сказали: 12723 раза |
-Why do you call your software "beta"?
-'coz it's beta than nothing. Замена вызовов, версия 0.3 Вызовы элементалей заменяются на вызовы других существ В мод включена измененная раскладка заклинаний. Автор: Iv (с участием Algor) Язык: русский Формат: архив с папкой мода для Эры 2.х https://dl.dropboxusercontent.com/u/5852703.../H3IVsummon.exe -------------------- |
|
|
|
||
21 Sep 2013, 23:13
(Сообщение отредактировал igrik - 03 Dec 2013, 15:37)
Сообщение
#15
|
|
![]() Immortal Сообщений: 589 Спасибо сказали: 891 раз |
Рюкзак героя
Версия 1.04. Автор: igrik Язык: русский и английский Формат: архив с папкой мода для ERA II Спасибо Berserker, baratoch. Функция аналогичная функции в HDmod, но с меньшим функционалом (не реализована и не планируется передача артов по Ctrl, Shift, Alt) Совместима с большинством модов (за исключением Феникс-Мода! ввиду пересечения расположения кнопок) Поддерживает Hot Seat, TCP/IP, новые артефакты от feanor'a "emerald.dll v2.01" и т.п. Спасибо: Berserker, baratorch. Скачать Rus Скачать Eng ![]() ![]() ![]() ![]() ![]() ********* Исправлено: [+] Нормальное отображение описания артефактов! За что огромное спасобо Berserker'у! [-] Больше не используется файл "artifact.def", который мог перекрывать аналогичный из других модов. [-] Исправлен баг, при котором игра вылетала если в рюкзаке лежала книга заклинаний. [-] Исправлен баг вследствие некорректного действия команды "HE:A1". [+] Улучшена подложка [+] Подсказка при наведении мыши на элемент диалога. (для временного хранения используются переменные z1 - z65) -------------------- |
|
|
|
13 Mar 2014, 13:14
Сообщение
#16
|
|
![]() Immortal Сообщений: 6 287 Спасибо сказали: 12723 раза |
Случайные нейтральные герои
Нейтралы с вероятностью 10/20/30/40/50% в зависимости от уровня сложности получают героя-предводителя, который будет сражаться на их стороне в бою против игрока-человека. ![]() Автор: Algor, Iv Формат: sfx-архив с папкой мода. Randomhero.exe (306 Кб) -------------------- |
|
|
|
22 Apr 2014, 20:39
(Сообщение отредактировал feanor - 22 Apr 2014, 20:42)
Сообщение
#17
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Статуя Ленина в Инферно вместо Бога Огня
Автор: feanor Формат: архив с папкой мода. ![]() https://dl.dropboxusercontent.com/u/61759222/HoMM/lenin.zip Спасибо сказали: Mantiss, Bes, Docent Picolan, hippocamus, GORynytch, Agar, Algor, dik X.B., DRONыч, Etoprostoya, Kislolord, Axolotl, Арысь-Поле, DrSlash, Orzie, dr0n, Samail |
|
|
|
15 Jun 2014, 20:37
Сообщение
#18
|
|
![]() Immortal Сообщений: 6 287 Спасибо сказали: 12723 раза |
Родная грязь (dirt) для Подземелья
Маленький патчик для рандомок без подземного уровня. На них Подземелье генерится на грязи, но бонуса родной земли не получает. Патчик исправляет эту несправедливость. Автор: Iv Формат: bin-файл для Era II. Класть в \EraPlugins\AfterWoG\ -------------------- Спасибо сказали: |
|
|
|
15 Jul 2014, 13:12
(Сообщение отредактировал Orzie - 15 Jul 2014, 13:23)
Сообщение
#19
|
|
![]() Immortal Сообщений: 7 870 Спасибо сказали: 16070 раз |
Культ Вождя Мирового Пролетариата
Авторы: feanor, Orzie, Docent Picolan, Bes Формат: SFX-архив мода для ERA II, спрашивающий директорию установленной игры. Апгрейд мода "Статуя Ленина в Инферно вместо Бога Огня" Определённые строения в Инферно, Некрополисе и Замке будут содержать различные образы вождя пролетариата - В.И.Ленина. ![]() https://app.box.com/s/qmfj3km81roz85tutojf Спасибо сказали: |
|
|
|
31 Jul 2014, 22:57
(Сообщение отредактировал feanor - 01 Aug 2014, 00:09)
Сообщение
#20
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Магические сундуки
Сундуки с артефактами теперь отличаются по виду от сундуков с золотом. Автор: Axolotl, feanor Язык: нет Формат: zip-архив с папкой мода. magechest.zip (14 Кб)
Спасибо сказали: |
|
|
|
03 Feb 2015, 19:06
Сообщение
#21
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Вуду-гарпии.
Иногда гарпии-ведьмы будут атаковать с места, не приближаясь к противнику. Анимация этой атаки будет отличаться от обычной. Автор: feanor Язык: нет Формат: erm-скрипт. Установка через копирование в data/s любого мода. voodoo.erm (1 Кб)
Спасибо сказали: |
|
|
|
10 Feb 2015, 03:13
Сообщение
#22
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Иной формат даты.
Дни недели и месяцы именуются, а не нумеруются. Автор: feanor Язык: русский Формат: dll-плагин. Установка через копирование в /eraplugins любого мода. human_month_names.dll (8,5 Кб)
Спасибо сказали: |
|
|
|
10 Feb 2015, 20:56
(Сообщение отредактировал feanor - 10 Feb 2015, 21:04)
Сообщение
#23
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Иные виды снарядов-лучей.
Архимаги стреляют молниеподобными лучами, бехолдеры - лучами разноцветными (семь цветов радуги). Автор: feanor Язык: нет Формат: erm-скрипт. Установка через копирование в data/s любого мода. Старая тема: http://forum.df2.ru/index.php?showtopic=22685 rays.erm (1 Кб)
|
|
|
|
12 Feb 2015, 16:27
Сообщение
#24
|
|
![]() допустим, мяў Сообщений: 24 165 Спасибо сказали: 13533 раза |
Приручённые нейтралы
Большинство нейтралов теперь принадлежат фракциям, к которым они сродны. Орки на кабанах - Цитадель Мумии - Некрополис Тролли - Крепость Крестьне - Замок Воры - Темница Хоббиты - Башня Внефракционными остались высшие драконы, чародеи, снайперы и кочевники (есть соблазн приписать их к Сопряжению - по антуражу подходят, но стоит ли?) автор: hippocamus формат: bin для SOD, HotA + HD (возможно Era) язык: отсутствует Скачать (76 байт) Кампанейские герои доступны как стартовые На случайных картах можно стартовать любым героем автор: возможно, МоП (я взял из ExeBuilder и перебил адреса, адаптировал под ХД) формат: bin для SoD+HD (под Хоту не работает) язык: отсутствует Скачать (301 байт) -------------------- Вокруг столько фильмов, книг, музыки - а природа какая невероятная!
Если тебе скучно жить - ты совсем дурак. (Татьяна Черниговская) |
|
|
|
19 Feb 2015, 23:46
Сообщение
#25
|
|
![]() Immortal Сообщений: 6 287 Спасибо сказали: 12723 раза |
Больше колодцев для бога колодцев
Маленький патчик для рандомок. На карте генерится больше колодцев. Иногда даже слишком много Автор: Iv (инфа от Sav) Формат: bin-файл для Era II. Класть в \EraPlugins\AfterWoG\ любого активного мода
-------------------- |
|
|
|
13 Mar 2015, 23:57
(Сообщение отредактировал feanor - 14 Mar 2015, 00:00)
Сообщение
#26
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
В честь минувших праздников полового диморфизма..
Зависящие от пола имена классов. Автор: feanor Язык: русский Формат: папка с модом. gcn.zip (6 Кб)
|
|
|
|
14 Aug 2016, 00:56
Сообщение
#27
|
|
![]() laughed as one fey Сообщений: 12 167 Спасибо сказали: 20610 раз |
Анимированные существа на поле боя (порт из WoG 3.59)
Автор: sergroj Портировано: feanor в рамках проекта TSW; разрешение автора получено. Формат: папка с модом. InstantAnimation.zip, 7 Кб Скорости анимаций настраиваются индивидуально для каждого типа существ в файле anims.ini; существующие параметры взяты из блока monanim0 хотовского HotA.dat (версия 1.3.4), для вог-монстров взято по подобию. Помимо этого, есть глобальный множитель, позволяющий ускорить или замедлить анимацию для всех монстров без пересчета всех параметров. Спасибо сказали: |
|
|
|
21 Oct 2016, 19:17
(Сообщение отредактировал igrik - 10 Aug 2017, 09:57)
Сообщение
#28
|
|
![]() Immortal Сообщений: 589 Спасибо сказали: 891 раз |
Цифровое отображение морали и удачи в окне стека.
Как в MOP автор: igrik язык: нет формат: dll (плагин для HD-мода) версии: SoD/WoG/ERA NumMoralLuck.dll (8.50kb) Код ///////////////////////////////////////////////////////// // Расширение диалога монстров: // // - отображение единиц удачи и морали (igrik) // // - отображение длительности заклинаний (из HotA) // ///////////////////////////////////////////////////////// #include "..\..\include\homm3.h" // Объекты patcher_x86. Patcher* _P; PatcherInstance* _PI; int __stdcall Y_MoralLuckBonus(LoHook* h, HookContext* c) { // цифровое отображение морали if (*(int*)(c->edi+1256) < 1) sprintf(o_TextBuffer, "%d", *(int*)(c->edi+1256)); else sprintf(o_TextBuffer, "+%d", *(int*)(c->edi+1256)); int bonMoralNew = CALL_1 (int, __cdecl, 6386834, 80); int bonMoral = CALL_12 (int, __thiscall, 6014624, bonMoralNew, 48, 209, 20, 20, o_TextBuffer, "tiny.fnt", 4, 3006, 10, 0, 8); CALL_4 (int, __thiscall, 0x5FE2D0, c->ebx, *(int*)(c->ebx+8), 1, &bonMoral); // цифровое отображение удачи if (*(int*)(c->edi+1260) < 1) sprintf(o_TextBuffer, "%d", *(int*)(c->edi+1260)); else sprintf(o_TextBuffer, "+%d", *(int*)(c->edi+1260)); int bonLuckNew = CALL_1 (int, __cdecl, 6386834, 80); int bonLuck = CALL_12 (int, __thiscall, 6014624, bonLuckNew, 101, 209, 20, 20, o_TextBuffer, "tiny.fnt", 4, 3007, 10, 0, 8); CALL_4 (int, __thiscall, 0x5FE2D0, c->ebx, *(int*)(c->ebx+8), 1, &bonLuck); return EXEC_DEFAULT; } int __stdcall Y_MoralLuckBonus2(LoHook* h, HookContext* c) { if (*(int*)(c->ebx+104) < 1) sprintf(o_TextBuffer, "%d", *(int*)(c->ebx+104)); else sprintf(o_TextBuffer, "+%d", *(int*)(c->ebx+104)); int bonMoralNew = CALL_1 (int, __cdecl, 6386834, 80); int bonMoral = CALL_12 (int, __thiscall, 6014624, bonMoralNew, 48, 209, 20, 20, o_TextBuffer, "tiny.fnt", 4, 3006, 10, 0, 8); CALL_4 (int, __thiscall, 0x5FE2D0, c->ebx+48, *(int*)(c->ebx+56), 1, &bonMoral); // отображение единиц удачи if (*(int*)(c->ebx+124) < 1) sprintf(o_TextBuffer, "%d", *(int*)(c->ebx+124)); else sprintf(o_TextBuffer, "+%d", *(int*)(c->ebx+124)); int bonLuckNew = CALL_1 (int, __cdecl, 6386834, 80); int bonLuck = CALL_12 (int, __thiscall, 6014624, bonLuckNew, 101, 209, 20, 20, o_TextBuffer, "tiny.fnt", 4, 3007, 10, 0, 8); CALL_4 (int, __thiscall, 0x5FE2D0, c->ebx+48, *(int*)(c->ebx+56), 1, &bonLuck); return EXEC_DEFAULT; } int __stdcall Y_SpellShow(LoHook* h, HookContext* c) { // цифровое отображение длительности заклинаний (вытащено из HotA.dll) int Spell = *(int*)(c->esi); int DlgShow = *(int*)(c->ebp-40); if (Spell >=0) { if (Spell == 47 || Spell == 59 || Spell == 72) int Spell = 47; else { sprintf(o_TextBuffer, "x%d", *(int*)(c->esi+12)); int SpellNew = CALL_1 (int, __cdecl, 6386834, 80); int SpellShow = CALL_12 (int, __thiscall, 6014624, SpellNew, *(int*)(c->ebp-28), 202, 46, 20, o_TextBuffer, "tiny.fnt", 4, 3003 - *(int*)(c->ebp-32), 10, 0, 8); CALL_4 (int, __thiscall, 0x5FE2D0, DlgShow + 48, *(int*)(DlgShow +56), 1, &SpellShow); } } return EXEC_DEFAULT; } int __stdcall Y_SpellInfo1(LoHook* h, HookContext* c) { // в этой функции я не смог поставить HiHook // потому что в WoGе после её выполнения вылетает if( c->eax >= 3000 && c->eax <= 3007 ) { switch (c->eax){ case 3000: c->eax = 11; break; // спелл_1 case 3001: c->eax = 11; break; // спелл_2 case 3002: c->eax = 11; break; // спелл_3 case 3006: c->eax = 9; break; // мораль case 3007: c->eax = 10; break; // удача default: c->eax = -1; break; // на всякий } c->return_address = 0x5F4B34; return NO_EXEC_DEFAULT; } return EXEC_DEFAULT; } int __stdcall Y_SpellInfo2(LoHook* h, HookContext* c) { // подсказка для циферных отображений спеллов, морали и удачи switch (c->esi){ case 3000: c->esi = 221; break; // спелл_1 case 3001: c->esi = 222; break; // спелл_2 case 3002: c->esi = 223; break; // спелл_3 case 3006: c->esi = 219; break; // мораль case 3007: c->esi = 220; break; // удача } return EXEC_DEFAULT; } int __stdcall Y_SpellShow1(LoHook* h, HookContext* c) { int New = CALL_1 (int, __cdecl, 0x617492, 80); int SpellShow = CALL_12 (int, __thiscall, 6014624, New, 15, c->ebx + 16, 46, 20, "", "tiny.fnt", 4, c->edi + 3003, 10, 0, 8); CALL_4 (int, __thiscall, 0x4230D0, c->esi, *(int*)(c->esi + 8), 1, &SpellShow); return EXEC_DEFAULT; } int __stdcall Y_SpellShow2(LoHook* h, HookContext* c) { int New = CALL_1 (int, __cdecl, 0x617492, 80); int SpellShow = CALL_12 (int, __thiscall, 6014624, New, 15, *(int*)(c->ebp + 24) + 16, 46, 20, "", "tiny.fnt", 4, c->ebx + 3003, 10, 0, 8); CALL_4 (int, __thiscall, 0x4230D0, c->esi, *(int*)(c->esi + 8), 1, &SpellShow); return EXEC_DEFAULT; } int __stdcall Y_SpellShow3(LoHook* h, HookContext* c) { _Dlg_* dlg = (_Dlg_*)(c->edi + 56); int item = 3006 - *(int*)(c->ebp + 8); int spell = *(int*)c->esp - 1; if (spell >= 0 && spell != 47 && spell != 59 && spell != 72) sprintf(o_TextBuffer, "x%d", *(int*)(c->esi + 4 * spell + 408)); else sprintf(o_TextBuffer, ""); ((_DlgStaticText_*)dlg->GetItem(item))->SetText(o_TextBuffer); return 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("MonDescription"); // Патч на tiny.fnt малые описания монстров (все в DEC) *(int*)6243434 = 6687924; // в бою *(int*)6244485 = 6687924; // при покупке *(int*)6241855 = 6687924; // не в бою _PI->WriteLoHook(0x5F3C43, Y_MoralLuckBonus); // мораль и удача в бою _PI->WriteLoHook(0x5F439B, Y_MoralLuckBonus2); // мораль и удача вне в боя // отображение длительности заклинаний в окне монстра (вытащено из HotA.dll) _PI->WriteLoHook(0x5F6BE2, Y_SpellShow); _PI->WriteLoHook(0x5F4B05, Y_SpellInfo1); // тут WoG/ERA не дают поставить HiHook _PI->WriteLoHook(0x5F522A, Y_SpellInfo2); // отображение длительности заклинаний в расширенной статистике (вытащено из HotA.dll) _PI->WriteLoHook(0x46D12B, Y_SpellShow1); _PI->WriteLoHook(0x46D4CB, Y_SpellShow2); _PI->WriteLoHook(0x46D9F0, Y_SpellShow3); } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
-------------------- Спасибо сказали: |
|
|
|
08 Aug 2017, 21:11
(Сообщение отредактировал Ben - 15 Sep 2017, 13:18)
Сообщение
#29
|
|
|
Power Member Сообщений: 198 Спасибо сказали: 134 раза |
Новая версия заклинания Городской портал
Авторы: AlexSpl, Ben Dll плагин к HD моду. Теперь на любом уровне магии Земли можно выбирать город. Существенно увеличились расходы MP - для основного уровня 1200 MP, для продвинутого 1000 MP, для эксперта 800 MP. AI в курсе введенных изменений, применяет Городской портал для перемещения в нужный город, даже не имея навыка Магия Земли. Код #include "..\..\include\homm3.h" // объекты patcher_x86. Patcher* _P; PatcherInstance* _PI; int __stdcall tpCostForHuman(LoHook* h, HookContext* c) { *(int*)(c->ebp - 0x40) = 1200; *(int*)(c->ebp - 0x3C) = 1200; *(int*)(c->ebp - 0x38) = 1000; *(int*)(c->ebp - 0x34) = 800; return EXEC_DEFAULT; } int __stdcall skipTownPortalConfirm(LoHook* h, HookContext* c) { if ( c->eax == -1 ) { c->ecx = *(unsigned char*)(c->edi + 5); // Выполняем затёртую jmp-патчем команду c->return_address = 0x41D990; // Обходим jmp-патч return NO_EXEC_DEFAULT; } c->return_address = 0x41D939; return NO_EXEC_DEFAULT; } int __stdcall mpointsEarth_1(LoHook* h, HookContext* c) { int level = c->eax; int mpoints[] = {1200, 1200, 1000, 800}; c->eax = mpoints[level]; c->return_address = 0x56B5AA; return NO_EXEC_DEFAULT; } int __stdcall mpointsEarth_2(LoHook* h, HookContext* c) { int level = c->eax; int mpoints[] = {1200, 1200, 1000, 800}; c->eax = mpoints[level]; c->ecx = *(int*)(c->esi + 0x4D); c->return_address = 0x430532; 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.TownPortal"); _PI->WriteLoHook(0x41D538, tpCostForHuman); // меняем расходы MP c 300/300/200 на 1200/1000/800 _PI->WriteHexPatch(0x41D6D1, "90 90 90 90 90 90 90 90 90 90"); // отменяем проверку на уровень Магии Земли в главной функции заклинания _PI->WriteLoHook(0x56B59B, mpointsEarth_1); // расходы MP во вспомогат. функции 1 _PI->WriteHexPatch(0x56B3B4, "90 90 90 90 90 90"); // отменяем проверку на уровень Магии Земли во вспомогат. функции 1 _PI->WriteLoHook(0x430520, mpointsEarth_2); // расходы MP во вспомогат. функции 2 _PI->WriteLoHook(0x41D934, skipTownPortalConfirm); // обходим jmp патч HD мода (версии 3.809 и выше) } break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } Ссылка на DLL: https://yadi.sk/d/BMehvHpF3MuoqR |
|
|
|
09 Aug 2017, 17:47
(Сообщение отредактировал igrik - 09 Aug 2017, 17:59)
Сообщение
#30
|
|
![]() Immortal Сообщений: 589 Спасибо сказали: 891 раз |
А где сама DLL?
Кстати забыл. Тестировал. Багов не обнаружил, поэтому включил и в мультиплеере. Автоулучшение существ в городе. автор: [igrik] язык: нет формат: dll (плагин для HD-мода) версии: SoD/HotA/ERA HD_Plugin.AutoGradeMonInTown (10.5kb) Плагин позволяет улучшать существ в городе по комбинации клавиш [ЛКМ+A] (левая кнопка мыши + "A" в английской раскладке или "Ф" в русской раскладке): - [ЛКМ+A] на иконке героя (или флаге): улучшение всех существ у данного героя/города. Исключения: Скелеты в Скелетов-Воинов, Корсары в Морских Волков (для HotA), специалисты по улучшению существ (например Джелу); - [ЛКМ+A] на стеке: улучшение выбранного стека. Исключения: Корсары в Морских Волков (для HotA), специалисты по улучшению существ (например Джелу); Поддерживаемые версии HoMM3: SoD, HotA, ERA/WoG. Способ установки: это плагин для HD мода и его необходимо скопировать в "..[Ваша папка героев]\_HD3_Data\Packs\[Любое название]\.." и подключить это "Любое название" в лаунчере HD мода. Код ////////////////////////////////////////////////////////// // Плагин автоматического улучшения существ в городе // // Автор: [igrik] // ///////////////////////////////////////////////////////// #include "..\..\include\homm3.h" // Объекты patcher_x86. Patcher* _P; PatcherInstance* _PI; // улучшение всех стеков у героя или в городе _bool_ Y_AutoGradeMonInTownFunc(_Town_* town, char type){ _Player_* me = o_GameMgr->GetMe(); int cost_res[7]; if (!me->IsActive()) return false; if (type != 0 ) // если не город { _Hero_* hero = 0; if (type == 1) hero = o_GameMgr->GetHero(town->up_hero_id); else hero = o_GameMgr->GetHero(town->down_hero_id); if (me->id != hero->owner_id) return false; for (char i = 0; i < 7; i++ ) { if( hero->army.type[i] >= 0 ) { if ( GetCreatureGrade(hero->army.type[i]) != -1 && hero->army.type[i] != 158 && hero->army.type[i] != 56) { if( town->IsBuildingBuilt(37 + o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].level, 1) && town->type == o_pCreatureInfo[hero->army.type[i]].town ) { cost_res[0] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.wood * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.wood * hero->army.count[i]); cost_res[1] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.mercury * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.mercury * hero->army.count[i]); cost_res[2] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.ore * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.ore * hero->army.count[i]); cost_res[3] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.sulfur * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.sulfur * hero->army.count[i]); cost_res[4] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.crystal * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.crystal * hero->army.count[i]); cost_res[5] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.jems * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.jems * hero->army.count[i]); cost_res[6] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.gold * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.gold * hero->army.count[i]); if (me->resourses.wood >= cost_res[0] && me->resourses.mercury >= cost_res[1] && me->resourses.ore >= cost_res[2] && me->resourses.sulfur >= cost_res[3] && me->resourses.crystal >= cost_res[4] && me->resourses.jems >= cost_res[5] && me->resourses.gold >= cost_res[6]) { me->resourses.wood -= cost_res[0]; me->resourses.mercury -= cost_res[1]; me->resourses.ore -= cost_res[2]; me->resourses.sulfur -= cost_res[3]; me->resourses.crystal -= cost_res[4]; me->resourses.jems -= cost_res[5]; me->resourses.gold -= cost_res[6]; hero->army.type[i] = GetCreatureGrade(hero->army.type[i]); } } } } } return true; } else { if (me->id != town->owner_id) return false; for (char i = 0; i < 7; i++ ) { if( town->guards.type[i] >= 0 ) { if ( GetCreatureGrade(town->guards.type[i]) != -1 && town->guards.type[i] != 158 && town->guards.type[i] != 56) { if( town->IsBuildingBuilt(37 + o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].level, 1) && town->type == o_pCreatureInfo[town->guards.type[i]].town ) { cost_res[0] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.wood * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.wood * town->guards.count[i]); cost_res[1] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.mercury * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.mercury * town->guards.count[i]); cost_res[2] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.ore * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.ore * town->guards.count[i]); cost_res[3] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.sulfur * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.sulfur * town->guards.count[i]); cost_res[4] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.crystal * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.crystal * town->guards.count[i]); cost_res[5] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.jems * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.jems * town->guards.count[i]); cost_res[6] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.gold * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.gold * town->guards.count[i]); if (me->resourses.wood >= cost_res[0] && me->resourses.mercury >= cost_res[1] && me->resourses.ore >= cost_res[2] && me->resourses.sulfur >= cost_res[3] && me->resourses.crystal >= cost_res[4] && me->resourses.jems >= cost_res[5] && me->resourses.gold >= cost_res[6]) { me->resourses.wood -= cost_res[0]; me->resourses.mercury -= cost_res[1]; me->resourses.ore -= cost_res[2]; me->resourses.sulfur -= cost_res[3]; me->resourses.crystal -= cost_res[4]; me->resourses.jems -= cost_res[5]; me->resourses.gold -= cost_res[6]; town->guards.type[i] = GetCreatureGrade(town->guards.type[i]); } } } } } return true; } return false; } // улучшение одного стека у героя _bool_ Y_AutoGradeMonInTownOne_H(_Town_* town, char type, char i) { _Player_* me = o_GameMgr->GetMe(); if (!me->IsActive()) return false; int cost_res[7]; _Hero_* hero = 0; if (type == 1) hero = o_GameMgr->GetHero(town->up_hero_id); else hero = o_GameMgr->GetHero(town->down_hero_id); if (me->id != hero->owner_id || hero->army.type[i] == -1 ) return false; if ( GetCreatureGrade(hero->army.type[i]) != -1 && hero->army.type[i] != 158 ) { if( town->IsBuildingBuilt(37 + o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].level, 1) && town->type == o_pCreatureInfo[hero->army.type[i]].town ) { cost_res[0] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.wood * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.wood * hero->army.count[i]); cost_res[1] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.mercury * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.mercury * hero->army.count[i]); cost_res[2] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.ore * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.ore * hero->army.count[i]); cost_res[3] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.sulfur * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.sulfur * hero->army.count[i]); cost_res[4] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.crystal * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.crystal * hero->army.count[i]); cost_res[5] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.jems * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.jems * hero->army.count[i]); cost_res[6] = (o_pCreatureInfo[GetCreatureGrade(hero->army.type[i])].cost.gold * hero->army.count[i]) - (o_pCreatureInfo[hero->army.type[i]].cost.gold * hero->army.count[i]); if (me->resourses.wood >= cost_res[0] && me->resourses.mercury >= cost_res[1] && me->resourses.ore >= cost_res[2] && me->resourses.sulfur >= cost_res[3] && me->resourses.crystal >= cost_res[4] && me->resourses.jems >= cost_res[5] && me->resourses.gold >= cost_res[6]) { me->resourses.wood -= cost_res[0]; me->resourses.mercury -= cost_res[1]; me->resourses.ore -= cost_res[2]; me->resourses.sulfur -= cost_res[3]; me->resourses.crystal -= cost_res[4]; me->resourses.jems -= cost_res[5]; me->resourses.gold -= cost_res[6]; hero->army.type[i] = GetCreatureGrade(hero->army.type[i]); return true; } } } return false; } // улучшение одного стека в городе без героя _bool_ Y_AutoGradeMonInTownOne_T(_Town_* town, char type, char i) { _Player_* me = o_GameMgr->GetMe(); if (!me->IsActive()) return false; int cost_res[7]; if (me->id != town->owner_id || town->guards.type[i] == -1 ) return false; if ( GetCreatureGrade(town->guards.type[i]) != -1 && town->guards.type[i] != 158 ) { if( town->IsBuildingBuilt(37 + o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].level, 1) && town->type == o_pCreatureInfo[town->guards.type[i]].town ) { cost_res[0] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.wood * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.wood * town->guards.count[i]); cost_res[1] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.mercury * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.mercury * town->guards.count[i]); cost_res[2] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.ore * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.ore * town->guards.count[i]); cost_res[3] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.sulfur * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.sulfur * town->guards.count[i]); cost_res[4] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.crystal * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.crystal * town->guards.count[i]); cost_res[5] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.jems * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.jems * town->guards.count[i]); cost_res[6] = (o_pCreatureInfo[GetCreatureGrade(town->guards.type[i])].cost.gold * town->guards.count[i]) - (o_pCreatureInfo[town->guards.type[i]].cost.gold * town->guards.count[i]); if (me->resourses.wood >= cost_res[0] && me->resourses.mercury >= cost_res[1] && me->resourses.ore >= cost_res[2] && me->resourses.sulfur >= cost_res[3] && me->resourses.crystal >= cost_res[4] && me->resourses.jems >= cost_res[5] && me->resourses.gold >= cost_res[6]) { me->resourses.wood -= cost_res[0]; me->resourses.mercury -= cost_res[1]; me->resourses.ore -= cost_res[2]; me->resourses.sulfur -= cost_res[3]; me->resourses.crystal -= cost_res[4]; me->resourses.jems -= cost_res[5]; me->resourses.gold -= cost_res[6]; town->guards.type[i] = GetCreatureGrade(town->guards.type[i]); return true; } } } return false; } // автоулучшение существ в городе по ЛКМ+A _int_ __stdcall Y_AutoGradeMonInTown(LoHook* h, HookContext* c) { if (/* !o_IsOnlineGame && */ GetKeyState(65)<0 ) { _bool_ done = 0; _Town_* town = o_TownMgr->town; int klick_id = c->edi; if(klick_id == 125 && town->down_hero_id != -1) done = Y_AutoGradeMonInTownFunc(town, 2); if(klick_id == 123 && town->up_hero_id != -1) done = Y_AutoGradeMonInTownFunc(town, 1); if(klick_id == 123 && town->up_hero_id == -1) done = Y_AutoGradeMonInTownFunc(town, 0); if( klick_id >= 140 && klick_id <= 146 && town->down_hero_id != -1 ) done = Y_AutoGradeMonInTownOne_H(town, 2, klick_id - 140); if( klick_id >= 115 && klick_id <= 121 && town->up_hero_id != -1 ) done = Y_AutoGradeMonInTownOne_H(town, 1, klick_id - 115); if( klick_id >= 115 && klick_id <= 121 && town->up_hero_id == -1 ) done = Y_AutoGradeMonInTownOne_T(town, 1, klick_id - 115); // обновить экран города if (done) { CALL_1(void, __thiscall, 0x5D5930, *(int*)0x69954C); // отключить жёлтую обводку CALL_1(void, __thiscall, 0x5D5810, o_TownMgr); // обновить экран города c->return_address = 0x5D460F; return NO_EXEC_DEFAULT; } } return 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; // Создаём объекты patcher_x86. _P = GetPatcher(); _PI = _P->CreateInstance("HD_Plugin.AutoGradeMonInTown"); _PI->WriteLoHook(0x5D45FD, Y_AutoGradeMonInTown); } break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } -------------------- |
|
|
|
22 Aug 2017, 06:37
(Сообщение отредактировал Ben - 02 Oct 2017, 22:17)
Сообщение
#31
|
|
|
Power Member Сообщений: 198 Спасибо сказали: 134 раза |
|
|
|
|
22 Aug 2017, 16:33
Сообщение
#32
|
|
![]() Immortal Сообщений: 6 287 Спасибо сказали: 12723 раза |
Напоминаю:
Все обсуждения - в соседней теме.
.. Просьба здесь особо не обсуждать. Мне куда более доставляет складывать добро в чистую тему. -------------------- |
|
|
|
02 Sep 2017, 17:46
(Сообщение отредактировал Ben - 02 Oct 2017, 22:21)
Сообщение
#33
|
|
|
Power Member Сообщений: 198 Спасибо сказали: 134 раза |
Модификация Зыбучих песков и Мин
Dll плагин к HD моду. Теперь количество этих объектов не 4/6/8, а 6/8/10. С помощью SPTRAITS.txt это недостижимо. Код #include "..\..\include\homm3.h" Patcher* _P; PatcherInstance* _PI; int __stdcall quicksandSpell(LoHook* h, HookContext* c) { int peski[] = {6, 6, 8, 10}; c->edi = peski[c->esi]; return EXEC_DEFAULT; } int __stdcall minesSpell(LoHook* h, HookContext* c) { int miny[] = {6, 6, 8, 10}; c->edx = miny[c->esi]; return 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.QuicksandMines"); _PI->WriteLoHook(0x5A066B, quicksandSpell); _PI->WriteLoHook(0x5A0852, minesSpell); } break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } Сама Dll: https://yadi.sk/d/5iwgKir_3NQmdY |
|
|
|
27 Sep 2017, 18:41
(Сообщение отредактировал Ben - 02 Oct 2017, 22:24)
Сообщение
#34
|
|
|
Power Member Сообщений: 198 Спасибо сказали: 134 раза |
Улучшение вторичного навыка Обучение
Dll плагин к HD моду. https://yadi.sk/d/MpGGkmG33NGbsE UPD внес небольшое исправление по совету AlexSpl - поменял тип int на _word_ в строке с объявлением heroLevel. https://yadi.sk/d/Tek6oZpq3NQmxA Теперь герой с данным навыком с увеличением количества опыта увеличивает свой уровневый отрыв от героя без данного навыка. Сравнительное движение героев по уровням: Герой с навыком: 1->3->8->16->21->25->37->40->46 Герой без навыка: 1->3->7->11->14->17->27->30->34 Суть нововведения в том, что количество дополнительного опыта рассчитывается исходя из текущего уровня героя (это количество линейно зависит от текущего уровня, степень же навыка является дополнительным множителем). Код #include "..\..\include\homm3.h"
Patcher* _P; PatcherInstance* _PI; static _bool_ plugin_On = 0; int __stdcall changeLearningPower(LoHook* h, HookContext* c) { char learningSkill = *(char*)(c->ecx + 0xDE); _word_ heroLevel = *(_word_*)(c->ecx + 0x55); float multiplier = learningSkill * heroLevel / (float)15.0; *(float*)(c->ebp - 4) = (float)multiplier; return EXEC_DEFAULT; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if ( DLL_PROCESS_ATTACH == ul_reason_for_call ) { if ( !plugin_On ) { plugin_On = 1; _P = GetPatcher(); _PI = _P->CreateInstance("HD.Plugin.LearningSkill"); _PI->WriteLoHook(0x4E4ACD, changeLearningPower); } } return TRUE; } |
|
|
|
30 Sep 2017, 09:02
(Сообщение отредактировал Iv - 06 May 2021, 16:32)
Причина редактирования: спрятал под спойлер
Сообщение
#35
|
|
|
Power Member Сообщений: 198 Спасибо сказали: 134 раза |
Улучшение навыка Орлиный глаз
Авторы: AlexSpl, Ben Dll плагин к HD моду. https://yadi.sk/d/8xAXgEpk3NLf8f UPD Обновленная ссылка с версией в релизной конфигурации (предыдущая могла не работать на каких-то системах) https://yadi.sk/d/RVqiFWfr3NQNWi Теперь навык действует не после битвы, а до, в книгу заклинаний копируются заклинания противника, с определенной вероятностью по схеме 30/35/40% для каждого заклинания в зависимости от степени навыка (герою доступны заклинания 1-2/1-3/1-4 уровней в зависимости от степени навыка, как в оригинальной игре). Влияние артефактов и специальности учитывается. В сетевой игре работает. ![]() Код #define _CRT_RAND_S #define _CRT_SECURE_NO_WARNINGS #include "..\..\include\homm3.h" Patcher* _P; PatcherInstance* _PI; static _bool_ plugin_On = 0; struct PicStruc { int type; // тип картинки (9 - заклинание) int id; // ID картинки }; // кастомный _List_ struct List { _ptr_ Creation; PicStruc* Data; PicStruc* EndData; _ptr_ EndMem; }; int captionAddr; bool dlgFirst[] = {true, true}; // Заголовок в каждом диалоге int __stdcall saveCaption(LoHook* h, HookContext* c) { captionAddr = c->ecx; return EXEC_DEFAULT; } int __stdcall captionFix(LoHook* h, HookContext* c) { *(int*)(c->ebp - 0x14) = captionAddr; return EXEC_DEFAULT; } int showSpellDlg(_Hero_* hero, int spells[], int nPics) { if ( !nPics ) return 0; List picList; // Динамический массив картинок // Первый и последний элемент резервируем для полей Creation и EndData/EndMem соответственно PicStruc* pic = new PicStruc[nPics + 2]; for (int i = 0; i < nPics; ++i) { pic[i + 1].type = 9; pic[i + 1].id = spells[i]; } picList.Creation = (_ptr_)pic + 4; picList.Data = pic + 1; // Адрес первого элемента в списке picList.EndData = picList.Data + nPics; // Адрес следующего за последним элементом в списке байта picList.EndMem = (_ptr_)picList.EndData; sprintf(o_TextBuffer, "Благодаря навыку {Орлиный глаз}, {%s} выучил%s следующ%s заклинан%s:", hero->name, hero->sex ? "а" : "", nPics > 1 ? "ие" : "ее", nPics > 1 ? "ия" : "ие"); CALL_5(unsigned int, __fastcall, 0x4F7D20, o_TextBuffer, &picList, -1, -1, 0); delete [] pic; return 0; } int getEagleEyeSpells(_Hero_* hero, _Hero_* heroDonor, int spells[]) { int n = 0; unsigned int eagleEyeProb = (unsigned int)(CALL_1(float, __thiscall, 0x4E4690, hero) * 100.0); for (_Spell_* iSpell = o_Spell + SPL_QUICKSAND; iSpell <= o_Spell + SPL_AIR_ELEMENTAL; ++iSpell) { int i = iSpell - o_Spell; if ( heroDonor->spell_level[i] && !hero->spell[i] ) { if ( iSpell->level <= hero->second_skill[HSS_EAGLE_EYE] + 1 ) { unsigned int dice; rand_s(&dice); dice = (unsigned int)((double)dice / ((double)UINT_MAX + 1) * 100.0) + 1; if ( dice <= eagleEyeProb ) { spells[n++] = i; hero->spell[i] = 1; hero->spell_level[i] = 1; } } } } return n; } int __stdcall eagleEyeMain(LoHook* h, HookContext* c) { _Hero_* hero[] = {o_BattleMgr->hero[ATTACKER], o_BattleMgr->hero[DEFENDER]}; if ( hero[ATTACKER] && hero[DEFENDER] ) { int spells[70]; for (int i = ATTACKER; i <= DEFENDER; ++i) { if ( dlgFirst[i] && o_BattleMgr->current_side == i && hero[i]->second_skill[HSS_EAGLE_EYE] && hero[i]->doll_art[AS_SPELL_BOOK].id == AID_SPELL_BOOK ) { dlgFirst[i] = false; // Учим заклинания всегда. int n = getEagleEyeSpells(hero[i], hero[1 - i], spells); // Но диалог показываем только для игрока-человека: // в хотсите - диалог для обоих героев, в сетевой игре - только для своего героя. if ( o_GameMgr->GetPlayer(hero[i]->owner_id)->IsHuman() ) { int id = o_GameMgr->GetMeID(); if ( !o_NetworkGame || hero[i]->owner_id == id ) { o_ActivePlayerID = hero[i]->owner_id; showSpellDlg(hero[i], spells, n); o_ActivePlayerID = id; } } } } } return EXEC_DEFAULT; } int __stdcall eagleEyeSetGlobalFlags(LoHook* h, HookContext* c) { dlgFirst[ATTACKER] = true; dlgFirst[DEFENDER] = true; return EXEC_DEFAULT; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if ( DLL_PROCESS_ATTACH == ul_reason_for_call ) { if ( !plugin_On ) { plugin_On = 1; _P = GetPatcher(); _PI = _P->CreateInstance("HD.Plugin.NewEagleEye"); // Меняем коэффициенты float eagleEyeCoefs[] = {0.00f, 0.30f, 0.35f, 0.40f}; _PI->WriteDword(0x63EA2C, (int&)eagleEyeCoefs[1]); _PI->WriteDword(0x63EA30, (int&)eagleEyeCoefs[2]); _PI->WriteDword(0x63EA34, (int&)eagleEyeCoefs[3]); // Убираем оригинальный эффект _PI->WriteHexPatch(0x469C23, "EB"); _PI->WriteHexPatch(0x476996, "E9 DD 01 00 00"); // Фиксим заголовок диалога _PI->WriteLoHook(0x4F7D49, saveCaption); _PI->WriteLoHook(0x4F7D54, captionFix); _PI->WriteLoHook(0x462C7D, eagleEyeSetGlobalFlags); _PI->WriteLoHook(0x477C00, eagleEyeMain); } } return TRUE; } Спасибо сказали: |
|
|
|
20 Sep 2018, 22:02
(Сообщение отредактировал igrik - 18 Sep 2020, 17:42)
Сообщение
#36
|
|
![]() Immortal Сообщений: 589 Спасибо сказали: 891 раз |
WoG Native Dialogs
(Вог диалоги в родном исполнении) Основная цель: поддержка мастшабирования высоких разрешений при игре с HD-модом Сделано: ( ) ( ) ( ) ( ) ( ) ( ) ( ) ( )Автор: igrik Язык: Rus/Eng Формат: самораспаковывающийся архив Поддерживаемые версии: ERA Способ установки: указать корневую папку ERA Скачать -------------------- |
|
|
|
16 Nov 2018, 08:42
Сообщение
#37
|
|
![]() Immortal Сообщений: 589 Спасибо сказали: 891 раз |
Защита артефактов, пандор и свитков
Скачать (41.5kb) Совместимость: SoD, ERA Автор: igrik Описание: теперь артефакты, ящики пандор и свитки защищены рядом стоящими монстрами (монстр защищает объекты согласно красной рамки): ![]() -------------------- |
|
|
|
11 Feb 2019, 15:15
(Сообщение отредактировал Richter - 11 Feb 2019, 15:49)
Сообщение
#38
|
|
![]() collector of time Сообщений: 159 Спасибо сказали: 73 раза |
Небольшая модификация добавляющая статистику пройденного расстояния героя, просмотр по нажатию клавиши "X"
Автор:Richter 1 клетка карты равна 0,85714 км. Содержимое архива положить в папку "Мods" X_button_mod (950 байт) -------------------- |
|
|
|
26 Apr 2020, 15:21
(Сообщение отредактировал suftfree - 27 Apr 2020, 11:34)
Сообщение
#39
|
|
![]() Newbie Сообщений: 4 Спасибо сказали: 3 раза |
Модификация добавляющая огромное количество новых меню, подменю, интерфейс, обои, экраны загрузки
Автор: Suftfree, Berserker Язык: ENG Формат: папка с модом. Установка: кинуть в папку Mod, включить мод в менеджере модификаций ERA. Здравствуйте я завершил улучшение модификации Berserkera. Добавлена поддержка случайных меню, изменены фоны, экраны загрузки, экран сетевого меню. Версия BETA 0.1 - Preview eng new interface - потом добавлю стандартный интерфейс ENG и RUS При начале игры выбирается 1 случайное меню, 2 случайных подменю и случайный экран загрузки. Скачать: https://yadi.sk/d/HpgEpfirNktdOw
|
|
|
|
![]() ![]() |
| Текстовая версия | Сейчас: 15 April 2026 - 03:44 |
|
Copyright by Алексей Крючков
Programming by Degtyarev Dmitry |
|