1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-09-16 09:26:28 +02:00

Merge pull request #5725 from IvanSavenko/bonus_description

Custom descriptions and icons for creature abilities
This commit is contained in:
Ivan Savenko
2025-05-23 14:02:34 +03:00
committed by GitHub
20 changed files with 618 additions and 428 deletions

View File

@@ -649,6 +649,8 @@
"core.bonus.DEFENSIVE_STANCE.description" : "+${val} Defense when defending",
"core.bonus.DESTRUCTION.name" : "Destruction",
"core.bonus.DESTRUCTION.description" : "Has ${val}% chance to kill extra units after attack",
"core.bonus.DISINTEGRATE.name" : "Disintegrate",
"core.bonus.DISINTEGRATE.description" : "No corpse remains after death",
"core.bonus.DOUBLE_DAMAGE_CHANCE.name" : "Death Blow",
"core.bonus.DOUBLE_DAMAGE_CHANCE.description" : "Has a ${val}% chance of dealing double base damage when attacking",
"core.bonus.DRAGON_NATURE.name" : "Dragon",
@@ -689,6 +691,8 @@
"core.bonus.HEALER.description" : "Heals allied units",
"core.bonus.HP_REGENERATION.name" : "Regeneration",
"core.bonus.HP_REGENERATION.description" : "Heals ${val} hit points every round",
"core.bonus.INVINCIBLE.name" : "Invincible",
"core.bonus.INVINCIBLE.description" : "Cannot be affected by anything",
"core.bonus.JOUSTING.name" : "Champion charge",
"core.bonus.JOUSTING.description" : "+${val}% damage for each hex travelled",
"core.bonus.KING.name" : "King",
@@ -707,6 +711,8 @@
"core.bonus.MAGIC_MIRROR.description" : "Has a ${val}% chance to redirect an offensive spell to an enemy unit",
"core.bonus.MAGIC_RESISTANCE.name" : "Magic Resistance (${val}%)",
"core.bonus.MAGIC_RESISTANCE.description" : "Has a ${val}% chance to resist an enemy spell",
"core.bonus.MECHANICAL.name" : "Mechanical",
"core.bonus.MECHANICAL.description" : "Immunity to many effects, repairable",
"core.bonus.MIND_IMMUNITY.name" : "Mind Spell Immunity",
"core.bonus.MIND_IMMUNITY.description" : "Immune to Mind-type spells",
"core.bonus.NO_DISTANCE_PENALTY.name" : "No distance penalty",
@@ -719,6 +725,10 @@
"core.bonus.NO_WALL_PENALTY.description" : "Full damage during siege",
"core.bonus.NON_LIVING.name" : "Non living",
"core.bonus.NON_LIVING.description" : "Immunity to many effects",
"core.bonus.OPENING_BATTLE_SPELL.name" : "Starts with spell",
"core.bonus.OPENING_BATTLE_SPELL.description" : "Casts ${subtype.spell} on battle start",
"core.bonus.PRISM_HEX_ATTACK_BREATH.name" : "Prism Breath",
"core.bonus.PRISM_HEX_ATTACK_BREATH.description" : "Prism Breath Attack (three directions)",
"core.bonus.RANDOM_SPELLCASTER.name" : "Random spellcaster",
"core.bonus.RANDOM_SPELLCASTER.description" : "Can cast random spell",
"core.bonus.RANGED_RETALIATION.name" : "Ranged retaliation",
@@ -743,10 +753,30 @@
"core.bonus.SPELL_AFTER_ATTACK.description" : "Has a ${val}% chance to cast ${subtype.spell} after it attacks",
"core.bonus.SPELL_BEFORE_ATTACK.name" : "Cast Before Attack",
"core.bonus.SPELL_BEFORE_ATTACK.description" : "Has a ${val}% chance to cast ${subtype.spell} before it attacks",
"core.bonus.SPELL_DAMAGE_REDUCTION.name" : "Spell Resistance",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.air" : "Air Spells Resistance",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.fire" : "Fire Spells Resistance",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.water" : "Water Spells Resistance",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.earth" : "Earth Spells Resistance",
"core.bonus.SPELL_DAMAGE_REDUCTION.description" : "Damage from all spells reduced by ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.air" : "Damage from all Air spells reduced by ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.fire" : "Damage from all Fire spells reduced by ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.water" : "Damage from all Water spells reduced by ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.earth" : "Damage from all Earth spells reduced by ${val}%.",
"core.bonus.SPELL_IMMUNITY.name" : "Spell immunity",
"core.bonus.SPELL_IMMUNITY.description" : "Immune to ${subtype.spell}",
"core.bonus.SPELL_LIKE_ATTACK.name" : "Spell-like attack",
"core.bonus.SPELL_LIKE_ATTACK.description" : "Attacks with ${subtype.spell}",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name" : "Spell immunity",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.air" : "Air immunity",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.fire" : "Fire immunity",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.water" : "Water immunity",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.earth" : "Earth immunity",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description" : "This unit is immune to all spells",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.air" : "This unit is immune to all Air school spells",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.fire" : "This unit is immune to all Fire school spells",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.water" : "This unit is immune to all Water school spells",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.earth" : "This unit is immune to all Earth school spells",
"core.bonus.SPELL_RESISTANCE_AURA.name" : "Aura of Resistance",
"core.bonus.SPELL_RESISTANCE_AURA.description" : "Nearby stacks get ${val}% magic resistance",
"core.bonus.SUMMON_GUARDIANS.name" : "Summon guardians",
@@ -767,36 +797,6 @@
"core.bonus.WATER_IMMUNITY.description" : "Immune to all spells from the school of Water magic",
"core.bonus.WIDE_BREATH.name" : "Wide breath",
"core.bonus.WIDE_BREATH.description" : "Wide breath attack (multiple hexes)",
"core.bonus.DISINTEGRATE.name" : "Disintegrate",
"core.bonus.DISINTEGRATE.description" : "No corpse remains after death",
"core.bonus.INVINCIBLE.name" : "Invincible",
"core.bonus.INVINCIBLE.description" : "Cannot be affected by anything",
"core.bonus.MECHANICAL.name" : "Mechanical",
"core.bonus.MECHANICAL.description" : "Immunity to many effects, repairable",
"core.bonus.PRISM_HEX_ATTACK_BREATH.name" : "Prism Breath",
"core.bonus.PRISM_HEX_ATTACK_BREATH.description" : "Prism Breath Attack (three directions)",
"core.bonus.SPELL_DAMAGE_REDUCTION.name" : "Spell Resistance",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.air" : "Air Spells Resistance",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.fire" : "Fire Spells Resistance",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.water" : "Water Spells Resistance",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.earth" : "Earth Spells Resistance",
"core.bonus.SPELL_DAMAGE_REDUCTION.description" : "Damage from all spells reduced by ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.air" : "Damage from all Air spells reduced by ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.fire" : "Damage from all Fire spells reduced by ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.water" : "Damage from all Water spells reduced by ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.earth" : "Damage from all Earth spells reduced by ${val}%.",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name" : "Spell immunity",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.air" : "Air immunity",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.fire" : "Fire immunity",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.water" : "Water immunity",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.earth" : "Earth immunity",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description" : "This unit is immune to all spells",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.air" : "This unit is immune to all Air school spells",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.fire" : "This unit is immune to all Fire school spells",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.water" : "This unit is immune to all Water school spells",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.earth" : "This unit is immune to all Earth school spells",
"core.bonus.OPENING_BATTLE_SPELL.name" : "Starts with spell",
"core.bonus.OPENING_BATTLE_SPELL.description" : "Casts ${subtype.spell} on battle start",
"spell.core.castleMoat.name" : "Moat",
"spell.core.castleMoatTrigger.name" : "Moat",

View File

@@ -647,6 +647,8 @@
"core.bonus.DEFENSIVE_STANCE.description" : "+${val} Захист при обороні",
"core.bonus.DESTRUCTION.name" : "Знищення",
"core.bonus.DESTRUCTION.description" : "Має ${val}% шанс вбити додаткових юнітів після атаки",
"core.bonus.DISINTEGRATE.description" : "Після смерті не залишається трупа",
"core.bonus.DISINTEGRATE.name" : "Розпад",
"core.bonus.DOUBLE_DAMAGE_CHANCE.name" : "Смертельний удар",
"core.bonus.DOUBLE_DAMAGE_CHANCE.description" : "${val}% шанс нанести подвійної шкоди",
"core.bonus.DRAGON_NATURE.name" : "Дракон",
@@ -657,6 +659,8 @@
"core.bonus.ENCHANTER.description" : "Може використовувати масове закляття ${subtype.spell} кожного ходу",
"core.bonus.ENCHANTED.name" : "Зачарований",
"core.bonus.ENCHANTED.description" : "Піддається впливу постійних закляття ${subtype.spell}",
"core.bonus.ENEMY_ATTACK_REDUCTION.name" : "Ігнорування атаки (${val}%)",
"core.bonus.ENEMY_ATTACK_REDUCTION.description" : "При атаці ігнорується ${val}% атаки нападника",
"core.bonus.ENEMY_DEFENCE_REDUCTION.name" : "Ігнорує ${val}% захисту",
"core.bonus.ENEMY_DEFENCE_REDUCTION.description" : "Ігнорує частину захисту для атаки",
"core.bonus.FIRE_IMMUNITY.name" : "Імунітет до вогню",
@@ -669,6 +673,8 @@
"core.bonus.FEAR.description" : "Спричиняє страх у загоні ворога",
"core.bonus.FEARLESS.name" : "Безстрашний",
"core.bonus.FEARLESS.description" : "Імунітет до страху",
"core.bonus.FEROCITY.name" : "Лютість",
"core.bonus.FEROCITY.description" : "Атакує ${val} більше разів, якщо вбиває когось",
"core.bonus.FLYING.name" : "Літає",
"core.bonus.FLYING.description" : "Може літати (ігнорує перешкоди)",
"core.bonus.FREE_SHOOTING.name" : "Стріляє впритул",
@@ -677,6 +683,8 @@
"core.bonus.GARGOYLE.description" : "Не може бути відроджена або зцілена",
"core.bonus.GENERAL_DAMAGE_REDUCTION.name" : "Зменшує шкоду (${val}%)",
"core.bonus.GENERAL_DAMAGE_REDUCTION.description" : "Зменшує фізичну шкоду від ударів з дальньої та ближньої дистанції",
"core.bonus.INVINCIBLE.description" : "На нього ніщо не може вплинути",
"core.bonus.INVINCIBLE.name" : "Невразливий",
"core.bonus.HATE.name" : "Ненавидить ${subtype.creature}",
"core.bonus.HATE.description" : "Завдає на ${val}% більше шкоди",
"core.bonus.HEALER.name" : "Цілитель",
@@ -691,6 +699,8 @@
"core.bonus.LEVEL_SPELL_IMMUNITY.description" : "Імунітет до заклять рівнів 1-${val}",
"core.bonus.LIFE_DRAIN.name" : "Висмоктує життя (${val}%)",
"core.bonus.LIFE_DRAIN.description" : "Висмоктує ${val}% від завданої шкоди",
"core.bonus.LIMITED_SHOOTING_RANGE.name" : "Обмежена дальність стрільби",
"core.bonus.LIMITED_SHOOTING_RANGE.description" : "Не може стріляти по цілях на відстані більше ${val} гексів",
"core.bonus.MANA_CHANNELING.name" : "Магічний канал ${val}%",
"core.bonus.MANA_CHANNELING.description" : "Повертає вашому герою ману, витрачену ворогом",
"core.bonus.MANA_DRAIN.name" : "Викрадання мани",
@@ -699,6 +709,8 @@
"core.bonus.MAGIC_MIRROR.description" : "Відбиває ворожі заклинання до випадкової істоти ворога з силою в ${val}%",
"core.bonus.MAGIC_RESISTANCE.name" : "Опір магії (${val}%)",
"core.bonus.MAGIC_RESISTANCE.description" : "${val}% шанс протистояти ворожим закляттям",
"core.bonus.MECHANICAL.description" : "Імунітет до багатьох ефектів, можна ремонтувати",
"core.bonus.MECHANICAL.name" : "Механічний",
"core.bonus.MIND_IMMUNITY.name" : "Імунітет до заклять розуму",
"core.bonus.MIND_IMMUNITY.description" : "Імунітет до заклять типу ",
"core.bonus.NO_DISTANCE_PENALTY.name" : "Немає штрафу за відстань",
@@ -711,6 +723,8 @@
"core.bonus.NO_WALL_PENALTY.description" : "Повна шкода при пострілах через стіни",
"core.bonus.NON_LIVING.name" : "Не жива",
"core.bonus.NON_LIVING.description" : "Імунітет до багатьох ефектів",
"core.bonus.PRISM_HEX_ATTACK_BREATH.description" : "Атака подихом у трьох напрямах",
"core.bonus.PRISM_HEX_ATTACK_BREATH.name" : "Призматична атака",
"core.bonus.RANDOM_SPELLCASTER.name" : "Випадковий заклинатель",
"core.bonus.RANDOM_SPELLCASTER.description" : "Може накласти випадкове закляття",
"core.bonus.RANGED_RETALIATION.name" : "Дистанційна відплата",
@@ -721,6 +735,8 @@
"core.bonus.REBIRTH.description" : "${val}% загону відродиться після смерті",
"core.bonus.RETURN_AFTER_STRIKE.name" : "Атакує і повертається",
"core.bonus.RETURN_AFTER_STRIKE.description" : "Повертається після атаки ближнього бою",
"core.bonus.REVENGE.name" : "Помста",
"core.bonus.REVENGE.description" : "Завдає додаткової шкоди залежно від втраченого здоров'я в бою",
"core.bonus.SHOOTER.name" : "Стрілок",
"core.bonus.SHOOTER.description" : "Істота може стріляти",
"core.bonus.SHOOTS_ALL_ADJACENT.name" : "Стріляйте по площі",
@@ -729,16 +745,36 @@
"core.bonus.SOUL_STEAL.description" : "Отримує ${val} нових істот за кожного вбитого ворога",
"core.bonus.SPELLCASTER.name" : "Заклинатель",
"core.bonus.SPELLCASTER.description" : "Може використовувати закляття ${subtype.spell}",
"core.bonus.SPELL_AFTER_ATTACK.name" : "Після атаки",
"core.bonus.SPELL_AFTER_ATTACK.name" : "Закляття після атаки",
"core.bonus.SPELL_AFTER_ATTACK.description" : "Застосовує ${subtype.spell} з вірогідністю ${val}% після атаки",
"core.bonus.SPELL_BEFORE_ATTACK.name" : "закляття перед атакою",
"core.bonus.SPELL_BEFORE_ATTACK.name" : "Закляття перед атакою",
"core.bonus.SPELL_BEFORE_ATTACK.description" : "Застосовує ${subtype.spell} з вірогідністю ${val}% перед атакою",
"core.bonus.SPELL_DAMAGE_REDUCTION.name": "Стійкість до заклять",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.air": "Стійкість до Повітря",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.fire": "Стійкість до Вогню",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.water": "Стійкість до Води",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.earth": "Стійкість до Землі",
"core.bonus.SPELL_DAMAGE_REDUCTION.description": "Шкода від усіх заклять зменшується на ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.air": "Шкода від усіх заклять школи Повітря зменшується на ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.fire": "Шкода від усіх заклять школи Вогню зменшується на ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.water": "Шкода від усіх заклять школи Води зменшується на ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.earth": "Шкода від усіх заклять школи Землі зменшується на ${val}%.",
"core.bonus.SPELL_IMMUNITY.name" : "Імунітет до заклять",
"core.bonus.SPELL_IMMUNITY.description" : "Імунітет до ${subtype.spell}",
"core.bonus.SPELL_LIKE_ATTACK.name" : "Атака, схожа на закляття",
"core.bonus.SPELL_LIKE_ATTACK.description" : "Атакує за допомогою ${subtype.spell}",
"core.bonus.SPELL_RESISTANCE_AURA.name" : "Аура стійкості",
"core.bonus.SPELL_RESISTANCE_AURA.description" : "Поруч розташовані стеки отримують ${val}% опору",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name": "Імунітет до усіх заклять",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.air": "Імунітет до Повітря",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.fire": "Імунітет до Вогню",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.water": "Імунітет до Води",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.earth": "Імунітет до Землі",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description": "На цей загін не діють жодні заклинання",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.air": "На цей загін не діють жодні закляття школи Повітря",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.fire": "На цей загін не діють жодні закляття школи Вогню",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.water": "На цей загін не діють жодні закляття школи Води",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.earth": "На цей загін не діють жодні закляття школи Землі",
"core.bonus.SUMMON_GUARDIANS.name" : "Закликати охоронців",
"core.bonus.SUMMON_GUARDIANS.description" : "На початку бою викликає ${subtype.creature} (${val}%)",
"core.bonus.SYNERGY_TARGET.name" : "Синергізм",
@@ -757,42 +793,6 @@
"core.bonus.WATER_IMMUNITY.description" : "Імунітет до всіх заклять школи Води",
"core.bonus.WIDE_BREATH.name" : "Широкий подих",
"core.bonus.WIDE_BREATH.description" : "Атака широким подихом",
"core.bonus.LIMITED_SHOOTING_RANGE.name" : "Обмежена дальність стрільби",
"core.bonus.LIMITED_SHOOTING_RANGE.description" : "Не може стріляти по цілях на відстані більше ${val} гексів",
"core.bonus.DISINTEGRATE.description" : "Після смерті не залишається трупа",
"core.bonus.DISINTEGRATE.name" : "Розпад",
"core.bonus.ENEMY_ATTACK_REDUCTION.description" : "При атаці ігнорується ${val}% атаки нападника",
"core.bonus.ENEMY_ATTACK_REDUCTION.name" : "Ігнорування атаки (${val}%)",
"core.bonus.FEROCITY.description" : "Атакує ${val} більше разів, якщо вбиває когось",
"core.bonus.FEROCITY.name" : "Лютість",
"core.bonus.INVINCIBLE.description" : "На нього ніщо не може вплинути",
"core.bonus.INVINCIBLE.name" : "Невразливий",
"core.bonus.MECHANICAL.description" : "Імунітет до багатьох ефектів, можна ремонтувати",
"core.bonus.MECHANICAL.name" : "Механічний",
"core.bonus.PRISM_HEX_ATTACK_BREATH.description" : "Атака подихом у трьох напрямах",
"core.bonus.PRISM_HEX_ATTACK_BREATH.name" : "Призматична атака",
"core.bonus.SPELL_DAMAGE_REDUCTION.name": "Стійкість до заклять",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.air": "Стійкість до Повітря",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.fire": "Стійкість до Вогню",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.water": "Стійкість до Води",
"core.bonus.SPELL_DAMAGE_REDUCTION.name.earth": "Стійкість до Землі",
"core.bonus.SPELL_DAMAGE_REDUCTION.description": "Шкода від усіх заклять зменшується на ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.air": "Шкода від усіх заклять школи Повітря зменшується на ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.fire": "Шкода від усіх заклять школи Вогню зменшується на ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.water": "Шкода від усіх заклять школи Води зменшується на ${val}%.",
"core.bonus.SPELL_DAMAGE_REDUCTION.description.earth": "Шкода від усіх заклять школи Землі зменшується на ${val}%.",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name": "Імунітет до усіх заклять",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.air": "Імунітет до Повітря",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.fire": "Імунітет до Вогню",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.water": "Імунітет до Води",
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.earth": "Імунітет до Землі",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description": "На цей загін не діють жодні заклинання",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.air": "На цей загін не діють жодні закляття школи Повітря",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.fire": "На цей загін не діють жодні закляття школи Вогню",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.water": "На цей загін не діють жодні закляття школи Води",
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.earth": "На цей загін не діють жодні закляття школи Землі",
"core.bonus.REVENGE.description" : "Завдає додаткової шкоди залежно від втраченого здоров'я в бою",
"core.bonus.REVENGE.name" : "Помста",
"spell.core.castleMoat.name" : "Рів",
"spell.core.castleMoatTrigger.name" : "Рів",

