Пример базы данных по броне юнитов

Добавлен , опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
cJass
Тип:
Наработка
Пример базы данных, позволяющей узнавать броню любого юнита или героя с учётом внесённых в базу предметов и показателей ловкости. Также учитываются способности, повышающие броню и одноуровневые ауры.
Код
library ArmorDB initializer initialize {
    #include "cj_types_priv.j"

    private int unitRawCode[];
    private float unitArmor[];
    private int unitsCount = 0;

    private int itemRawCode[];
    private float itemArmor[];
    private int itemsCount = 0;

    private int abilityRawCode[];
    private float abilityArmor[1000][4];
    private int abilitiesCount = 0;

    private constant float armorPerAgility = 0.3;    //from constants
    private constant float armorPenAgility = -2.0;   //from constants

    public void addUnit(int rawCode, float armor) {
        unitRawCode[unitsCount] = rawCode;
        unitArmor[unitsCount] = armor;
        unitsCount++;
    }

    public void addItem(int rawCode, float armor) {
        itemRawCode[itemsCount] = rawCode;
        itemArmor[itemsCount] = armor;
        itemsCount++;
    }

    public void addAbility(int rawCode, float armorLevel1, float armorLevel2, float armorLevel3, float armorLevel4) {
        abilityRawCode[abilitiesCount] = rawCode;
        abilityArmor[abilitiesCount][1] = armorLevel1;
        abilityArmor[abilitiesCount][2] = armorLevel2;
        abilityArmor[abilitiesCount][3] = armorLevel3;
        abilityArmor[abilitiesCount][4] = armorLevel4;
        abilitiesCount++;
    }

    private void initialize() {
        // do not remove
        // item, unit or ability with id == 0 represents respective entity that was not found in DB
        addUnit(0, 0.0);
        addItem(0, 0.0);
        addAbility(0, 0.0, 0.0, 0.0, 0.0);
    }

    // математическое округление
    private int integral(float a) {
        if (a >= 0) {
            return R2I(a + 0.5);
        }
        return R2I(a - 0.5);
    }

    private int getUnitIndex(int rawCode) {
        for (int unitIndex = 0; unitIndex <= unitsCount; unitIndex++) {
            if (unitRawCode[unitIndex] == rawCode) {
                return unitIndex;
            }
        }
        return 0;
    }

    private int getItemIndex(int rawCode) {
        for (int itemIndex = 0; itemIndex <= itemsCount; itemIndex++) {
            if (itemRawCode[itemIndex] == rawCode) {
                return itemIndex;
            }
        }
        return 0;
    }

    public float getUnitBasicArmor(unit u) {
        return unitArmor[getUnitIndex(GetUnitTypeId(u))];
    }

    public float getItemArmor(item i) {
        return itemArmor[getItemIndex(GetItemTypeId(i))];
    }

    public float getArmorFromAbilities(unit u) {
        float armor = 0.0;
        for (int abilityIndex = 1; abilityIndex <= abilitiesCount; abilityIndex++) {
            int abilityLevel = GetUnitAbilityLevel(u, abilityRawCode[abilityIndex]);
            if (abilityLevel > 0) {
                armor = armor + abilityArmor[abilityIndex][abilityLevel];
            }
        }
        return armor;
    }

    public float getUnitArmor(unit u) {
        if (IsHeroUnitId(GetUnitTypeId(u))) {
            float armorFromItems = 0;
            for (int itemSlotIndex = 0; itemSlotIndex < 6; itemSlotIndex++) {
                if (UnitItemInSlot(u, itemSlotIndex) != null) {
                    armorFromItems = armorFromItems + getItemArmor(UnitItemInSlot(u, itemSlotIndex));
                }
            }
            return armorFromItems + getArmorFromAbilities(u) \
                    + integral(getUnitBasicArmor(u) + armorPerAgility*GetHeroAgi(u, false) + armorPenAgility) \
                    + armorPerAgility*(GetHeroAgi(u, true) - GetHeroAgi(u, false));
        }
        return getUnitBasicArmor(u) + getArmorFromAbilities(u);
    }
}

Для получения корректного результата в базу помимо базовых параметров защиты войск должны быть введены все способности и предметы, влияющие непосредственно на защиту.
Ауры не выше 1 уровня, вписывать для них нужно rawcode баффа, а не самой способности.

