Разработка

Запуск сервера: https://tangar.info/allods2/zapusk-servera-heta-v-allody-2

Как работать с Гидрой:

  1. качаем Гидру https://github.com/NationalSecurityAgency/ghidra/releases
  2. качаем Java https://www.java.com/ru/download/
  3. качаем JDK (сверху в меню выбираем Windows)  https://www.oracle.com/java/technologies/downloads/
  4. качаем файл https://github.com/Marisa-Chan/A2Serv_ghidra
  5. создаем новый проект
  6. перетаскиваем файл в Гидру
  7. ???
  8. Profit!

Примечание от Zidane:
Главные классы CWinApp и CMainWindow можно в списке классов в гидре найти. А оттуда перейти уже на идентифицированные методы типа Run, WindowProc, OnIdle и т.д. Окно Symbol Tree в помощь по размеченным классам и неймспейсам.


1) Статьи с сайта ex-lend:

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 шт
Для любителей убить много белок.

Добавить комментарий

🇬🇧 Attention! Comments with URLs/email are not allowed.
🇷🇺 Комментарии со ссылками/email удаляются автоматически.