Пример базы данных, позволяющей узнавать броню любого юнита или героя с учётом внесённых в базу предметов и показателей ловкости. Также учитываются способности, повышающие броню и одноуровневые ауры.
Код
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 баффа, а не самой способности.
Ауры не выше 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 библиотеки со способностями или требующими этой БД системами, а также в библиотеки, в которых в базу добавляются новые значения.
Броня - реальное, в чем проблема?
Зато я могу использовать эту функцию и в функциях, возвращающих целые.
Базовая броня героев от основной ловкости всегда целое, а от дополнительной она уже меняется по десятым долям.
Ред. Clamp
return integral(GetUnitArmorEx(u) + ArmorPenAgility + GetHeroAgi(u,false)*ArmorPerAgility) + am + (GetHeroAgi(u,true)-GetHeroAgi(u,false))*ArmorPerAgility + byabil
Объясняю почему так. Когда герой не имеет бонусов к защите, его показатель брони просто-напросто округляется. Не знаю, как на самом деле, но "damage reduction" пишется именно от этого округленного значения, причем сам он тоже округляется до целых процентов, хотя это округление чисто косметическое.
От ловкости защита пляшет уже от десятых долей.
Единственное что, в реально получаемом уроне никакие округления не ставятся, это исключительно косметический момент. Но, если в карте это реально заметно (уменьшение 100%, урон проходит), то карта идиотична, ибо это овер99999 брони.
Ред. Clamp
Алсо теперь хорошо видно, что округляется только одно слагаемое, а не весь результат :D