View File

@@ -258,8 +258,8 @@ CStackWindow::BonusLineSection::BonusLineSection(CStackWindow * owner, size_t li
static const std::array<Point, 2> offset =
{
Point(6, 4),
Point(214, 4)
Point(6, 2),
Point(214, 2)
};
auto drawBonusSource = [this](int leftRight, Point p, BonusInfo & bi)
@@ -274,7 +274,7 @@ CStackWindow::BonusLineSection::BonusLineSection(CStackWindow * owner, size_t li
{BonusSource::STACK_EXPERIENCE, Colors::CYAN},
{BonusSource::COMMANDER, Colors::CYAN},
};
std::map<BonusSource, std::string> bonusNames = {
{BonusSource::ARTIFACT, LIBRARY->generaltexth->translate("vcmi.bonusSource.artifact")},
{BonusSource::ARTIFACT_INSTANCE, LIBRARY->generaltexth->translate("vcmi.bonusSource.artifact")},
@@ -313,8 +313,14 @@ CStackWindow::BonusLineSection::BonusLineSection(CStackWindow * owner, size_t li
BonusInfo & bi = parent->activeBonuses[bonusIndex];
if (!bi.imagePath.empty())
icon[leftRight] = std::make_shared<CPicture>(bi.imagePath, position.x, position.y);
name[leftRight] = std::make_shared<CLabel>(position.x + 60, position.y + 2, FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, bi.name, 137);
description[leftRight] = std::make_shared<CMultiLineLabel>(Rect(position.x + 60, position.y + 20, 137, 26), FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, bi.description);
if (!bi.name.empty())
{
name[leftRight] = std::make_shared<CLabel>(position.x + 60, position.y + 2, FONT_TINY, ETextAlignment::TOPLEFT, Colors::YELLOW, bi.name, 137);
description[leftRight] = std::make_shared<CMultiLineLabel>(Rect(position.x + 60, position.y + 20, 137, 26), FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, bi.description);
}
else
description[leftRight] = std::make_shared<CMultiLineLabel>(Rect(position.x + 60, position.y + 2, 137, 50), FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, bi.description);
drawBonusSource(leftRight, Point(position.x - 1, position.y - 1), bi);
}
}
@@ -846,12 +852,10 @@ void CStackWindow::init()
void CStackWindow::initBonusesList()
{
auto inputPtr = info->stackNode->getBonuses(CSelector(Bonus::Permanent), Selector::all);
BonusList receivedBonuses = *info->stackNode->getBonuses(CSelector(Bonus::Permanent), Selector::all);
BonusList abilities = info->creature->getExportedBonusList();
BonusList output;
BonusList input = *inputPtr;
std::sort(input.begin(), input.end(), [this](std::shared_ptr<Bonus> v1, std::shared_ptr<Bonus> & v2){
const auto & bonusSortingPredicate = [this](const std::shared_ptr<Bonus> & v1, const std::shared_ptr<Bonus> & v2){
if (v1->source != v2->source)
{
int priorityV1 = v1->source == BonusSource::CREATURE_ABILITY ? -1 : static_cast<int>(v1->source);
@@ -860,30 +864,78 @@ void CStackWindow::initBonusesList()
}
else
return info->stackNode->bonusToString(v1, false) < info->stackNode->bonusToString(v2, false);
});
};
while(!input.empty())
// these bonuses require special handling. For example they come with own descriptions, for use in morale/luck description
// also, this information is already available in creature window
receivedBonuses.remove_if(Selector::type()(BonusType::MORALE));
receivedBonuses.remove_if(Selector::type()(BonusType::LUCK));
std::vector<BonusList> groupedBonuses;
while (!receivedBonuses.empty())
{
auto b = input.front();
output.push_back(std::make_shared<Bonus>(*b));
output.back()->val = input.valOfBonuses(Selector::typeSubtype(b->type, b->subtype)); //merge multiple bonuses into one
input.remove_if (Selector::typeSubtype(b->type, b->subtype)); //remove used bonuses
auto currentBonus = receivedBonuses.front();
const auto & sameBonusPredicate = [currentBonus](const std::shared_ptr<Bonus> & b)
{
return currentBonus->type == b->type && currentBonus->subtype == b->subtype;
};
groupedBonuses.emplace_back();
std::copy_if(receivedBonuses.begin(), receivedBonuses.end(), std::back_inserter(groupedBonuses.back()), sameBonusPredicate);
receivedBonuses.remove_if(Selector::typeSubtype(currentBonus->type, currentBonus->subtype));
// FIXME: potential edge case: unit has ability that is propagated away (and needs to be displayed), but also receives same bonus from someplace else
abilities.remove_if(Selector::typeSubtype(currentBonus->type, currentBonus->subtype));
}
// Add any remaining abilities of this unit that don't affect it at the moment, such as abilities that are propagated away, e.g. to other side in combat
BonusList visibleBonuses = abilities;
for (auto & group : groupedBonuses)
{
// Try to find the bonus in the group that represents the final effect in the best way.
std::sort(group.begin(), group.end(), bonusSortingPredicate);
BonusList groupIndepMin = group;
BonusList groupIndepMax = group;
BonusList groupNoMinMax = group;
groupIndepMin.remove_if([](const Bonus * b) { return b->valType != BonusValueType::INDEPENDENT_MIN; });
groupIndepMax.remove_if([](const Bonus * b) { return b->valType != BonusValueType::INDEPENDENT_MAX; });
groupNoMinMax.remove_if([](const Bonus * b) { return b->valType == BonusValueType::INDEPENDENT_MAX || b->valType == BonusValueType::INDEPENDENT_MIN; });
int valIndepMin = groupIndepMin.totalValue();
int valIndepMax = groupIndepMax.totalValue();
int valNoMinMax = group.totalValue();
BonusList usedGroup;
if (!groupIndepMin.empty() && valNoMinMax != valIndepMin)
usedGroup = groupIndepMin; // bonus value was limited due to INDEPENDENT_MIN bonus -> show this bonus
else if (!groupIndepMax.empty() && valNoMinMax != valIndepMax)
usedGroup = groupIndepMax; // bonus value was limited due to INDEPENDENT_MAX bonus -> show this bonus
else
usedGroup = groupNoMinMax; // bonus value is not limited - show first non-independent bonus
// It is possible that empty group was selected. For example, there is only INDEPENDENT effect with value of 0, which does not actually has any effect on this unit
// For example, orb of vulnerability on unit without any resistances
if (!usedGroup.empty())
visibleBonuses.push_back(usedGroup.front());
}
std::sort(visibleBonuses.begin(), visibleBonuses.end(), bonusSortingPredicate);
BonusInfo bonusInfo;
for(auto b : output)
for(auto b : visibleBonuses)
{
bonusInfo.name = info->stackNode->bonusToString(b, false);
bonusInfo.description = info->stackNode->bonusToString(b, true);
bonusInfo.imagePath = info->stackNode->bonusToGraphics(b);
bonusInfo.bonusSource = b->source;
if(b->sid.as<CreatureID>() != info->stackNode->getId() && b->propagator && b->propagator->getPropagatorType() == CBonusSystemNode::HERO) // Shows bonus with "propagator":"HERO" only at creature with bonus
continue;
//if it's possible to give any description or image for this kind of bonus
//TODO: figure out why half of bonuses don't have proper description
if(!bonusInfo.name.empty() || !bonusInfo.imagePath.empty())
if(!bonusInfo.name.empty() || !bonusInfo.description.empty())
activeBonuses.push_back(bonusInfo);
}
}

View File

@@ -124,7 +124,7 @@ std::vector<std::string> CMessage::breakText(std::string text, size_t maxLineWid
// not all line has been processed - it turned out to be too long, so erase everything after last word break
// if string consists from a single word (or this is Chinese/Korean) - erase only last symbol to bring line back to allowed length
if(currPos < text.length() && (text[currPos] != 0x0a))
if(fontPtr->getStringWidth(printableString) > maxLineWidth && (text[currPos] != 0x0a))
{
if(wordBreak != ui32(-1))
{

View File

@@ -79,14 +79,14 @@
"type" : "MORALE",
"val" : 1,
"valueType" : "BASE_NUMBER",
"description" : "core.arraytxt.123",
"description" : "@core.arraytxt.123",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["good"] }]
},
{
"type" : "MORALE",
"val" : -1,
"valueType" : "BASE_NUMBER",
"description" : "core.arraytxt.124",
"description" : "@core.arraytxt.124",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["evil"] }]
}
]
@@ -99,7 +99,7 @@
"type" : "LUCK",
"val" : 2,
"valueType" : "BASE_NUMBER",
"description" : "core.arraytxt.83",
"description" : "@core.arraytxt.83",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["neutral"] }]
}
]
@@ -112,14 +112,14 @@
"type" : "MORALE",
"val" : -1,
"valueType" : "BASE_NUMBER",
"description" : "core.arraytxt.126",
"description" : "@core.arraytxt.126",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["good"] }]
},
{
"type" : "MORALE",
"val" : 1,
"valueType" : "BASE_NUMBER",
"description" : "core.arraytxt.125",
"description" : "@core.arraytxt.125",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["evil"] }]
}
]
@@ -132,13 +132,13 @@
"type" : "NO_MORALE",
"val" : 0,
"valueType" : "INDEPENDENT_MIN",
"description" : "core.arraytxt.112"
"description" : "@core.arraytxt.112"
},
{
"type" : "NO_LUCK",
"val" : 0,
"valueType" : "INDEPENDENT_MIN",
"description" : "core.arraytxt.81"
"description" : "@core.arraytxt.81"
},
{
"type" : "BLOCK_MAGIC_ABOVE",

View File

@@ -178,6 +178,11 @@
"type" : "string",
"description" : "stacking"
},
"icon" : {
"type" : "string",
"description" : "Optional, custom icons to show in creature window",
"format" : "imageFile"
},
"description" : {
"anyOf" : [
{ "type" : "string" },

View File

@@ -17,6 +17,7 @@ digraph mygraph {
<tr><td>C++ Class: <font face="monospace"><b>CGameState</b></font></td></tr>
<tr><td>Global node to which<br/>all map entities are connected</td></tr>
<tr><td>Note: Not recruited heroes (such as in tavern)<br/>are not attached to any node</td></tr>
<tr><td>Contains global bonuses, global stack experience and difficulty bonuses</td></tr>
</table>>
]
"Team" [
@@ -46,6 +47,7 @@ digraph mygraph {
<tr><td>Propagator: <font face="monospace"><b>HERO</b></font></td></tr>
<tr><td>C++ Class: <font face="monospace"><b>CGHeroInstance</b></font></td></tr>
<tr><td>Represents a hero, either owned by player or in prison.<br/>Bonuses from specialty and secondary skills<br/>are attached directly to this node</td></tr>
<tr><td>Contains per-hero global bonuses, specialty bonuses, <br/>primary and secondary skill bonuses, campaign primary skill bonus</td></tr>
</table>>
]
"Combat" [
@@ -94,6 +96,13 @@ digraph mygraph {
<tr><td>Army owned by a player.<br/>Mines, Garrisons, Dwellings</td></tr>
</table>>
]
"Owned Object" [
label =<<table>
<tr><td><b>Owned Object</b></td></tr>
<tr><td>Other objects owned by a player, like Lighthouse</td></tr>
<tr><td>Contains Flaggable Objects bonuses</td></tr>
</table>>
]
};
subgraph rankedTopHero {
@@ -103,15 +112,17 @@ digraph mygraph {
label =<<table>
<tr><td><b>Town</b></td></tr>
<tr><td>C++ Class: <font face="monospace"><b>CGTownInstance</b></font></td></tr>
<tr><td>Represents a town on map.<br/>Town buildings can provide bonuses to this node<br/>(or propagate them upward)</td></tr>
<tr><td>Represents a town on map.</td></tr>
<tr><td>Contains town building bonuses</td></tr>
</table>>
]
"Artifact Instance" [
fillcolor="#00FFFF80"
label =<<table>
<tr><td><b>Artifact Instance</b></td></tr>
<tr><td>C++ Class: <font face="monospace"><b>CArtifact</b></font></td></tr>
<tr><td>C++ Class: <font face="monospace"><b>CArtifactInstance</b></font></td></tr>
<tr><td>Represents a particular instance of an artifact<br/> that hero can equip or trade</td></tr>
<tr><td>Contains bonuses of spell scrolls and growing artifacts</td></tr>
</table>>
]
"Boat" [
@@ -119,7 +130,8 @@ digraph mygraph {
label =<<table>
<tr><td><b>Boat</b></td></tr>
<tr><td>C++ Class: <font face="monospace"><b>CGBoat</b></font></td></tr>
<tr><td>Represents a boat or other type of transport.<br/>Can provide bonuses to boarded hero</td></tr>
<tr><td>Represents a boat or other type of transport.</td></tr>
<tr><td>Contains bonuses provided to boarded hero</td></tr>
</table>>
]
};
@@ -142,6 +154,7 @@ digraph mygraph {
<tr><td>Propagator: <font face="monospace"><b>BATTLE_WIDE</b></font></td></tr>
<tr><td>C++ Class: <font face="monospace"><b>BattleInfo</b></font></td></tr>
<tr><td>Node that contains both sides of a combat<br/>Anything propagated to this node will affect both sides in combat</td></tr>
<tr><td>Contains battlefield and native terrain bonuses</td></tr>
</table>>
]
@@ -151,6 +164,7 @@ digraph mygraph {
<tr><td><b>Creature Type</b></td></tr>
<tr><td>C++ Class: <font face="monospace"><b>CCreature</b></font></td></tr>
<tr><td>Represents a creature type, such as Pikeman or Archer</td></tr>
<tr><td>Contains creature abilities bonuses, stack experience bonuses</td></tr>
</table>>
]
@@ -160,6 +174,7 @@ digraph mygraph {
<tr><td><b>Artifact Type</b></td></tr>
<tr><td>C++ Class: <font face="monospace"><b>CArtifact</b></font></td></tr>
<tr><td>Represents an artifact type, for example Ring of Life</td></tr>
<tr><td>Contains fixed bonuses of artifacts</td></tr>
</table>>
]
@@ -167,7 +182,7 @@ digraph mygraph {
fillcolor="#80808080"
label =<<table>
<tr><td><b>Artifact Component</b></td></tr>
<tr><td>C++ Class: <font face="monospace"><b>CArtifact</b></font></td></tr>
<tr><td>C++ Class: <font face="monospace"><b>CArtifactInstance</b></font></td></tr>
<tr><td>For combined, non-fused artifacts,<br/>instances of components are attached to instance of combined artifact</td></tr>
</table>>
]
@@ -177,6 +192,7 @@ digraph mygraph {
<tr><td><b>Army</b></td></tr>
<tr><td>C++ Class: <font face="monospace"><b>CArmedInstance</b></font></td></tr>
<tr><td>Represents any object that can hold army,<br/>such as town, hero, mines, garrisons, wandering monsters</td></tr>
<tr><td>Contain anti-magic garrison bonus, faction mixing morale bonus</td></tr>
</table>>
]
@@ -188,6 +204,14 @@ digraph mygraph {
</table>>
]
"Commander" [
label =<<table>
<tr><td><b>Commander</b></td></tr>
<tr><td>C++ Class: <font face="monospace"><b>CCommanderInstance</b></font></td></tr>
<tr><td>Represents a hero commander, WoG feature</td></tr>
</table>>
]
"Unit in Combat" [
label =<<table>
<tr><td><b>Unit in Combat</b></td></tr>
@@ -211,17 +235,21 @@ digraph mygraph {
"Player" -> "Town and visiting hero"
"Player" -> "Wandering Hero"
"Player" -> "Owned Army"
"Player" -> "Owned Object"
"Town and visiting hero" -> "Town"
"Town and visiting hero" -> "Visiting Hero"
"Boat" -> "Hero"
"Combat" -> "Army"
"Army" -> "Commander"
"Army" -> "Unit in Army"
"Army" -> "Summon in Combat"
"Unit in Army" -> "Unit in Combat"
"Commander" -> "Unit in Combat"
"Artifact Type" -> "Artifact Instance"
"Artifact Component" -> "Artifact Instance"
"Artifact Instance" -> "Hero"
"Creature Type" -> "Commander"
"Creature Type" -> "Summon in Combat"
"Creature Type" -> "Unit in Army"

View File

@@ -4,471 +4,536 @@
<!-- Generated by graphviz version 2.43.0 (0)
-->
<!-- Title: mygraph Pages: 1 -->
<svg width="1625pt" height="1440pt"
viewBox="0.00 0.00 1624.50 1440.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1436)">
<svg width="1970pt" height="1540pt"
viewBox="0.00 0.00 1970.00 1540.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1536)">
<title>mygraph</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-1436 1620.5,-1436 1620.5,4 -4,4"/>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-1536 1966,-1536 1966,4 -4,4"/>
<!-- Global -->
<g id="node1" class="node">
<title>Global</title>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1365.5,-1432 1047.5,-1432 1047.5,-1283 1365.5,-1283 1365.5,-1432"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1050.5,-1407.5 1050.5,-1428.5 1362.5,-1428.5 1362.5,-1407.5 1050.5,-1407.5"/>
<text text-anchor="start" x="1183" y="-1415.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Global</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1050.5,-1384.5 1050.5,-1405.5 1362.5,-1405.5 1362.5,-1384.5 1050.5,-1384.5"/>
<text text-anchor="start" x="1110.5" y="-1392.3" font-family="Noto Serif" font-size="14.00">Propagator: </text>
<text text-anchor="start" x="1194.5" y="-1392.3" font-family="monospace" font-weight="bold" font-size="14.00">GLOBAL_EFFECT</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1050.5,-1361.5 1050.5,-1382.5 1362.5,-1382.5 1362.5,-1361.5 1050.5,-1361.5"/>
<text text-anchor="start" x="1131" y="-1369.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1199" y="-1369.3" font-family="monospace" font-weight="bold" font-size="14.00">CGameState</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1050.5,-1323.5 1050.5,-1359.5 1362.5,-1359.5 1362.5,-1323.5 1050.5,-1323.5"/>
<text text-anchor="start" x="1135" y="-1345.3" font-family="Noto Serif" font-size="14.00">Global node to which</text>
<text text-anchor="start" x="1105" y="-1330.3" font-family="Noto Serif" font-size="14.00">all map entities are connected</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1050.5,-1285.5 1050.5,-1321.5 1362.5,-1321.5 1362.5,-1285.5 1050.5,-1285.5"/>
<text text-anchor="start" x="1053.5" y="-1307.3" font-family="Noto Serif" font-size="14.00">Note: Not recruited heroes (such as in tavern)</text>
<text text-anchor="start" x="1109" y="-1292.3" font-family="Noto Serif" font-size="14.00">are not attached to any node</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1047.5,-1283 1047.5,-1432 1365.5,-1432 1365.5,-1283 1047.5,-1283"/>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1495,-1532 1005,-1532 1005,-1360 1495,-1360 1495,-1532"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1008,-1508 1008,-1529 1492,-1529 1492,-1508 1008,-1508"/>
<text text-anchor="start" x="1226.5" y="-1515.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Global</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1008,-1485 1008,-1506 1492,-1506 1492,-1485 1008,-1485"/>
<text text-anchor="start" x="1154" y="-1492.8" font-family="Noto Serif" font-size="14.00">Propagator: </text>
<text text-anchor="start" x="1238" y="-1492.8" font-family="monospace" font-weight="bold" font-size="14.00">GLOBAL_EFFECT</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1008,-1462 1008,-1483 1492,-1483 1492,-1462 1008,-1462"/>
<text text-anchor="start" x="1174.5" y="-1469.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1242.5" y="-1469.8" font-family="monospace" font-weight="bold" font-size="14.00">CGameState</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1008,-1424 1008,-1460 1492,-1460 1492,-1424 1008,-1424"/>
<text text-anchor="start" x="1178.5" y="-1445.8" font-family="Noto Serif" font-size="14.00">Global node to which</text>
<text text-anchor="start" x="1148.5" y="-1430.8" font-family="Noto Serif" font-size="14.00">all map entities are connected</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1008,-1386 1008,-1422 1492,-1422 1492,-1386 1008,-1386"/>
<text text-anchor="start" x="1097" y="-1407.8" font-family="Noto Serif" font-size="14.00">Note: Not recruited heroes (such as in tavern)</text>
<text text-anchor="start" x="1152.5" y="-1392.8" font-family="Noto Serif" font-size="14.00">are not attached to any node</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1008,-1363 1008,-1384 1492,-1384 1492,-1363 1008,-1363"/>
<text text-anchor="start" x="1011" y="-1369.8" font-family="Noto Serif" font-size="14.00">Contains global bonuses, global stack experience and difficulty bonuses</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1005,-1360 1005,-1532 1495,-1532 1495,-1360 1005,-1360"/>
</g>
<!-- Team -->
<g id="node2" class="node">
<title>Team</title>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1256,-1247 1001,-1247 1001,-1121 1256,-1121 1256,-1247"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1004.5,-1223 1004.5,-1244 1253.5,-1244 1253.5,-1223 1004.5,-1223"/>
<text text-anchor="start" x="1109" y="-1230.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Team</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1004.5,-1200 1004.5,-1221 1253.5,-1221 1253.5,-1200 1004.5,-1200"/>
<text text-anchor="start" x="1025" y="-1207.8" font-family="Noto Serif" font-size="14.00">Propagator: </text>
<text text-anchor="start" x="1109" y="-1207.8" font-family="monospace" font-weight="bold" font-size="14.00">TEAM_PROPAGATOR</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1004.5,-1177 1004.5,-1198 1253.5,-1198 1253.5,-1177 1004.5,-1177"/>
<text text-anchor="start" x="1057.5" y="-1184.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1125.5" y="-1184.8" font-family="monospace" font-weight="bold" font-size="14.00">TeamState</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1004.5,-1124 1004.5,-1175 1253.5,-1175 1253.5,-1124 1004.5,-1124"/>
<text text-anchor="start" x="1077.5" y="-1160.8" font-family="Noto Serif" font-size="14.00">Per&#45;team node.</text>
<text text-anchor="start" x="1007.5" y="-1145.8" font-family="Noto Serif" font-size="14.00">Game will put players without team</text>
<text text-anchor="start" x="1022" y="-1130.8" font-family="Noto Serif" font-size="14.00">into a team with a single player</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1001,-1121 1001,-1247 1256,-1247 1256,-1121 1001,-1121"/>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1299.5,-1324 1044.5,-1324 1044.5,-1198 1299.5,-1198 1299.5,-1324"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1048,-1300 1048,-1321 1297,-1321 1297,-1300 1048,-1300"/>
<text text-anchor="start" x="1152.5" y="-1307.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Team</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1048,-1277 1048,-1298 1297,-1298 1297,-1277 1048,-1277"/>
<text text-anchor="start" x="1068.5" y="-1284.8" font-family="Noto Serif" font-size="14.00">Propagator: </text>
<text text-anchor="start" x="1152.5" y="-1284.8" font-family="monospace" font-weight="bold" font-size="14.00">TEAM_PROPAGATOR</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1048,-1254 1048,-1275 1297,-1275 1297,-1254 1048,-1254"/>
<text text-anchor="start" x="1101" y="-1261.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1169" y="-1261.8" font-family="monospace" font-weight="bold" font-size="14.00">TeamState</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1048,-1201 1048,-1252 1297,-1252 1297,-1201 1048,-1201"/>
<text text-anchor="start" x="1121" y="-1237.8" font-family="Noto Serif" font-size="14.00">Per&#45;team node.</text>
<text text-anchor="start" x="1051" y="-1222.8" font-family="Noto Serif" font-size="14.00">Game will put players without team</text>
<text text-anchor="start" x="1065.5" y="-1207.8" font-family="Noto Serif" font-size="14.00">into a team with a single player</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1044.5,-1198 1044.5,-1324 1299.5,-1324 1299.5,-1198 1044.5,-1198"/>
</g>
<!-- Global&#45;&gt;Team -->
<g id="edge1" class="edge">
<title>Global&#45;&gt;Team</title>
<path fill="none" stroke="black" d="M1172.97,-1282.77C1169,-1274.04 1164.95,-1265.14 1160.99,-1256.43"/>
<polygon fill="black" stroke="black" points="1164.07,-1254.74 1156.74,-1247.09 1157.69,-1257.64 1164.07,-1254.74"/>
<path fill="none" stroke="black" d="M1213.74,-1359.93C1209.97,-1351.09 1206.17,-1342.16 1202.47,-1333.49"/>
<polygon fill="black" stroke="black" points="1205.65,-1332.03 1198.51,-1324.2 1199.21,-1334.77 1205.65,-1332.03"/>
</g>
<!-- Neutral Army -->
<g id="node9" class="node">
<title>Neutral Army</title>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="1616.5,-614 1336.5,-614 1336.5,-549 1616.5,-549 1616.5,-614"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1339.5,-589.5 1339.5,-610.5 1613.5,-610.5 1613.5,-589.5 1339.5,-589.5"/>
<text text-anchor="start" x="1427" y="-597.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Neutral Army</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1339.5,-551.5 1339.5,-587.5 1613.5,-587.5 1613.5,-551.5 1339.5,-551.5"/>
<text text-anchor="start" x="1343" y="-573.3" font-family="Noto Serif" font-size="14.00">Any army that is not owned by a player</text>
<text text-anchor="start" x="1342.5" y="-558.3" font-family="Noto Serif" font-size="14.00">Wandering monsters, Banks, Events, etc</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1336.5,-549 1336.5,-614 1616.5,-614 1616.5,-549 1336.5,-549"/>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="1962,-679 1682,-679 1682,-614 1962,-614 1962,-679"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1685,-654.5 1685,-675.5 1959,-675.5 1959,-654.5 1685,-654.5"/>
<text text-anchor="start" x="1772.5" y="-662.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Neutral Army</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1685,-616.5 1685,-652.5 1959,-652.5 1959,-616.5 1685,-616.5"/>
<text text-anchor="start" x="1688.5" y="-638.3" font-family="Noto Serif" font-size="14.00">Any army that is not owned by a player</text>
<text text-anchor="start" x="1688" y="-623.3" font-family="Noto Serif" font-size="14.00">Wandering monsters, Banks, Events, etc</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1682,-614 1682,-679 1962,-679 1962,-614 1682,-614"/>
</g>
<!-- Global&#45;&gt;Neutral Army -->
<g id="edge2" class="edge">
<title>Global&#45;&gt;Neutral Army</title>
<path fill="none" stroke="black" d="M1292.33,-1282.85C1354.8,-1220.68 1428.5,-1125.59 1428.5,-1023 1428.5,-1023 1428.5,-1023 1428.5,-855 1428.5,-771.96 1450.39,-676.82 1464.6,-623.78"/>
<polygon fill="black" stroke="black" points="1468,-624.63 1467.25,-614.07 1461.24,-622.8 1468,-624.63"/>
<path fill="none" stroke="black" d="M1495.07,-1396.94C1650.32,-1350.63 1822,-1262.65 1822,-1100 1822,-1100 1822,-1100 1822,-932 1822,-845.69 1822,-744.66 1822,-689.21"/>
<polygon fill="black" stroke="black" points="1825.5,-689.07 1822,-679.07 1818.5,-689.07 1825.5,-689.07"/>
</g>
<!-- Player -->
<g id="node3" class="node">
<title>Player</title>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1173,-1085 936,-1085 936,-959 1173,-959 1173,-1085"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="939.5,-1061 939.5,-1082 1170.5,-1082 1170.5,-1061 939.5,-1061"/>
<text text-anchor="start" x="1031.5" y="-1068.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Player</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="939.5,-1038 939.5,-1059 1170.5,-1059 1170.5,-1038 939.5,-1038"/>
<text text-anchor="start" x="942.5" y="-1045.8" font-family="Noto Serif" font-size="14.00">Propagator: </text>
<text text-anchor="start" x="1026.5" y="-1045.8" font-family="monospace" font-weight="bold" font-size="14.00">PLAYER_PROPAGATOR</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="939.5,-1015 939.5,-1036 1170.5,-1036 1170.5,-1015 939.5,-1015"/>
<text text-anchor="start" x="971" y="-1022.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1039" y="-1022.8" font-family="monospace" font-weight="bold" font-size="14.00">CPlayerState</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="939.5,-962 939.5,-1013 1170.5,-1013 1170.5,-962 939.5,-962"/>
<text text-anchor="start" x="999" y="-998.8" font-family="Noto Serif" font-size="14.00">Per&#45;player team.</text>
<text text-anchor="start" x="956.5" y="-983.8" font-family="Noto Serif" font-size="14.00">All objects owned by a player</text>
<text text-anchor="start" x="988" y="-968.8" font-family="Noto Serif" font-size="14.00">belong to such node</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="936,-959 936,-1085 1173,-1085 1173,-959 936,-959"/>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="796.5,-1162 559.5,-1162 559.5,-1036 796.5,-1036 796.5,-1162"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="563,-1138 563,-1159 794,-1159 794,-1138 563,-1138"/>
<text text-anchor="start" x="655" y="-1145.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Player</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="563,-1115 563,-1136 794,-1136 794,-1115 563,-1115"/>
<text text-anchor="start" x="566" y="-1122.8" font-family="Noto Serif" font-size="14.00">Propagator: </text>
<text text-anchor="start" x="650" y="-1122.8" font-family="monospace" font-weight="bold" font-size="14.00">PLAYER_PROPAGATOR</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="563,-1092 563,-1113 794,-1113 794,-1092 563,-1092"/>
<text text-anchor="start" x="594.5" y="-1099.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="662.5" y="-1099.8" font-family="monospace" font-weight="bold" font-size="14.00">CPlayerState</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="563,-1039 563,-1090 794,-1090 794,-1039 563,-1039"/>
<text text-anchor="start" x="622.5" y="-1075.8" font-family="Noto Serif" font-size="14.00">Per&#45;player team.</text>
<text text-anchor="start" x="580" y="-1060.8" font-family="Noto Serif" font-size="14.00">All objects owned by a player</text>
<text text-anchor="start" x="611.5" y="-1045.8" font-family="Noto Serif" font-size="14.00">belong to such node</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="559.5,-1036 559.5,-1162 796.5,-1162 796.5,-1036 559.5,-1036"/>
</g>
<!-- Team&#45;&gt;Player -->
<g id="edge3" class="edge">
<title>Team&#45;&gt;Player</title>
<path fill="none" stroke="black" d="M1099.68,-1120.68C1095.67,-1112.02 1091.53,-1103.07 1087.46,-1094.26"/>
<polygon fill="black" stroke="black" points="1090.62,-1092.76 1083.24,-1085.15 1084.26,-1095.69 1090.62,-1092.76"/>
<path fill="none" stroke="black" d="M1044.46,-1218.69C971.28,-1194.99 879.66,-1165.31 806.34,-1141.57"/>
<polygon fill="black" stroke="black" points="807.17,-1138.16 796.58,-1138.4 805.01,-1144.82 807.17,-1138.16"/>
</g>
<!-- Wandering Hero -->
<g id="node8" class="node">
<title>Wandering Hero</title>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="784.5,-614 548.5,-614 548.5,-549 784.5,-549 784.5,-614"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="551.5,-589.5 551.5,-610.5 781.5,-610.5 781.5,-589.5 551.5,-589.5"/>
<text text-anchor="start" x="607.5" y="-597.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Wandering Hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="551.5,-551.5 551.5,-587.5 781.5,-587.5 781.5,-551.5 551.5,-551.5"/>
<text text-anchor="start" x="592.5" y="-573.3" font-family="Noto Serif" font-size="14.00">Hero that is currently</text>
<text text-anchor="start" x="554.5" y="-558.3" font-family="Noto Serif" font-size="14.00">moving on map, outside of towns</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="548.5,-549 548.5,-614 784.5,-614 784.5,-549 548.5,-549"/>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="1664,-679 1428,-679 1428,-614 1664,-614 1664,-679"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1431,-654.5 1431,-675.5 1661,-675.5 1661,-654.5 1431,-654.5"/>
<text text-anchor="start" x="1487" y="-662.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Wandering Hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1431,-616.5 1431,-652.5 1661,-652.5 1661,-616.5 1431,-616.5"/>
<text text-anchor="start" x="1472" y="-638.3" font-family="Noto Serif" font-size="14.00">Hero that is currently</text>
<text text-anchor="start" x="1434" y="-623.3" font-family="Noto Serif" font-size="14.00">moving on map, outside of towns</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1428,-614 1428,-679 1664,-679 1664,-614 1428,-614"/>
</g>
<!-- Player&#45;&gt;Wandering Hero -->
<g id="edge5" class="edge">
<title>Player&#45;&gt;Wandering Hero</title>
<path fill="none" stroke="black" d="M1019.12,-958.91C1013.14,-947.18 1007.32,-934.87 1002.5,-923 953.37,-801.94 993.71,-733.83 893.5,-650 884.76,-642.69 841.02,-629.05 794.23,-615.94"/>
<polygon fill="black" stroke="black" points="795.1,-612.55 784.53,-613.24 793.22,-619.29 795.1,-612.55"/>
<path fill="none" stroke="black" d="M796.56,-1096.14C1064.93,-1090.69 1700.65,-1070.42 1765,-1000 1851.75,-905.07 1786.66,-810.2 1696,-719 1682.06,-704.97 1664.83,-693.33 1647.07,-683.81"/>
<polygon fill="black" stroke="black" points="1648.24,-680.47 1637.75,-679.01 1645.04,-686.7 1648.24,-680.47"/>
</g>
<!-- Owned Army -->
<g id="node10" class="node">
<title>Owned Army</title>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="199,-614 0,-614 0,-549 199,-549 199,-614"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="3.5,-589.5 3.5,-610.5 196.5,-610.5 196.5,-589.5 3.5,-589.5"/>
<text text-anchor="start" x="53" y="-597.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Owned Army</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="3.5,-551.5 3.5,-587.5 196.5,-587.5 196.5,-551.5 3.5,-551.5"/>
<text text-anchor="start" x="16.5" y="-573.3" font-family="Noto Serif" font-size="14.00">Army owned by a player.</text>
<text text-anchor="start" x="6.5" y="-558.3" font-family="Noto Serif" font-size="14.00">Mines, Garrisons, Dwellings</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="0,-549 0,-614 199,-614 199,-549 0,-549"/>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="555.5,-679 356.5,-679 356.5,-614 555.5,-614 555.5,-679"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="360,-654.5 360,-675.5 553,-675.5 553,-654.5 360,-654.5"/>
<text text-anchor="start" x="409.5" y="-662.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Owned Army</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="360,-616.5 360,-652.5 553,-652.5 553,-616.5 360,-616.5"/>
<text text-anchor="start" x="373" y="-638.3" font-family="Noto Serif" font-size="14.00">Army owned by a player.</text>
<text text-anchor="start" x="363" y="-623.3" font-family="Noto Serif" font-size="14.00">Mines, Garrisons, Dwellings</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="356.5,-614 356.5,-679 555.5,-679 555.5,-614 356.5,-614"/>
</g>
<!-- Player&#45;&gt;Owned Army -->
<g id="edge6" class="edge">
<title>Player&#45;&gt;Owned Army</title>
<path fill="none" stroke="black" d="M935.73,-1017.81C688.35,-1009.92 135.99,-985.45 79.5,-923 4.57,-840.16 50.92,-694.54 80.5,-623.62"/>
<polygon fill="black" stroke="black" points="83.85,-624.7 84.55,-614.13 77.41,-621.95 83.85,-624.7"/>
<path fill="none" stroke="black" d="M559.38,-1065.77C526.78,-1051.05 494.95,-1029.97 475,-1000 411.22,-904.22 430.78,-759.31 445.74,-688.86"/>
<polygon fill="black" stroke="black" points="449.17,-689.54 447.9,-679.03 442.33,-688.04 449.17,-689.54"/>
</g>
<!-- Owned Object -->
<g id="node11" class="node">
<title>Owned Object</title>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="338,-683 0,-683 0,-610 338,-610 338,-683"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="3,-658.5 3,-679.5 335,-679.5 335,-658.5 3,-658.5"/>
<text text-anchor="start" x="119" y="-666.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Owned Object</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="3,-635.5 3,-656.5 335,-656.5 335,-635.5 3,-635.5"/>
<text text-anchor="start" x="6" y="-642.3" font-family="Noto Serif" font-size="14.00">Other objects owned by a player, like Lighthouse</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="3,-612.5 3,-633.5 335,-633.5 335,-612.5 3,-612.5"/>
<text text-anchor="start" x="50" y="-619.3" font-family="Noto Serif" font-size="14.00">Contains Flaggable Objects bonuses</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="0,-610 0,-683 338,-683 338,-610 0,-610"/>
</g>
<!-- Player&#45;&gt;Owned Object -->
<g id="edge7" class="edge">
<title>Player&#45;&gt;Owned Object</title>
<path fill="none" stroke="black" d="M559.41,-1066.51C515.59,-1051.13 467.31,-1029.44 429,-1000 316.53,-913.58 229.92,-765.96 191.2,-692.2"/>
<polygon fill="black" stroke="black" points="194.22,-690.41 186.5,-683.15 188.01,-693.64 194.22,-690.41"/>
</g>
<!-- Town and visiting hero -->
<g id="node14" class="node">
<g id="node15" class="node">
<title>Town and visiting hero</title>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1398,-923 1011,-923 1011,-789 1398,-789 1398,-923"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1014.5,-899 1014.5,-920 1395.5,-920 1395.5,-899 1014.5,-899"/>
<text text-anchor="start" x="1122" y="-906.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Town and Visiting Hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1014.5,-876 1014.5,-897 1395.5,-897 1395.5,-876 1014.5,-876"/>
<text text-anchor="start" x="1063.5" y="-883.8" font-family="Noto Serif" font-size="14.00">Propagator: </text>
<text text-anchor="start" x="1147.5" y="-883.8" font-family="monospace" font-weight="bold" font-size="14.00">VISITED_TOWN_AND_VISITOR</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1014.5,-853 1014.5,-874 1395.5,-874 1395.5,-853 1014.5,-853"/>
<text text-anchor="start" x="1088" y="-860.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1156" y="-860.8" font-family="monospace" font-weight="bold" font-size="14.00">CTownAndVisitingHero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1014.5,-815 1014.5,-851 1395.5,-851 1395.5,-815 1014.5,-815"/>
<text text-anchor="start" x="1105.5" y="-836.8" font-family="Noto Serif" font-size="14.00">Helper node that exists solely</text>
<text text-anchor="start" x="1029" y="-821.8" font-family="Noto Serif" font-size="14.00">to propagate bonuses to both town and visiting hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1014.5,-792 1014.5,-813 1395.5,-813 1395.5,-792 1014.5,-792"/>
<text text-anchor="start" x="1017.5" y="-798.8" font-family="Noto Serif" font-size="14.00">Note: Neutral towns are attached to global node instead</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1011,-789 1011,-923 1398,-923 1398,-789 1011,-789"/>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="871.5,-1000 484.5,-1000 484.5,-866 871.5,-866 871.5,-1000"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="488,-976 488,-997 869,-997 869,-976 488,-976"/>
<text text-anchor="start" x="595.5" y="-983.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Town and Visiting Hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="488,-953 488,-974 869,-974 869,-953 488,-953"/>
<text text-anchor="start" x="537" y="-960.8" font-family="Noto Serif" font-size="14.00">Propagator: </text>
<text text-anchor="start" x="621" y="-960.8" font-family="monospace" font-weight="bold" font-size="14.00">VISITED_TOWN_AND_VISITOR</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="488,-930 488,-951 869,-951 869,-930 488,-930"/>
<text text-anchor="start" x="561.5" y="-937.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="629.5" y="-937.8" font-family="monospace" font-weight="bold" font-size="14.00">CTownAndVisitingHero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="488,-892 488,-928 869,-928 869,-892 488,-892"/>
<text text-anchor="start" x="579" y="-913.8" font-family="Noto Serif" font-size="14.00">Helper node that exists solely</text>
<text text-anchor="start" x="502.5" y="-898.8" font-family="Noto Serif" font-size="14.00">to propagate bonuses to both town and visiting hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="488,-869 488,-890 869,-890 869,-869 488,-869"/>
<text text-anchor="start" x="491" y="-875.8" font-family="Noto Serif" font-size="14.00">Note: Neutral towns are attached to global node instead</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="484.5,-866 484.5,-1000 871.5,-1000 871.5,-866 484.5,-866"/>
</g>
<!-- Player&#45;&gt;Town and visiting hero -->
<g id="edge4" class="edge">
<title>Player&#45;&gt;Town and visiting hero</title>
<path fill="none" stroke="black" d="M1111.21,-959C1119.65,-949.77 1128.43,-940.17 1137.07,-930.73"/>
<polygon fill="black" stroke="black" points="1139.79,-932.93 1143.96,-923.19 1134.63,-928.21 1139.79,-932.93"/>
<path fill="none" stroke="black" d="M678,-1036C678,-1027.59 678,-1018.88 678,-1010.26"/>
<polygon fill="black" stroke="black" points="681.5,-1010.19 678,-1000.19 674.5,-1010.19 681.5,-1010.19"/>
</g>
<!-- Hero -->
<g id="node4" class="node">
<title>Hero</title>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="1060.5,-513 678.5,-513 678.5,-387 1060.5,-387 1060.5,-513"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="681.5,-489 681.5,-510 1057.5,-510 1057.5,-489 681.5,-489"/>
<text text-anchor="start" x="851.5" y="-496.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="681.5,-466 681.5,-487 1057.5,-487 1057.5,-466 681.5,-466"/>
<text text-anchor="start" x="810.5" y="-473.8" font-family="Noto Serif" font-size="14.00">Propagator: </text>
<text text-anchor="start" x="894.5" y="-473.8" font-family="monospace" font-weight="bold" font-size="14.00">HERO</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="681.5,-443 681.5,-464 1057.5,-464 1057.5,-443 681.5,-443"/>
<text text-anchor="start" x="777.5" y="-450.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="845.5" y="-450.8" font-family="monospace" font-weight="bold" font-size="14.00">CGHeroInstance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="681.5,-390 681.5,-441 1057.5,-441 1057.5,-390 681.5,-390"/>
<text text-anchor="start" x="684.5" y="-426.8" font-family="Noto Serif" font-size="14.00">Represents a hero, either owned by player or in prison.</text>
<text text-anchor="start" x="722" y="-411.8" font-family="Noto Serif" font-size="14.00">Bonuses from specialty and secondary skills</text>
<text text-anchor="start" x="758" y="-396.8" font-family="Noto Serif" font-size="14.00">are attached directly to this node</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="678.5,-387 678.5,-513 1060.5,-513 1060.5,-387 678.5,-387"/>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="1435.5,-574 966.5,-574 966.5,-410 1435.5,-410 1435.5,-574"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="970,-550 970,-571 1433,-571 1433,-550 970,-550"/>
<text text-anchor="start" x="1183.5" y="-557.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="970,-527 970,-548 1433,-548 1433,-527 970,-527"/>
<text text-anchor="start" x="1142.5" y="-534.8" font-family="Noto Serif" font-size="14.00">Propagator: </text>
<text text-anchor="start" x="1226.5" y="-534.8" font-family="monospace" font-weight="bold" font-size="14.00">HERO</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="970,-504 970,-525 1433,-525 1433,-504 970,-504"/>
<text text-anchor="start" x="1109.5" y="-511.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1177.5" y="-511.8" font-family="monospace" font-weight="bold" font-size="14.00">CGHeroInstance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="970,-451 970,-502 1433,-502 1433,-451 970,-451"/>
<text text-anchor="start" x="1016.5" y="-487.8" font-family="Noto Serif" font-size="14.00">Represents a hero, either owned by player or in prison.</text>
<text text-anchor="start" x="1054" y="-472.8" font-family="Noto Serif" font-size="14.00">Bonuses from specialty and secondary skills</text>
<text text-anchor="start" x="1090" y="-457.8" font-family="Noto Serif" font-size="14.00">are attached directly to this node</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="970,-413 970,-449 1433,-449 1433,-413 970,-413"/>
<text text-anchor="start" x="1023.5" y="-434.8" font-family="Noto Serif" font-size="14.00">Contains per&#45;hero global bonuses, specialty bonuses, </text>
<text text-anchor="start" x="973" y="-419.8" font-family="Noto Serif" font-size="14.00">primary and secondary skill bonuses, campaign primary skill bonus</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="966.5,-410 966.5,-574 1435.5,-574 1435.5,-410 966.5,-410"/>
</g>
<!-- Army -->
<g id="node18" class="node">
<g id="node19" class="node">
<title>Army</title>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1071,-351 668,-351 668,-263 1071,-263 1071,-351"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="671.5,-327 671.5,-348 1068.5,-348 1068.5,-327 671.5,-327"/>
<text text-anchor="start" x="850" y="-334.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Army</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="671.5,-304 671.5,-325 1068.5,-325 1068.5,-304 671.5,-304"/>
<text text-anchor="start" x="778" y="-311.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="846" y="-311.8" font-family="monospace" font-weight="bold" font-size="14.00">CArmedInstance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="671.5,-266 671.5,-302 1068.5,-302 1068.5,-266 671.5,-266"/>
<text text-anchor="start" x="729" y="-287.8" font-family="Noto Serif" font-size="14.00">Represents any object that can hold army,</text>
<text text-anchor="start" x="674.5" y="-272.8" font-family="Noto Serif" font-size="14.00">such as town, hero, mines, garrisons, wandering monsters</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="668,-263 668,-351 1071,-351 1071,-263 668,-263"/>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1052,-374 604,-374 604,-263 1052,-263 1052,-374"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="607,-349.5 607,-370.5 1049,-370.5 1049,-349.5 607,-349.5"/>
<text text-anchor="start" x="808" y="-357.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Army</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="607,-326.5 607,-347.5 1049,-347.5 1049,-326.5 607,-326.5"/>
<text text-anchor="start" x="736" y="-334.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="804" y="-334.3" font-family="monospace" font-weight="bold" font-size="14.00">CArmedInstance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="607,-288.5 607,-324.5 1049,-324.5 1049,-288.5 607,-288.5"/>
<text text-anchor="start" x="687" y="-310.3" font-family="Noto Serif" font-size="14.00">Represents any object that can hold army,</text>
<text text-anchor="start" x="632.5" y="-295.3" font-family="Noto Serif" font-size="14.00">such as town, hero, mines, garrisons, wandering monsters</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="607,-265.5 607,-286.5 1049,-286.5 1049,-265.5 607,-265.5"/>
<text text-anchor="start" x="610" y="-272.3" font-family="Noto Serif" font-size="14.00">Contain anti&#45;magic garrison bonus, faction mixing morale bonus</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="604,-263 604,-374 1052,-374 1052,-263 604,-263"/>
</g>
<!-- Hero&#45;&gt;Army -->
<g id="edge26" class="edge">
<g id="edge30" class="edge">
<title>Hero&#45;&gt;Army</title>
<path fill="none" stroke="black" d="M869.5,-386.74C869.5,-378.34 869.5,-369.78 869.5,-361.55"/>
<polygon fill="black" stroke="black" points="873,-361.33 869.5,-351.33 866,-361.33 873,-361.33"/>
<path fill="none" stroke="black" d="M1024.6,-409.9C1001.41,-399.23 978.02,-388.47 955.85,-378.28"/>
<polygon fill="black" stroke="black" points="957.31,-375.1 946.76,-374.1 954.38,-381.46 957.31,-375.1"/>
</g>
<!-- Combat -->
<g id="node5" class="node">
<title>Combat</title>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="660.5,-505.5 210.5,-505.5 210.5,-394.5 660.5,-394.5 660.5,-505.5"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="213.5,-481 213.5,-502 657.5,-502 657.5,-481 213.5,-481"/>
<text text-anchor="start" x="408" y="-488.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Combat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="213.5,-458 213.5,-479 657.5,-479 657.5,-458 213.5,-458"/>
<text text-anchor="start" x="348" y="-465.8" font-family="Noto Serif" font-size="14.00">Propagator: </text>
<text text-anchor="start" x="432" y="-465.8" font-family="monospace" font-weight="bold" font-size="14.00">BATTLE_WIDE</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="213.5,-435 213.5,-456 657.5,-456 657.5,-435 213.5,-435"/>
<text text-anchor="start" x="360" y="-442.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="428" y="-442.8" font-family="monospace" font-weight="bold" font-size="14.00">BattleInfo</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="213.5,-397 213.5,-433 657.5,-433 657.5,-397 213.5,-397"/>
<text text-anchor="start" x="295" y="-418.8" font-family="Noto Serif" font-size="14.00">Node that contains both sides of a combat</text>
<text text-anchor="start" x="216.5" y="-403.8" font-family="Noto Serif" font-size="14.00">Anything propagated to this node will affect both sides in combat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="210.5,-394.5 210.5,-505.5 660.5,-505.5 660.5,-394.5 210.5,-394.5"/>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="800,-559 350,-559 350,-425 800,-425 800,-559"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="353,-535 353,-556 797,-556 797,-535 353,-535"/>
<text text-anchor="start" x="547.5" y="-542.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Combat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="353,-512 353,-533 797,-533 797,-512 353,-512"/>
<text text-anchor="start" x="487.5" y="-519.8" font-family="Noto Serif" font-size="14.00">Propagator: </text>
<text text-anchor="start" x="571.5" y="-519.8" font-family="monospace" font-weight="bold" font-size="14.00">BATTLE_WIDE</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="353,-489 353,-510 797,-510 797,-489 353,-489"/>
<text text-anchor="start" x="499.5" y="-496.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="567.5" y="-496.8" font-family="monospace" font-weight="bold" font-size="14.00">BattleInfo</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="353,-451 353,-487 797,-487 797,-451 353,-451"/>
<text text-anchor="start" x="434.5" y="-472.8" font-family="Noto Serif" font-size="14.00">Node that contains both sides of a combat</text>
<text text-anchor="start" x="356" y="-457.8" font-family="Noto Serif" font-size="14.00">Anything propagated to this node will affect both sides in combat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="353,-428 353,-449 797,-449 797,-428 353,-428"/>
<text text-anchor="start" x="417" y="-434.8" font-family="Noto Serif" font-size="14.00">Contains battlefield and native terrain bonuses</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="350,-425 350,-559 800,-559 800,-425 350,-425"/>
</g>
<!-- Combat&#45;&gt;Army -->
<g id="edge10" class="edge">
<g id="edge11" class="edge">
<title>Combat&#45;&gt;Army</title>
<path fill="none" stroke="black" d="M603.3,-394.49C644.28,-381.17 687.74,-367.05 727.4,-354.17"/>
<polygon fill="black" stroke="black" points="728.7,-357.42 737.13,-351.01 726.53,-350.77 728.7,-357.42"/>
<path fill="none" stroke="black" d="M672.45,-424.94C694.33,-410.11 717.43,-394.45 738.94,-379.87"/>
<polygon fill="black" stroke="black" points="741.1,-382.63 747.42,-374.13 737.17,-376.84 741.1,-382.63"/>
</g>
<!-- Visiting Hero -->
<g id="node6" class="node">
<title>Visiting Hero</title>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="1012,-614 803,-614 803,-549 1012,-549 1012,-614"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="806.5,-589.5 806.5,-610.5 1009.5,-610.5 1009.5,-589.5 806.5,-589.5"/>
<text text-anchor="start" x="861" y="-597.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Visiting Hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="806.5,-551.5 806.5,-587.5 1009.5,-587.5 1009.5,-551.5 806.5,-551.5"/>
<text text-anchor="start" x="834" y="-573.3" font-family="Noto Serif" font-size="14.00">Hero that is currently</text>
<text text-anchor="start" x="809.5" y="-558.3" font-family="Noto Serif" font-size="14.00">visiting owned or allied town</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="803,-549 803,-614 1012,-614 1012,-549 803,-549"/>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="1371.5,-679 1162.5,-679 1162.5,-614 1371.5,-614 1371.5,-679"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1166,-654.5 1166,-675.5 1369,-675.5 1369,-654.5 1166,-654.5"/>
<text text-anchor="start" x="1220.5" y="-662.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Visiting Hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1166,-616.5 1166,-652.5 1369,-652.5 1369,-616.5 1166,-616.5"/>
<text text-anchor="start" x="1193.5" y="-638.3" font-family="Noto Serif" font-size="14.00">Hero that is currently</text>
<text text-anchor="start" x="1169" y="-623.3" font-family="Noto Serif" font-size="14.00">visiting owned or allied town</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1162.5,-614 1162.5,-679 1371.5,-679 1371.5,-614 1162.5,-614"/>
</g>
<!-- Visiting Hero&#45;&gt;Hero -->
<g id="edge23" class="edge">
<g id="edge27" class="edge">
<title>Visiting Hero&#45;&gt;Hero</title>
<path fill="none" stroke="black" d="M898.2,-548.82C895.88,-540.9 893.29,-532.08 890.65,-523.07"/>
<polygon fill="black" stroke="black" points="893.94,-521.86 887.77,-513.25 887.22,-523.83 893.94,-521.86"/>
<path fill="none" stroke="black" d="M1253.32,-613.9C1249.37,-604.77 1244.85,-594.32 1240.15,-583.46"/>
<polygon fill="black" stroke="black" points="1243.36,-582.06 1236.18,-574.28 1236.94,-584.84 1243.36,-582.06"/>
</g>
<!-- Garrisoned Hero -->
<g id="node7" class="node">
<title>Garrisoned Hero</title>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="1280.5,-614 1030.5,-614 1030.5,-549 1280.5,-549 1280.5,-614"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1033.5,-589.5 1033.5,-610.5 1277.5,-610.5 1277.5,-589.5 1033.5,-589.5"/>
<text text-anchor="start" x="1095.5" y="-597.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Garrisoned Hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1033.5,-551.5 1033.5,-587.5 1277.5,-587.5 1277.5,-551.5 1033.5,-551.5"/>
<text text-anchor="start" x="1081.5" y="-573.3" font-family="Noto Serif" font-size="14.00">Hero that is currently</text>
<text text-anchor="start" x="1036.5" y="-558.3" font-family="Noto Serif" font-size="14.00">placed in a garrison of owned town</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1030.5,-549 1030.5,-614 1280.5,-614 1280.5,-549 1030.5,-549"/>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="1106,-679 856,-679 856,-614 1106,-614 1106,-679"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="859,-654.5 859,-675.5 1103,-675.5 1103,-654.5 859,-654.5"/>
<text text-anchor="start" x="921" y="-662.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Garrisoned Hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="859,-616.5 859,-652.5 1103,-652.5 1103,-616.5 859,-616.5"/>
<text text-anchor="start" x="907" y="-638.3" font-family="Noto Serif" font-size="14.00">Hero that is currently</text>
<text text-anchor="start" x="862" y="-623.3" font-family="Noto Serif" font-size="14.00">placed in a garrison of owned town</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="856,-614 856,-679 1106,-679 1106,-614 856,-614"/>
</g>
<!-- Garrisoned Hero&#45;&gt;Hero -->
<g id="edge24" class="edge">
<g id="edge28" class="edge">
<title>Garrisoned Hero&#45;&gt;Hero</title>
<path fill="none" stroke="black" d="M1085.9,-548.99C1064.64,-539.36 1040.41,-528.39 1016.05,-517.36"/>
<polygon fill="black" stroke="black" points="1017.26,-514.06 1006.71,-513.13 1014.37,-520.44 1017.26,-514.06"/>
<path fill="none" stroke="black" d="M1026.58,-613.9C1041.08,-603.86 1057.87,-592.21 1075.21,-580.2"/>
<polygon fill="black" stroke="black" points="1077.52,-582.85 1083.75,-574.28 1073.54,-577.1 1077.52,-582.85"/>
</g>
<!-- Wandering Hero&#45;&gt;Hero -->
<g id="edge25" class="edge">
<g id="edge29" class="edge">
<title>Wandering Hero&#45;&gt;Hero</title>
<path fill="none" stroke="black" d="M715.9,-548.99C730.39,-539.74 746.83,-529.26 763.42,-518.67"/>
<polygon fill="black" stroke="black" points="765.56,-521.46 772.11,-513.13 761.8,-515.56 765.56,-521.46"/>
<path fill="none" stroke="black" d="M1474.52,-613.9C1450.56,-603.31 1422.6,-590.95 1393.87,-578.25"/>
<polygon fill="black" stroke="black" points="1395.08,-574.96 1384.51,-574.12 1392.25,-581.36 1395.08,-574.96"/>
</g>
<!-- Neutral Army&#45;&gt;Army -->
<g id="edge21" class="edge">
<g id="edge25" class="edge">
<title>Neutral Army&#45;&gt;Army</title>
<path fill="none" stroke="black" d="M1461.15,-548.93C1437.84,-504.7 1389.07,-425.4 1322.5,-387 1231.06,-334.27 1190.02,-367.76 1081.09,-350.98"/>
<polygon fill="black" stroke="black" points="1081.48,-347.49 1071.04,-349.32 1080.34,-354.4 1081.48,-347.49"/>
<path fill="none" stroke="black" d="M1784.91,-613.89C1720.6,-561.13 1582.08,-456.33 1445,-410 1285.7,-356.16 1232.22,-399.85 1062.07,-374.08"/>
<polygon fill="black" stroke="black" points="1062.45,-370.6 1052.03,-372.5 1061.36,-377.51 1062.45,-370.6"/>
</g>
<!-- Owned Army&#45;&gt;Army -->
<g id="edge22" class="edge">
<g id="edge26" class="edge">
<title>Owned Army&#45;&gt;Army</title>
<path fill="none" stroke="black" d="M106.42,-548.96C117.92,-504.75 145.46,-425.48 201.5,-387 273.67,-337.44 490.45,-318.84 657.69,-311.93"/>
<polygon fill="black" stroke="black" points="658.02,-315.42 667.87,-311.52 657.74,-308.42 658.02,-315.42"/>
<path fill="none" stroke="black" d="M380.63,-613.89C364.79,-603.59 350.14,-590.44 341,-574 305.59,-510.29 294.41,-466.05 341,-410 374.42,-369.8 485.94,-347.37 593.84,-334.9"/>
<polygon fill="black" stroke="black" points="594.38,-338.36 603.93,-333.76 593.6,-331.41 594.38,-338.36"/>
</g>
<!-- Town -->
<g id="node11" class="node">
<g id="node12" class="node">
<title>Town</title>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="1388,-753 1049,-753 1049,-650 1388,-650 1388,-753"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1052.5,-728.5 1052.5,-749.5 1385.5,-749.5 1385.5,-728.5 1052.5,-728.5"/>
<text text-anchor="start" x="1199.5" y="-736.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Town</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1052.5,-705.5 1052.5,-726.5 1385.5,-726.5 1385.5,-705.5 1052.5,-705.5"/>
<text text-anchor="start" x="1127" y="-713.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1195" y="-713.3" font-family="monospace" font-weight="bold" font-size="14.00">CGTownInstance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1052.5,-652.5 1052.5,-703.5 1385.5,-703.5 1385.5,-652.5 1052.5,-652.5"/>
<text text-anchor="start" x="1128" y="-689.3" font-family="Noto Serif" font-size="14.00">Represents a town on map.</text>
<text text-anchor="start" x="1055.5" y="-674.3" font-family="Noto Serif" font-size="14.00">Town buildings can provide bonuses to this node</text>
<text text-anchor="start" x="1123" y="-659.3" font-family="Noto Serif" font-size="14.00">(or propagate them upward)</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1049,-650 1049,-753 1388,-753 1388,-650 1049,-650"/>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="925,-822.5 699,-822.5 699,-726.5 925,-726.5 925,-822.5"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="702,-798.5 702,-819.5 922,-819.5 922,-798.5 702,-798.5"/>
<text text-anchor="start" x="792.5" y="-806.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Town</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="702,-775.5 702,-796.5 922,-796.5 922,-775.5 702,-775.5"/>
<text text-anchor="start" x="720" y="-783.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="788" y="-783.3" font-family="monospace" font-weight="bold" font-size="14.00">CGTownInstance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="702,-752.5 702,-773.5 922,-773.5 922,-752.5 702,-752.5"/>
<text text-anchor="start" x="721" y="-759.3" font-family="Noto Serif" font-size="14.00">Represents a town on map.</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="702,-729.5 702,-750.5 922,-750.5 922,-729.5 702,-729.5"/>
<text text-anchor="start" x="705" y="-736.3" font-family="Noto Serif" font-size="14.00">Contains town building bonuses</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="699,-726.5 699,-822.5 925,-822.5 925,-726.5 699,-726.5"/>
</g>
<!-- Town&#45;&gt;Garrisoned Hero -->
<g id="edge19" class="edge">
<g id="edge23" class="edge">
<title>Town&#45;&gt;Garrisoned Hero</title>
<path fill="none" stroke="black" d="M1191.42,-649.77C1186.67,-640.87 1181.78,-631.72 1177.2,-623.14"/>
<polygon fill="black" stroke="black" points="1180.16,-621.27 1172.37,-614.09 1173.99,-624.56 1180.16,-621.27"/>
<path fill="none" stroke="black" d="M875.41,-726.22C893.52,-712.72 913.01,-698.19 930.26,-685.33"/>
<polygon fill="black" stroke="black" points="932.6,-687.95 938.53,-679.17 928.42,-682.34 932.6,-687.95"/>
</g>
<!-- Town&#45;&gt;Army -->
<g id="edge20" class="edge">
<g id="edge24" class="edge">
<title>Town&#45;&gt;Army</title>
<path fill="none" stroke="black" d="M1269.58,-649.67C1277.74,-638.72 1284.98,-626.62 1289.5,-614 1299.23,-586.8 1302.53,-574.78 1289.5,-549 1240.14,-451.35 1132.4,-390.7 1038.41,-354.66"/>
<polygon fill="black" stroke="black" points="1039.37,-351.29 1028.78,-351.04 1036.9,-357.84 1039.37,-351.29"/>
<path fill="none" stroke="black" d="M813.67,-726.2C816.55,-644.44 822.46,-476.58 825.72,-384.13"/>
<polygon fill="black" stroke="black" points="829.22,-384.18 826.08,-374.06 822.23,-383.93 829.22,-384.18"/>
</g>
<!-- Artifact Instance -->
<g id="node12" class="node">
<g id="node13" class="node">
<title>Artifact Instance</title>
<polygon fill="#00ffff" fill-opacity="0.501961" stroke="transparent" points="884.5,-745.5 562.5,-745.5 562.5,-657.5 884.5,-657.5 884.5,-745.5"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="565.5,-721.5 565.5,-742.5 881.5,-742.5 881.5,-721.5 565.5,-721.5"/>
<text text-anchor="start" x="663" y="-729.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Artifact Instance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="565.5,-698.5 565.5,-719.5 881.5,-719.5 881.5,-698.5 565.5,-698.5"/>
<text text-anchor="start" x="652" y="-706.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="720" y="-706.3" font-family="monospace" font-weight="bold" font-size="14.00">CArtifact</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="565.5,-660.5 565.5,-696.5 881.5,-696.5 881.5,-660.5 565.5,-660.5"/>
<text text-anchor="start" x="568.5" y="-682.3" font-family="Noto Serif" font-size="14.00">Represents a particular instance of an artifact</text>
<text text-anchor="start" x="626.5" y="-667.3" font-family="Noto Serif" font-size="14.00"> that hero can equip or trade</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="562.5,-657.5 562.5,-745.5 884.5,-745.5 884.5,-657.5 562.5,-657.5"/>
<polygon fill="#00ffff" fill-opacity="0.501961" stroke="transparent" points="1687,-830 1311,-830 1311,-719 1687,-719 1687,-830"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1314,-805.5 1314,-826.5 1684,-826.5 1684,-805.5 1314,-805.5"/>
<text text-anchor="start" x="1438.5" y="-813.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Artifact Instance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1314,-782.5 1314,-803.5 1684,-803.5 1684,-782.5 1314,-782.5"/>
<text text-anchor="start" x="1394.5" y="-790.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1462.5" y="-790.3" font-family="monospace" font-weight="bold" font-size="14.00">CArtifactInstance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1314,-744.5 1314,-780.5 1684,-780.5 1684,-744.5 1314,-744.5"/>
<text text-anchor="start" x="1344" y="-766.3" font-family="Noto Serif" font-size="14.00">Represents a particular instance of an artifact</text>
<text text-anchor="start" x="1402" y="-751.3" font-family="Noto Serif" font-size="14.00"> that hero can equip or trade</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1314,-721.5 1314,-742.5 1684,-742.5 1684,-721.5 1314,-721.5"/>
<text text-anchor="start" x="1317" y="-728.3" font-family="Noto Serif" font-size="14.00">Contains bonuses of spell scrolls and growing artifacts</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1311,-719 1311,-830 1687,-830 1687,-719 1311,-719"/>
</g>
<!-- Artifact Instance&#45;&gt;Hero -->
<g id="edge16" class="edge">
<g id="edge19" class="edge">
<title>Artifact Instance&#45;&gt;Hero</title>
<path fill="none" stroke="black" d="M585.05,-657.47C566.99,-646.13 550.85,-631.88 539.5,-614 524.02,-589.61 522.01,-571.99 539.5,-549 573.95,-503.71 608.3,-527.17 668.56,-512.98"/>
<polygon fill="black" stroke="black" points="669.69,-516.3 678.46,-510.36 667.9,-509.53 669.69,-516.3"/>
<path fill="none" stroke="black" d="M1446.84,-718.76C1437.06,-707.35 1427.31,-695.1 1419,-683 1398.29,-652.85 1405.59,-637.08 1381,-610 1371.53,-599.57 1360.94,-589.68 1349.76,-580.38"/>
<polygon fill="black" stroke="black" points="1351.91,-577.62 1341.93,-574.04 1347.5,-583.06 1351.91,-577.62"/>
</g>
<!-- Boat -->
<g id="node13" class="node">
<g id="node14" class="node">
<title>Boat</title>
<polygon fill="#00ffff" fill-opacity="0.501961" stroke="transparent" points="544,-745.5 233,-745.5 233,-657.5 544,-657.5 544,-745.5"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="236.5,-721.5 236.5,-742.5 541.5,-742.5 541.5,-721.5 236.5,-721.5"/>
<text text-anchor="start" x="372.5" y="-729.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Boat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="236.5,-698.5 236.5,-719.5 541.5,-719.5 541.5,-698.5 236.5,-698.5"/>
<text text-anchor="start" x="330" y="-706.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="398" y="-706.3" font-family="monospace" font-weight="bold" font-size="14.00">CGBoat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="236.5,-660.5 236.5,-696.5 541.5,-696.5 541.5,-660.5 236.5,-660.5"/>
<text text-anchor="start" x="239.5" y="-682.3" font-family="Noto Serif" font-size="14.00">Represents a boat or other type of transport.</text>
<text text-anchor="start" x="263.5" y="-667.3" font-family="Noto Serif" font-size="14.00">Can provide bonuses to boarded hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="233,-657.5 233,-745.5 544,-745.5 544,-657.5 233,-657.5"/>
<polygon fill="#00ffff" fill-opacity="0.501961" stroke="transparent" points="1254.5,-822.5 943.5,-822.5 943.5,-726.5 1254.5,-726.5 1254.5,-822.5"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="947,-798.5 947,-819.5 1252,-819.5 1252,-798.5 947,-798.5"/>
<text text-anchor="start" x="1083" y="-806.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Boat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="947,-775.5 947,-796.5 1252,-796.5 1252,-775.5 947,-775.5"/>
<text text-anchor="start" x="1040.5" y="-783.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1108.5" y="-783.3" font-family="monospace" font-weight="bold" font-size="14.00">CGBoat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="947,-752.5 947,-773.5 1252,-773.5 1252,-752.5 947,-752.5"/>
<text text-anchor="start" x="950" y="-759.3" font-family="Noto Serif" font-size="14.00">Represents a boat or other type of transport.</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="947,-729.5 947,-750.5 1252,-750.5 1252,-729.5 947,-729.5"/>
<text text-anchor="start" x="953.5" y="-736.3" font-family="Noto Serif" font-size="14.00">Contains bonuses provided to boarded hero</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="943.5,-726.5 943.5,-822.5 1254.5,-822.5 1254.5,-726.5 943.5,-726.5"/>
</g>
<!-- Boat&#45;&gt;Hero -->
<g id="edge9" class="edge">
<g id="edge10" class="edge">
<title>Boat&#45;&gt;Hero</title>
<path fill="none" stroke="black" d="M415.69,-657.4C439.67,-622.94 477.72,-576.05 522.5,-549 577.38,-515.85 602.3,-529.51 668.43,-513.13"/>
<polygon fill="black" stroke="black" points="669.71,-516.41 678.5,-510.49 667.94,-509.64 669.71,-516.41"/>
<path fill="none" stroke="black" d="M1114.06,-726.38C1124.73,-693.58 1139.65,-648.92 1154,-610 1157.14,-601.48 1160.5,-592.65 1163.92,-583.83"/>
<polygon fill="black" stroke="black" points="1167.27,-584.86 1167.65,-574.28 1160.75,-582.32 1167.27,-584.86"/>
</g>
<!-- Town and visiting hero&#45;&gt;Visiting Hero -->
<g id="edge8" class="edge">
<g id="edge9" class="edge">
<title>Town and visiting hero&#45;&gt;Visiting Hero</title>
<path fill="none" stroke="black" d="M1079.27,-788.81C1065.1,-778.07 1051.74,-766.11 1040.5,-753 1008.09,-715.22 1027.13,-689.24 996.5,-650 988.05,-639.18 977.46,-629.17 966.57,-620.37"/>
<polygon fill="black" stroke="black" points="968.65,-617.55 958.61,-614.18 964.36,-623.08 968.65,-617.55"/>
<path fill="none" stroke="black" d="M871.69,-868C874.81,-867.31 877.92,-866.64 881,-866 964.71,-848.68 1205.93,-892.74 1264,-830 1298.6,-792.62 1290.93,-730.23 1280.43,-688.97"/>
<polygon fill="black" stroke="black" points="1283.79,-687.96 1277.8,-679.22 1277.03,-689.79 1283.79,-687.96"/>
</g>
<!-- Town and visiting hero&#45;&gt;Town -->
<g id="edge7" class="edge">
<g id="edge8" class="edge">
<title>Town and visiting hero&#45;&gt;Town</title>
<path fill="none" stroke="black" d="M1210.56,-789C1211.34,-780.53 1212.13,-771.89 1212.9,-763.5"/>
<polygon fill="black" stroke="black" points="1216.4,-763.71 1213.82,-753.43 1209.42,-763.07 1216.4,-763.71"/>
<path fill="none" stroke="black" d="M734.83,-865.63C744.91,-853.85 755.31,-841.71 765.08,-830.29"/>
<polygon fill="black" stroke="black" points="767.89,-832.4 771.74,-822.52 762.57,-827.84 767.89,-832.4"/>
</g>
<!-- Creature Type -->
<g id="node15" class="node">
<g id="node16" class="node">
<title>Creature Type</title>
<polygon fill="#00ffff" fill-opacity="0.501961" stroke="transparent" points="1469.5,-343.5 1089.5,-343.5 1089.5,-270.5 1469.5,-270.5 1469.5,-343.5"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1092.5,-319 1092.5,-340 1466.5,-340 1466.5,-319 1092.5,-319"/>
<text text-anchor="start" x="1228" y="-326.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Creature Type</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1092.5,-296 1092.5,-317 1466.5,-317 1466.5,-296 1092.5,-296"/>
<text text-anchor="start" x="1208" y="-303.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1276" y="-303.8" font-family="monospace" font-weight="bold" font-size="14.00">CCreature</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1092.5,-273 1092.5,-294 1466.5,-294 1466.5,-273 1092.5,-273"/>
<text text-anchor="start" x="1095.5" y="-279.8" font-family="Noto Serif" font-size="14.00">Represents a creature type, such as Pikeman or Archer</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1089.5,-270.5 1089.5,-343.5 1469.5,-343.5 1469.5,-270.5 1089.5,-270.5"/>
<polygon fill="#00ffff" fill-opacity="0.501961" stroke="transparent" points="1494,-366.5 1070,-366.5 1070,-270.5 1494,-270.5 1494,-366.5"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1073,-342.5 1073,-363.5 1491,-363.5 1491,-342.5 1073,-342.5"/>
<text text-anchor="start" x="1230.5" y="-350.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Creature Type</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1073,-319.5 1073,-340.5 1491,-340.5 1491,-319.5 1073,-319.5"/>
<text text-anchor="start" x="1210.5" y="-327.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1278.5" y="-327.3" font-family="monospace" font-weight="bold" font-size="14.00">CCreature</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1073,-296.5 1073,-317.5 1491,-317.5 1491,-296.5 1073,-296.5"/>
<text text-anchor="start" x="1098" y="-303.3" font-family="Noto Serif" font-size="14.00">Represents a creature type, such as Pikeman or Archer</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1073,-273.5 1073,-294.5 1491,-294.5 1491,-273.5 1073,-273.5"/>
<text text-anchor="start" x="1076" y="-280.3" font-family="Noto Serif" font-size="14.00">Contains creature abilities bonuses, stack experience bonuses</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1070,-270.5 1070,-366.5 1494,-366.5 1494,-270.5 1070,-270.5"/>
</g>
<!-- Unit in Army -->
<g id="node19" class="node">
<g id="node20" class="node">
<title>Unit in Army</title>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1394.5,-227 1118.5,-227 1118.5,-124 1394.5,-124 1394.5,-227"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1121.5,-202.5 1121.5,-223.5 1391.5,-223.5 1391.5,-202.5 1121.5,-202.5"/>
<text text-anchor="start" x="1210" y="-210.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Unit in Army</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1121.5,-179.5 1121.5,-200.5 1391.5,-200.5 1391.5,-179.5 1121.5,-179.5"/>
<text text-anchor="start" x="1164.5" y="-187.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1232.5" y="-187.3" font-family="monospace" font-weight="bold" font-size="14.00">CStackInstance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1121.5,-126.5 1121.5,-177.5 1391.5,-177.5 1391.5,-126.5 1121.5,-126.5"/>
<text text-anchor="start" x="1124.5" y="-163.3" font-family="Noto Serif" font-size="14.00">Represents a unit that is part of a army</text>
<text text-anchor="start" x="1142" y="-148.3" font-family="Noto Serif" font-size="14.00">A unit always has a creature type,</text>
<text text-anchor="start" x="1130" y="-133.3" font-family="Noto Serif" font-size="14.00">belongs to an army and has stack size</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1118.5,-124 1118.5,-227 1394.5,-227 1394.5,-124 1118.5,-124"/>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1198,-227 922,-227 922,-124 1198,-124 1198,-227"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="925,-202.5 925,-223.5 1195,-223.5 1195,-202.5 925,-202.5"/>
<text text-anchor="start" x="1013.5" y="-210.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Unit in Army</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="925,-179.5 925,-200.5 1195,-200.5 1195,-179.5 925,-179.5"/>
<text text-anchor="start" x="968" y="-187.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1036" y="-187.3" font-family="monospace" font-weight="bold" font-size="14.00">CStackInstance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="925,-126.5 925,-177.5 1195,-177.5 1195,-126.5 925,-126.5"/>
<text text-anchor="start" x="928" y="-163.3" font-family="Noto Serif" font-size="14.00">Represents a unit that is part of a army</text>
<text text-anchor="start" x="945.5" y="-148.3" font-family="Noto Serif" font-size="14.00">A unit always has a creature type,</text>
<text text-anchor="start" x="933.5" y="-133.3" font-family="Noto Serif" font-size="14.00">belongs to an army and has stack size</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="922,-124 922,-227 1198,-227 1198,-124 922,-124"/>
</g>
<!-- Creature Type&#45;&gt;Unit in Army -->
<g id="edge18" class="edge">
<g id="edge22" class="edge">
<title>Creature Type&#45;&gt;Unit in Army</title>
<path fill="none" stroke="black" d="M1273.15,-270.27C1271.32,-259.96 1269.27,-248.42 1267.25,-237.05"/>
<polygon fill="black" stroke="black" points="1270.69,-236.37 1265.49,-227.14 1263.8,-237.6 1270.69,-236.37"/>
<path fill="none" stroke="black" d="M1207.77,-270.35C1188.77,-258.29 1168.16,-245.2 1148.52,-232.72"/>
<polygon fill="black" stroke="black" points="1150.2,-229.64 1139.88,-227.23 1146.44,-235.55 1150.2,-229.64"/>
</g>
<!-- Commander -->
<g id="node21" class="node">
<title>Commander</title>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1524,-212 1216,-212 1216,-139 1524,-139 1524,-212"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1219,-187.5 1219,-208.5 1521,-208.5 1521,-187.5 1219,-187.5"/>
<text text-anchor="start" x="1326.5" y="-195.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Commander</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1219,-164.5 1219,-185.5 1521,-185.5 1521,-164.5 1219,-164.5"/>
<text text-anchor="start" x="1261.5" y="-172.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1329.5" y="-172.3" font-family="monospace" font-weight="bold" font-size="14.00">CCommanderInstance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1219,-141.5 1219,-162.5 1521,-162.5 1521,-141.5 1219,-141.5"/>
<text text-anchor="start" x="1222" y="-148.3" font-family="Noto Serif" font-size="14.00">Represents a hero commander, WoG feature</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1216,-139 1216,-212 1524,-212 1524,-139 1216,-139"/>
</g>
<!-- Creature Type&#45;&gt;Commander -->
<g id="edge20" class="edge">
<title>Creature Type&#45;&gt;Commander</title>
<path fill="none" stroke="black" d="M1311.55,-270.16C1321.49,-254.23 1332.54,-236.52 1342.33,-220.83"/>
<polygon fill="black" stroke="black" points="1345.3,-222.68 1347.63,-212.35 1339.36,-218.98 1345.3,-222.68"/>
</g>
<!-- Summon in Combat -->
<g id="node21" class="node">
<g id="node23" class="node">
<title>Summon in Combat</title>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1078,-219.5 751,-219.5 751,-131.5 1078,-131.5 1078,-219.5"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="754.5,-195.5 754.5,-216.5 1075.5,-216.5 1075.5,-195.5 754.5,-195.5"/>
<text text-anchor="start" x="846" y="-203.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Summon in Combat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="754.5,-172.5 754.5,-193.5 1075.5,-193.5 1075.5,-172.5 754.5,-172.5"/>
<text text-anchor="start" x="856" y="-180.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="924" y="-180.3" font-family="monospace" font-weight="bold" font-size="14.00">CStack</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="754.5,-134.5 754.5,-170.5 1075.5,-170.5 1075.5,-134.5 754.5,-134.5"/>
<text text-anchor="start" x="757.5" y="-156.3" font-family="Noto Serif" font-size="14.00">Represents any unit that was added in combat,</text>
<text text-anchor="start" x="800.5" y="-141.3" font-family="Noto Serif" font-size="14.00">and may not remain after combat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="751,-131.5 751,-219.5 1078,-219.5 1078,-131.5 751,-131.5"/>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="903.5,-219.5 576.5,-219.5 576.5,-131.5 903.5,-131.5 903.5,-219.5"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="580,-195.5 580,-216.5 901,-216.5 901,-195.5 580,-195.5"/>
<text text-anchor="start" x="671.5" y="-203.3" font-family="Noto Serif" font-weight="bold" font-size="14.00">Summon in Combat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="580,-172.5 580,-193.5 901,-193.5 901,-172.5 580,-172.5"/>
<text text-anchor="start" x="681.5" y="-180.3" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="749.5" y="-180.3" font-family="monospace" font-weight="bold" font-size="14.00">CStack</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="580,-134.5 580,-170.5 901,-170.5 901,-134.5 580,-134.5"/>
<text text-anchor="start" x="583" y="-156.3" font-family="Noto Serif" font-size="14.00">Represents any unit that was added in combat,</text>
<text text-anchor="start" x="626" y="-141.3" font-family="Noto Serif" font-size="14.00">and may not remain after combat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="576.5,-131.5 576.5,-219.5 903.5,-219.5 903.5,-131.5 576.5,-131.5"/>
</g>
<!-- Creature Type&#45;&gt;Summon in Combat -->
<g id="edge17" class="edge">
<g id="edge21" class="edge">
<title>Creature Type&#45;&gt;Summon in Combat</title>
<path fill="none" stroke="black" d="M1179.28,-270.44C1137.99,-255.79 1089.59,-238.62 1045.55,-223"/>
<polygon fill="black" stroke="black" points="1046.53,-219.63 1035.93,-219.58 1044.18,-226.23 1046.53,-219.63"/>
<path fill="none" stroke="black" d="M1091.54,-270.49C1081.21,-267.95 1070.98,-265.44 1061,-263 995.25,-246.9 978.4,-244.49 913,-227 907.29,-225.47 901.48,-223.9 895.61,-222.28"/>
<polygon fill="black" stroke="black" points="896.27,-218.83 885.7,-219.54 894.4,-225.58 896.27,-218.83"/>
</g>
<!-- Artifact Type -->
<g id="node16" class="node">
<g id="node17" class="node">
<title>Artifact Type</title>
<polygon fill="#00ffff" fill-opacity="0.501961" stroke="transparent" points="954.5,-892.5 590.5,-892.5 590.5,-819.5 954.5,-819.5 954.5,-892.5"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="593.5,-868 593.5,-889 951.5,-889 951.5,-868 593.5,-868"/>
<text text-anchor="start" x="724.5" y="-875.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Artifact Type</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="593.5,-845 593.5,-866 951.5,-866 951.5,-845 593.5,-845"/>
<text text-anchor="start" x="701" y="-852.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="769" y="-852.8" font-family="monospace" font-weight="bold" font-size="14.00">CArtifact</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="593.5,-822 593.5,-843 951.5,-843 951.5,-822 593.5,-822"/>
<text text-anchor="start" x="596.5" y="-828.8" font-family="Noto Serif" font-size="14.00">Represents an artifact type, for example Ring of Life</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="590.5,-819.5 590.5,-892.5 954.5,-892.5 954.5,-819.5 590.5,-819.5"/>
<polygon fill="#00ffff" fill-opacity="0.501961" stroke="transparent" points="1254,-981 890,-981 890,-885 1254,-885 1254,-981"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="893,-957 893,-978 1251,-978 1251,-957 893,-957"/>
<text text-anchor="start" x="1024" y="-964.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Artifact Type</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="893,-934 893,-955 1251,-955 1251,-934 893,-934"/>
<text text-anchor="start" x="1000.5" y="-941.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1068.5" y="-941.8" font-family="monospace" font-weight="bold" font-size="14.00">CArtifact</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="893,-911 893,-932 1251,-932 1251,-911 893,-911"/>
<text text-anchor="start" x="896" y="-917.8" font-family="Noto Serif" font-size="14.00">Represents an artifact type, for example Ring of Life</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="893,-888 893,-909 1251,-909 1251,-888 893,-888"/>
<text text-anchor="start" x="956.5" y="-894.8" font-family="Noto Serif" font-size="14.00">Contains fixed bonuses of artifacts</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="890,-885 890,-981 1254,-981 1254,-885 890,-885"/>
</g>
<!-- Artifact Type&#45;&gt;Artifact Instance -->
<g id="edge14" class="edge">
<g id="edge17" class="edge">
<title>Artifact Type&#45;&gt;Artifact Instance</title>
<path fill="none" stroke="black" d="M761.01,-819.25C754.91,-800.25 747.28,-776.52 740.51,-755.43"/>
<polygon fill="black" stroke="black" points="743.75,-754.08 737.36,-745.63 737.09,-756.23 743.75,-754.08"/>
<path fill="none" stroke="black" d="M1200.4,-884.94C1244.52,-868.77 1294.43,-850.48 1340.65,-833.54"/>
<polygon fill="black" stroke="black" points="1341.96,-836.79 1350.14,-830.06 1339.55,-830.21 1341.96,-836.79"/>
</g>
<!-- Artifact Component -->
<g id="node17" class="node">
<g id="node18" class="node">
<title>Artifact Component</title>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="572.5,-900 88.5,-900 88.5,-812 572.5,-812 572.5,-900"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="91.5,-876 91.5,-897 569.5,-897 569.5,-876 91.5,-876"/>
<text text-anchor="start" x="259.5" y="-883.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Artifact Component</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="91.5,-853 91.5,-874 569.5,-874 569.5,-853 91.5,-853"/>
<text text-anchor="start" x="259" y="-860.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="327" y="-860.8" font-family="monospace" font-weight="bold" font-size="14.00">CArtifact</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="91.5,-815 91.5,-851 569.5,-851 569.5,-815 91.5,-815"/>
<text text-anchor="start" x="215" y="-836.8" font-family="Noto Serif" font-size="14.00">For combined, non&#45;fused artifacts,</text>
<text text-anchor="start" x="94.5" y="-821.8" font-family="Noto Serif" font-size="14.00">instances of components are attached to instance of combined artifact</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="88.5,-812 88.5,-900 572.5,-900 572.5,-812 88.5,-812"/>
<polygon fill="#808080" fill-opacity="0.501961" stroke="transparent" points="1756,-977 1272,-977 1272,-889 1756,-889 1756,-977"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1275,-953 1275,-974 1753,-974 1753,-953 1275,-953"/>
<text text-anchor="start" x="1443" y="-960.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Artifact Component</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1275,-930 1275,-951 1753,-951 1753,-930 1275,-930"/>
<text text-anchor="start" x="1409.5" y="-937.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1477.5" y="-937.8" font-family="monospace" font-weight="bold" font-size="14.00">CArtifactInstance</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1275,-892 1275,-928 1753,-928 1753,-892 1275,-892"/>
<text text-anchor="start" x="1398.5" y="-913.8" font-family="Noto Serif" font-size="14.00">For combined, non&#45;fused artifacts,</text>
<text text-anchor="start" x="1278" y="-898.8" font-family="Noto Serif" font-size="14.00">instances of components are attached to instance of combined artifact</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1272,-889 1272,-977 1756,-977 1756,-889 1272,-889"/>
</g>
<!-- Artifact Component&#45;&gt;Artifact Instance -->
<g id="edge15" class="edge">
<g id="edge18" class="edge">
<title>Artifact Component&#45;&gt;Artifact Instance</title>
<path fill="none" stroke="black" d="M441.54,-811.91C491.86,-792.38 551.47,-769.25 602.89,-749.3"/>
<polygon fill="black" stroke="black" points="604.34,-752.5 612.39,-745.61 601.8,-745.97 604.34,-752.5"/>
<path fill="none" stroke="black" d="M1509.86,-888.82C1508.42,-873.76 1506.77,-856.52 1505.19,-840.1"/>
<polygon fill="black" stroke="black" points="1508.66,-839.63 1504.22,-830.01 1501.69,-840.3 1508.66,-839.63"/>
</g>
<!-- Army&#45;&gt;Unit in Army -->
<g id="edge11" class="edge">
<g id="edge13" class="edge">
<title>Army&#45;&gt;Unit in Army</title>
<path fill="none" stroke="black" d="M998.1,-262.97C1033.53,-251.11 1072.25,-238.15 1108.68,-225.96"/>
<polygon fill="black" stroke="black" points="1110.01,-229.21 1118.39,-222.72 1107.79,-222.57 1110.01,-229.21"/>
<path fill="none" stroke="black" d="M917.7,-262.99C934.2,-252.95 951.46,-242.47 968.03,-232.4"/>
<polygon fill="black" stroke="black" points="969.89,-235.36 976.62,-227.17 966.26,-229.38 969.89,-235.36"/>
</g>
<!-- Army&#45;&gt;Commander -->
<g id="edge12" class="edge">
<title>Army&#45;&gt;Commander</title>
<path fill="none" stroke="black" d="M1052.23,-264.59C1124.31,-247.46 1190.04,-231.65 1207,-227 1220.58,-223.28 1234.74,-219.2 1248.79,-215.02"/>
<polygon fill="black" stroke="black" points="1249.91,-218.34 1258.49,-212.12 1247.91,-211.63 1249.91,-218.34"/>
</g>
<!-- Army&#45;&gt;Summon in Combat -->
<g id="edge12" class="edge">
<g id="edge14" class="edge">
<title>Army&#45;&gt;Summon in Combat</title>
<path fill="none" stroke="black" d="M884.48,-262.88C888.2,-252.18 892.23,-240.59 896.09,-229.48"/>
<polygon fill="black" stroke="black" points="899.45,-230.47 899.43,-219.87 892.84,-228.17 899.45,-230.47"/>
<path fill="none" stroke="black" d="M793.98,-262.99C786.81,-251.5 779.27,-239.42 772.17,-228.04"/>
<polygon fill="black" stroke="black" points="775.1,-226.14 766.84,-219.51 769.17,-229.84 775.1,-226.14"/>
</g>
<!-- Unit in Combat -->
<g id="node20" class="node">
<g id="node22" class="node">
<title>Unit in Combat</title>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1428,-88 1085,-88 1085,0 1428,0 1428,-88"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1088.5,-64 1088.5,-85 1425.5,-85 1425.5,-64 1088.5,-64"/>
<text text-anchor="start" x="1203.5" y="-71.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Unit in Combat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1088.5,-41 1088.5,-62 1425.5,-62 1425.5,-41 1088.5,-41"/>
<text text-anchor="start" x="1198" y="-48.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1266" y="-48.8" font-family="monospace" font-weight="bold" font-size="14.00">CStack</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1088.5,-3 1088.5,-39 1425.5,-39 1425.5,-3 1088.5,-3"/>
<text text-anchor="start" x="1091.5" y="-24.8" font-family="Noto Serif" font-size="14.00">Represents current state of a unit during combat,</text>
<text text-anchor="start" x="1112" y="-9.8" font-family="Noto Serif" font-size="14.00">can be affected by spells or receive damage</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1085,0 1085,-88 1428,-88 1428,0 1085,0"/>
<polygon fill="#602000" fill-opacity="0.501961" stroke="transparent" points="1386.5,-88 1043.5,-88 1043.5,0 1386.5,0 1386.5,-88"/>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1047,-64 1047,-85 1384,-85 1384,-64 1047,-64"/>
<text text-anchor="start" x="1162" y="-71.8" font-family="Noto Serif" font-weight="bold" font-size="14.00">Unit in Combat</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1047,-41 1047,-62 1384,-62 1384,-41 1047,-41"/>
<text text-anchor="start" x="1156.5" y="-48.8" font-family="Noto Serif" font-size="14.00">C++ Class: </text>
<text text-anchor="start" x="1224.5" y="-48.8" font-family="monospace" font-weight="bold" font-size="14.00">CStack</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1047,-3 1047,-39 1384,-39 1384,-3 1047,-3"/>
<text text-anchor="start" x="1050" y="-24.8" font-family="Noto Serif" font-size="14.00">Represents current state of a unit during combat,</text>
<text text-anchor="start" x="1070.5" y="-9.8" font-family="Noto Serif" font-size="14.00">can be affected by spells or receive damage</text>
<polygon fill="none" stroke="#000000" stroke-opacity="0.501961" points="1043.5,0 1043.5,-88 1386.5,-88 1386.5,0 1043.5,0"/>
</g>
<!-- Unit in Army&#45;&gt;Unit in Combat -->
<g id="edge13" class="edge">
<g id="edge15" class="edge">
<title>Unit in Army&#45;&gt;Unit in Combat</title>
<path fill="none" stroke="black" d="M1256.5,-123.69C1256.5,-115.33 1256.5,-106.64 1256.5,-98.22"/>
<polygon fill="black" stroke="black" points="1260,-98.12 1256.5,-88.12 1253,-98.12 1260,-98.12"/>
<path fill="none" stroke="black" d="M1120.82,-123.69C1132.25,-114.13 1144.2,-104.15 1155.6,-94.63"/>
<polygon fill="black" stroke="black" points="1157.96,-97.22 1163.39,-88.12 1153.47,-91.85 1157.96,-97.22"/>
</g>
<!-- Commander&#45;&gt;Unit in Combat -->
<g id="edge16" class="edge">
<title>Commander&#45;&gt;Unit in Combat</title>
<path fill="none" stroke="black" d="M1327.24,-138.77C1310.99,-125.2 1292.19,-109.49 1274.67,-94.85"/>
<polygon fill="black" stroke="black" points="1276.64,-91.94 1266.72,-88.21 1272.15,-97.31 1276.64,-91.94"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -65,8 +65,12 @@ All parameters but type are optional.
// using its propagator. It has no effect on bonuses without propagator
"propagationUpdater" : {Bonus Updater, but works during propagation},
// TODO
"description" : "",
// Optional custom description, at the moment limited to creature abilities
// Visible only in creature window
"description" : "{Ability Name}\nLong description text",
// Optional, path to custom icon that will be visible in creature window
"icon" : "",
// Stacking string allows to block stacking of bonuses from different entities
// For example, devils and archdevils (different entities) both have battle-wide debuff to luck

View File

@@ -228,6 +228,11 @@ std::string CCreature::getDescriptionTextID() const
return TextIdentifier("creatures", modScope, identifier, "description").get();
}
std::string CCreature::getBonusTextID(const std::string & bonusID) const
{
return TextIdentifier("creatures", modScope, identifier, "bonus", bonusID).get();
}
CCreature::CreatureQuantityId CCreature::getQuantityID(const int & quantity)
{
if (quantity<5)
@@ -904,7 +909,7 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c
{
if (!ability.second.isNull())
{
auto b = JsonUtils::parseBonus(ability.second);
auto b = JsonUtils::parseBonus(ability.second, creature->getBonusTextID(ability.first));
b->source = BonusSource::CREATURE_ABILITY;
b->sid = BonusSourceID(creature->getId());
b->duration = BonusDuration::PERMANENT;

View File

@@ -56,6 +56,7 @@ class DLL_LINKAGE CCreature : public Creature, public CBonusSystemNode
public:
std::string getDescriptionTranslated() const;
std::string getDescriptionTextID() const;
std::string getBonusTextID(const std::string & bonusID) const;
ui32 ammMin; // initial size of stack of these creatures on adventure map (if not set in editor)
ui32 ammMax;

View File

@@ -837,11 +837,20 @@ void CStackInstance::setCount(TQuantity newCount)
std::string CStackInstance::bonusToString(const std::shared_ptr<Bonus>& bonus, bool description) const
{
if (!bonus->description.empty())
{
if (description)
return bonus->description.toString();
else
return {};
}
return LIBRARY->getBth()->bonusToString(bonus, this, description);
}
ImagePath CStackInstance::bonusToGraphics(const std::shared_ptr<Bonus> & bonus) const
{
if (!bonus->customIconPath.empty())
return bonus->customIconPath;
return LIBRARY->getBth()->bonusToGraphics(bonus);
}

View File

@@ -109,8 +109,11 @@ void CSkill::addNewBonus(const std::shared_ptr<Bonus> & b, int level)
b->source = BonusSource::SECONDARY_SKILL;
b->sid = BonusSourceID(id);
b->duration = BonusDuration::PERMANENT;
b->description.appendTextID(getNameTextID());
b->description.appendRawString(" %+d");
if (b->description.empty() && (b->type == BonusType::LUCK || b->type == BonusType::MORALE))
{
b->description.appendTextID(getNameTextID());
b->description.appendRawString(" %+d");
}
levels[level-1].effects.push_back(b);
}

View File

@@ -15,6 +15,7 @@
#include "../constants/EntityIdentifiers.h"
#include "../serializer/Serializeable.h"
#include "../texts/MetaString.h"
#include "../filesystem/ResourcePath.h"
VCMI_LIB_NAMESPACE_BEGIN
@@ -79,6 +80,7 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>, public Se
TUpdaterPtr updater;
TUpdaterPtr propagationUpdater;
ImagePath customIconPath;
MetaString description;
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID sourceID);
@@ -95,6 +97,8 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>, public Se
h & val;
h & sid;
h & description;
if (h.hasFeature(Handler::Version::CUSTOM_BONUS_ICONS))
h & customIconPath;
h & additionalInfo;
h & turnsRemain;
h & valType;

View File

@@ -80,8 +80,6 @@ public:
std::copy(newList.begin(), newList.end(), bonuses.begin());
}
template <class InputIterator>
void insert(const int position, InputIterator first, InputIterator last);
void insert(TInternalContainer::iterator position, TInternalContainer::size_type n, const std::shared_ptr<Bonus> & x);
template <typename Handler>

View File

@@ -332,8 +332,11 @@ void CArtifact::addNewBonus(const std::shared_ptr<Bonus>& b)
{
b->source = BonusSource::ARTIFACT;
b->duration = BonusDuration::PERMANENT;
b->description.appendTextID(getNameTextID());
b->description.appendRawString(" %+d");
if (b->description.empty() && (b->type == BonusType::LUCK || b->type == BonusType::MORALE))
{
b->description.appendTextID(getNameTextID());
b->description.appendRawString(" %+d");
}
CBonusSystemNode::addNewBonus(b);
}

View File

@@ -247,7 +247,8 @@ void CTownHandler::loadBuildingBonuses(const JsonNode & source, BonusList & bonu
if(!JsonUtils::parseBonus(b, bonus.get()))
continue;
bonus->description.appendTextID(building->getNameTextID());
if (bonus->description.empty() && (bonus->type == BonusType::MORALE || bonus->type == BonusType::LUCK))
bonus->description.appendTextID(building->getNameTextID());
//JsonUtils::parseBuildingBonus produces UNKNOWN type propagator instead of empty.
assert(bonus->propagator == nullptr || bonus->propagator->getPropagatorType() != CBonusSystemNode::ENodeTypes::UNKNOWN);

View File

@@ -638,10 +638,10 @@ std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter)
return nullptr;
}
std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonNode &ability)
std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonNode &ability, const TextIdentifier & descriptionID)
{
auto b = std::make_shared<Bonus>();
if (!parseBonus(ability, b.get()))
if (!parseBonus(ability, b.get(), descriptionID))
{
// caller code can not handle this case and presumes that returned bonus is always valid
logGlobal->error("Failed to parse bonus! Json config was %S ", ability.toString());
@@ -651,7 +651,7 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonNode &ability)
return b;
}
bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b, const TextIdentifier & descriptionID)
{
const JsonNode * value = nullptr;
@@ -694,12 +694,23 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
if(!ability["description"].isNull())
{
if (ability["description"].isString())
b->description.appendTextID(ability["description"].String());
if (ability["description"].isString() && !ability["description"].String().empty())
{
if (ability["description"].String()[0] == '@')
b->description.appendTextID(ability["description"].String());
else if (!descriptionID.get().empty())
{
LIBRARY->generaltexth->registerString(ability.getModScope(), descriptionID, ability["description"]);
b->description.appendTextID(descriptionID.get());
}
}
if (ability["description"].isNumber())
b->description.appendTextID("core.arraytxt." + std::to_string(ability["description"].Integer()));
}
if(!ability["icon"].isNull())
b->customIconPath = ImagePath::fromJson(ability["icon"]);
value = &ability["effectRange"];
if (!value->isNull())
b->effectRange = static_cast<BonusLimitEffect>(parseByMapN(bonusLimitEffect, value, "effect range "));

View File

@@ -11,6 +11,7 @@
#include "JsonNode.h"
#include "../GameConstants.h"
#include "../texts/TextIdentifier.h"
VCMI_LIB_NAMESPACE_BEGIN
@@ -18,12 +19,11 @@ struct Bonus;
class ILimiter;
class CSelector;
class CAddInfo;
namespace JsonUtils
{
std::shared_ptr<Bonus> parseBonus(const JsonVector & ability_vec);
std::shared_ptr<Bonus> parseBonus(const JsonNode & ability);
bool parseBonus(const JsonNode & ability, Bonus * placement);
std::shared_ptr<Bonus> parseBonus(const JsonNode & ability, const TextIdentifier & descriptionID = "");
bool parseBonus(const JsonNode & ability, Bonus * placement, const TextIdentifier & descriptionID = "");
std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter);
CSelector parseSelector(const JsonNode &ability);
}

View File

@@ -42,8 +42,9 @@ enum class ESerializationVersion : int32_t
REWARDABLE_EXTENSIONS, // new functionality for rewardable objects
FLAGGABLE_BONUS_SYSTEM_NODE, // flaggable objects now contain bonus system node
RANDOMIZATION_REWORK, // random rolls logic has been moved to server
CUSTOM_BONUS_ICONS, // support for custom icons in bonuses
CURRENT = RANDOMIZATION_REWORK,
CURRENT = CUSTOM_BONUS_ICONS,
};
static_assert(ESerializationVersion::MINIMAL <= ESerializationVersion::CURRENT, "Invalid serialization version definition!");