Запуск сервера: https://tangar.info/allods2/zapusk-servera-heta-v-allody-2
Как работать с Гидрой:
- качаем Гидру https://github.com/NationalSecurityAgency/ghidra/releases
- качаем Java https://www.java.com/ru/download/
- качаем JDK (сверху в меню выбираем Windows) https://www.oracle.com/java/technologies/downloads/
- качаем файл https://github.com/Marisa-Chan/A2Serv_ghidra
- создаем новый проект
- перетаскиваем файл в Гидру
- ???
- Profit!
Примечание от Zidane:
Главные классы CWinApp и CMainWindow можно в списке классов в гидре найти. А оттуда перейти уже на идентифицированные методы типа Run, WindowProc, OnIdle и т.д. Окно Symbol Tree в помощь по размеченным классам и неймспейсам.
1) Статьи с сайта ex-lend:
- базовая инфа: встройка .dll и деньги игрока
- фикс спидхака
- работа с графикой А2
- время прохождения тайлов
- id тайлов
- отрисовка обзора
- формат .alm
- значения ID предметов
- описание предметов
- анлок логина
- фикс воровства предметов из магазина
- список предметов с ID
- перенос охапкой
2) Статьи от ZZYZX:
3) Статьи с сайта -Vampire-:
- Триггеры — самое подробное руководство о том, как пользоваться скриптами редактора карт
- Делаем свой мод — руководство по построению собственных модов для Аллодов 2 (по опыту проекта Аллоды 2,5)
- Квесты и магазины — как правильно настраивать квесты и магазины, чтобы избежать глюков
Ссылки:
https://github.com/igroglaz/a2mgr — клиент
https://github.com/igroglaz/srvmgr — сервер
https://github.com/igroglaz/redhat — хэт
https://github.com/igroglaz/a2mgr_rom2me — редактор
https://github.com/Marisa-Chan/A2Serv_ghidra — разбор исходников А2 в Ghidra
https://github.com/jewalky/UnityAllods — Аллоды 2 на Unity — порт с фокусом на сетевой игре
https://github.com/madwareru/orom-first-encounter — Open Rage Of Mage — порт с фокусом на кооп сингл кампании
https://github.com/igroglaz/rom2utils — утилиты для Аллодов 2
https://github.com/igroglaz/rom2maps — коллекция карт
https://github.com/serg-bloim/a2env/releases/tag/a2win7_v1 — общая среда разработки (хэт+сервер+исходники+IDE)
https://github.com/WarBeginner/a2-tools — инструмент работы с ресурсами А2
http://tangar.info/allods2/zapusk-servera-heta-v-allody-2 — гайд, как запустить хэт
FAQ:
Награды в таверне vs значения дропа вещей, на примере поножей
Поножи метеор в награду за квест в таверне 200к
Поножи в дропе монстра treasureItem 400к
Продаются в магаз за 400к
т.е. если вы поставите treasureItem 200к — поножи не упадут из моба; но при макс значении награды в таверне 200к — их дадут.
Как сделать, чтобы магазин быстро обновлял свитки?
Как распаковать ресурсы утилкой res.exe?
Создаем папку C:\a2 , кладем туда res.exe и, например, SCENARIO.RES . Создаем там папку world. Запускаем команду
res x c:\a2\SCENARIO SCENARIO C:\a2\world
Как открыть сетевые карты из Аллодов 1?
Переименовать .all -> .alm и открыть в редакторе 🙂
Как портировать карты кампании Аллодов 1-2 в мультиплеер?
Как в редакторе положить в моба определенные вещи? (отвечает zhuxor)
TreasureItemMask работает точно так же как и настройки полок магазинов, там функция одна и та же на выборку предметов. При дропе сначала подбирается 100 предметов по маске, потом из них один рандомный.
С помощью редактора полок удобно смотреть в игре, какие предметы будут дропаться с мобов при определенных подборках флагов (галочек) и цен.
Вот на скрине настройка полок =:
<treasureItem>40</treasureItem> - это шанс дропа :)
<treasureItemMin>308700</treasureItemMin> - мин стоимость
<treasureItemMax>1353434</treasureItemMax> - макс.стоимость
<treasureItemMask>566755327</treasureItemMask> - маска (ниже в таблице расшифровка)
Это огр 5. Заходим в лавку — там 100 шмоток на полке которые могут упасть. В редакторе можно и 1000 предметов на полке выставить (больше, вроде, нельзя), но для дропа подбирается именно 100 предметов.
Таблица значений TreasureItemMask (спасибо ex-lend за разбор, Kobik за верификацию и разбор, ZZYZX за наводку):
материалы: 0x00000001: железо 0x00000002: бронза 0x00000004: сталь 0x00000008: серебро 0x00000010: золото 0x00000020: мифрил 0x00000040: адамант 0x00000080: метеорит 0x00000100: дерево 0x00000200: вол. дерево 0x00000400: кожа 0x00000800: толcт.кожа 0x00001000: драк.кожа 0x00002000: кристалл 0x00004000: none (никакие) |
типы предметов: 0x00400000: оружие 0x00800000: щиты 0x01000000: броня 0x02000000: одежда (для магов) 0x04000000: остальное (other) 0x08000000: посохи |
allowed extra: 0x10000000: common 0x20000000: magic виды предметов: 0x00008000: common 0x00010000: uncommon 0x00020000: rare 0x00040000: very rare 0x00080000: elven 0x00100000: bad 0x00200000: good
|
Как пользоваться калькулятором Windows 10 для выставления нужных вещей (спасибо Кобику):
Примеры масок:
557 842 431 — вся броня и одежда (не включает оружие, посохи, щиты и банки-свитки-книги).
Далее, есть парсер treasureItemMask от zhuxor:
#include #include #include #include enum ItemAssortmentFlags : uint32_t { Material_Iron = 0x1, Material_Bronze = 0x2, Material_Steel = 0x4, Material_Silver = 0x8, Material_Gold = 0x10, Material_Mithrill = 0x20, Material_Adamantium = 0x40, Material_Meteoric = 0x80, Material_Wood = 0x100, Material_MagicWood = 0x200, Material_Leather = 0x400, Material_HardLeather = 0x800, Material_DragonLeather = 0x1000, Material_Crystal = 0x2000, Material_None = 0x4000, // all Material_AllOf = 0x7FFF, Material_NeitherOf = ~Material_AllOf, Shape_Common = 0x8000, Shape_Uncommon = 0x10000, Shape_Rare = 0x20000, Shape_VeryRare = 0x40000, Shape_Elven = 0x80000, Shape_Bad = 0x100000, Shape_Good = 0x200000, // all Shape_AllOf = Shape_Common | Shape_Uncommon | Shape_Rare | Shape_VeryRare | Shape_Elven | Shape_Bad | Shape_Good, Shape_NeitherOf = ~Shape_AllOf, Type_Weapons = 0x400000, Type_Shields = 0x800000, Type_Armors = 0x1000000, Type_Clothes = 0x2000000, Type_Other = 0x4000000, Type_Staffs = 0x8000000, // all Type_AllOf = Type_Weapons | Type_Shields | Type_Armors | Type_Clothes | Type_Other | Type_Staffs, Type_NeitherOf = ~Type_AllOf, Extra_Common = 0x10000000, Extra_Magic = 0x20000000, // all Extra_AllOf = Extra_Common | Extra_Magic, Extra_NeitherOf = ~Extra_AllOf, Unknown_0x40000000 = 0x40000000, Unknown_0x80000000 = 0x80000000, }; void print_assortment_mask(uint32_t mask) { std::vector materials; if ((mask & Material_AllOf) == Material_AllOf) { materials.push_back("- all of -"); } else if (!(mask & Material_AllOf)) { materials.push_back("- neither of -"); } else { if (mask & Material_Iron) materials.push_back("Iron"); if (mask & Material_Bronze) materials.push_back("Bronze"); if (mask & Material_Steel) materials.push_back("Steel"); if (mask & Material_Silver) materials.push_back("Silver"); if (mask & Material_Gold) materials.push_back("Gold"); if (mask & Material_Mithrill) materials.push_back("Mithrill"); if (mask & Material_Adamantium) materials.push_back("Adamantium"); if (mask & Material_Meteoric) materials.push_back("Meteoric"); if (mask & Material_Wood) materials.push_back("Wood"); if (mask & Material_MagicWood) materials.push_back("MagicWood"); if (mask & Material_Leather) materials.push_back("Leather"); if (mask & Material_HardLeather) materials.push_back("HardLeather"); if (mask & Material_DragonLeather) materials.push_back("DragonLeather"); if (mask & Material_Crystal) materials.push_back("Crystal"); if (mask & Material_None) materials.push_back("None"); } std::vector shapes; if ((mask & Shape_AllOf) == Shape_AllOf) { materials.push_back("All"); } else if (!(mask & Shape_AllOf)) { materials.push_back("- neither of -"); } else { if (mask & Shape_Common) shapes.push_back("Common"); if (mask & Shape_Uncommon) shapes.push_back("Uncommon"); if (mask & Shape_Rare) shapes.push_back("Rare"); if (mask & Shape_VeryRare) shapes.push_back("VeryRare"); if (mask & Shape_Elven) shapes.push_back("Elven"); if (mask & Shape_Bad) shapes.push_back("Bad"); if (mask & Shape_Good) shapes.push_back("Good"); } std::vector types; if ((mask & Type_AllOf) == Type_AllOf) { types.push_back("- all of -"); } else if (!(mask & Type_AllOf)) { types.push_back("- neither of -"); } else { if (mask & Type_Weapons) types.push_back("Weapons"); if (mask & Type_Shields) types.push_back("Shields"); if (mask & Type_Armors) types.push_back("Armors"); if (mask & Type_Clothes) types.push_back("Clothes"); if (mask & Type_Other) types.push_back("Other"); if (mask & Type_Staffs) types.push_back("Staffs"); } std::vector extras; if (!(mask & Extra_AllOf)) { extras.push_back("- neither of -"); } else { if (mask & Extra_Magic) extras.push_back("Magic"); if (mask & Extra_Common) extras.push_back("Common"); } std::cout << "print_assortment_mask(" << std::hex << mask << "):\n"; std::cout << " Materials:\n"; for (std::string material : materials) std::cout << " " << material << '\n'; std::cout << " Shapes:\n"; for (std::string shape : shapes) std::cout << " " << shape << '\n'; std::cout << " Types:\n"; for (std::string type : types) std::cout << " " << type << '\n'; std::cout << " Extra:\n"; for (std::string extra : extras) std::cout << " " << extra << '\n'; } int main() { // 566755327 from data.xml print_assortment_mask(566755327); // ogre_treasure_mask == 566755327 uint32_t ogre_treasure_mask = Material_AllOf | Shape_Common | Shape_Uncommon | Shape_Rare | Shape_VeryRare | Type_Weapons | Type_Shields | Type_Armors | Extra_Magic; return 0; }
меняем значения print_assortment_mask(566755327);
и наслаждаемся 🙂
Пишите комменты!
How to auto-attack flying monsters with blizzard or fireball (by ex-lend)
Когда-то я нашел это место, но не стал распространять на сервер, т.к. данное исправление имеет смысл только в сингле, Вы догадываетесь почему.
allods2.exe 0017498B: 7E 90 0017498C: 2E 90 00174B84: 7E 90 00174B85: 2E 90 00174D14: 7E 90 00174D15: 2E 90 00174EA4: 7E 90 00174EA5: 2B 90
Убрано несколько условных переходов, если внимательно посмотреть в дизассемблере, можно выяснить какой за что отвечает. Хотя не представляю, зачем это… 😉
ex-lend: размер мешка определяется количеством знаков в суммарной стоимости содержимого:
Поправить это можно в a2server.exe:0051AF26
Примечание по хакам от Кобика:
quest_kill_N_mobs.xck
Patch for increase maxN in quest «kill N mobs»
Description: https://discord.com/channels/615442786161786893/623619228896854016/804250926314422302
В сервере см. функцию sub_562148. Выбор mахN на участке от 562996 до 562А03.
Исходно логика такая:
Если на карте 1 моб, то квест дают на 1-4шт
Если на карте 2-3 моба, то квест на 2-бшт
Если на карте 4-7 мобов, то квест на 2-7шт
Если на карте 8+ мобов, то квест на 2-10шт
Патч задевает только последнюю ветку:
Если на карте 8+ мобов, то кв на 5-25 шт
Для любителей убить много белок.