Новые элементы базы добавляются следующим набором методов:
// Добавление значения базовой (указанной в редакторе объектов) брони юнита:
void ArmorDB.addUnit(int rawCode, float armor);

// Добавление показателя брони, получаемого от предмета:
void ArmorDB.addItem(int rawCode, float armor);

// Добавление брони от способностей:
void ArmorDB.addAbility(int rawCode, float armorLevel1, float armorLevel2, float armorLevel3, float armorLevel4);
Например:
library ExampleUsage uses ArmorDB initializer addDataToArmorDB {
    void addDataToArmorDB() {
        ArmorDB.addUnit('Hpal', 2);
        ArmorDB.addUnit('Hmkg', 1);

        ArmorDB.addItem('rde1', 2);
        ArmorDB.addItem('rde2', 3);
        ArmorDB.addItem('rde3', 4);

        ArmorDB.addAbility('AHad', 1.5, 3.0, 4.5, 0.0);
    }
}
Показатель брони получаем функциями:
// Текущий показатель брони юнита:
float ArmorDB.getUnitArmor(unit u);

// Базовое значение брони юнита, указанное в РО:
float ArmorDB.getUnitBasicArmor(unit u);

// Значение брони, получаемое от предмета:
float ArmorDB.getItemArmor(item i);

// Количество брони, которую юнит получает от воздействующих на него способностей:
float ArmorDB.getArmorFromAbilities(unit u);

Не забудьте вписывать библиотеку ArmorDB в uses библиотеки со способностями или требующими этой БД системами, а также в библиотеки, в которых в базу добавляются новые значения.
`
ОЖИДАНИЕ РЕКЛАМЫ...
31
просто и понятно... +
много людей спрашивали о нечто подобном...
думаю, найдутся те, кому будет полезно...
30
Для справки: наносимый урон вычисляется по формуле:
Ожидаемый_урон * (0.06*GetUnitArmor(Target)/(1+(0.06*GetUnitArmor(Target))))
28
А не проще ли сделать через получение урона? тем более если в карте есть система получения урона, куда занесены все юниты.
zumm:
Не понял зачем это надо.
чтобы узнать количество брони юнита. У меня вот в карте есть спелы дамажущие от брони врага.
38
int integral(real a)
real GetUnitArmor(unit u) {
...
return integral(...
в типах запутались, уважаемый
кстати у векса там кривой десятичный логарифм =)
ЛОЛ define
{
exit exitwhen
30
Ну мне было влом пробегаться по коду и менять дефайн :)
Броня - реальное, в чем проблема?
38
возвращаешь инт, теряя точность
30
Очевидно, что математическое округление дает целое на выходе, ведь оно округляет -.-
Зато я могу использовать эту функцию и в функциях, возвращающих целые.
Базовая броня героев от основной ловкости всегда целое, а от дополнительной она уже меняется по десятым долям.
38
Я имею ввиду, что в той формуле не надо округлять, ведь требуется то real, а ты отдаешь int, непонятно зачем.
30
ScorpioT1000, ты про эту формулу?
return integral(GetUnitArmorEx(u) + ArmorPenAgility + GetHeroAgi(u,false)*ArmorPerAgility) + am + (GetHeroAgi(u,true)-GetHeroAgi(u,false))*ArmorPerAgility + byabil
Объясняю почему так. Когда герой не имеет бонусов к защите, его показатель брони просто-напросто округляется. Не знаю, как на самом деле, но "damage reduction" пишется именно от этого округленного значения, причем сам он тоже округляется до целых процентов, хотя это округление чисто косметическое.
От ловкости защита пляшет уже от десятых долей.
Единственное что, в реально получаемом уроне никакие округления не ставятся, это исключительно косметический момент. Но, если в карте это реально заметно (уменьшение 100%, урон проходит), то карта идиотична, ибо это овер99999 брони.

Моей целью было получить реально отображаемое значение брони в общем, всё работает =)
Этот комментарий удален
30
Не знаю зачем, но напоролся на этот ресурс и причесал код.
38
Может не будешь округлять, всё-таки?))
30
ScorpioT1000, так там же по факту так учёт идёт, я только повторил логику, заложенную в оригинальной игре. Припоминается, что я сколько-то там попыток делал, чтобы всё совпало с выводимым в игре значением.
Алсо теперь хорошо видно, что округляется только одно слагаемое, а не весь результат :D
Чтобы оставить комментарий, пожалуйста, войдите на сайт.