From 0cf969d508838cdf92c6dea93523e65e9f6aa926 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Thu, 11 Apr 2013 19:24:14 +0000 Subject: [PATCH] - console logger by default uses same format as previously (no extra data) - a lot of changes in configs; - - update to creature format - abilities are now json structure - - multiple bugfixes revealed by validation - made schemas a bit more strict - creatures data can be replaced via mods - it is possible to validate vcmi configs using schemas (disabled) --- CMakeLists.txt | 2 +- client/battle/CBattleAnimations.cpp | 3 +- config/artifacts.json | 65 +++- config/creatures/castle.json | 128 ++++++-- config/creatures/conflux.json | 332 +++++++++++++++---- config/creatures/dungeon.json | 157 +++++++-- config/creatures/fortress.json | 98 +++++- config/creatures/inferno.json | 207 +++++++++--- config/creatures/necropolis.json | 130 ++++++-- config/creatures/neutral.json | 288 ++++++++++++++--- config/creatures/rampart.json | 150 +++++++-- config/creatures/special.json | 32 +- config/creatures/stronghold.json | 78 ++++- config/creatures/tower.json | 167 ++++++++-- config/creatures/wog.json | 485 ++++++++++++++++++++++------ config/factions/neutral.json | 1 + config/schemas/artifact.json | 48 ++- config/schemas/bonus.json | 30 +- config/schemas/creature.json | 84 +++-- config/schemas/faction.json | 17 +- config/schemas/hero.json | 22 +- config/schemas/heroClass.json | 9 + config/schemas/mod.json | 4 +- config/schemas/settings.json | 15 +- config/schemas/townBuilding.json | 2 + config/schemas/townSiege.json | 8 + config/schemas/townStructure.json | 1 + lib/CArtHandler.cpp | 5 +- lib/CCreatureHandler.cpp | 386 +++++++++++----------- lib/CCreatureHandler.h | 18 +- lib/CHeroHandler.cpp | 3 + lib/CTownHandler.cpp | 3 + lib/HeroBonus.cpp | 3 +- lib/JsonNode.cpp | 39 ++- lib/filesystem/CResourceLoader.cpp | 3 - lib/logging/CLogger.cpp | 9 +- 36 files changed, 2315 insertions(+), 717 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c15743c7b..7164be1f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,7 +133,7 @@ endif() # For apple this files will be already inside vcmiclient bundle if (NOT APPLE) # copy whole directory but .svn control files and user-specific settings.json - install(DIRECTORY config DESTINATION ${DATA_DIR} PATTERN ".svn" EXCLUDE PATTERN "settings.json" EXCLUDE) + install(DIRECTORY config DESTINATION ${DATA_DIR} PATTERN ".svn" EXCLUDE) # copy vcmi mod along with all its content install(DIRECTORY Mods/vcmi DESTINATION ${DATA_DIR}/Mods PATTERN ".svn" EXCLUDE) # copy only mod.json for WoG diff --git a/client/battle/CBattleAnimations.cpp b/client/battle/CBattleAnimations.cpp index 85ac9b3ee..190cff18d 100644 --- a/client/battle/CBattleAnimations.cpp +++ b/client/battle/CBattleAnimations.cpp @@ -139,8 +139,7 @@ bool CDefenceAnimation::init() int attackerAnimType = owner->creAnims[attacker->ID]->getType(); if( ( attackerAnimType == CCreatureAnim::ATTACK_UP || attackerAnimType == CCreatureAnim::ATTACK_FRONT || - attackerAnimType == CCreatureAnim::ATTACK_DOWN ) && - owner->creAnims[attacker->ID]->getFrame() < attacker->getCreature()->animation.attackClimaxFrame ) + attackerAnimType == CCreatureAnim::ATTACK_DOWN ) ) return false; } diff --git a/config/artifacts.json b/config/artifacts.json index 7eb331b3b..3c93b3cea 100644 --- a/config/artifacts.json +++ b/config/artifacts.json @@ -2194,7 +2194,7 @@ "valueType" : "BASE_NUMBER" }, { - "additionalInfo" : 2, + "addInfo" : 2, "subtype" : "spell.lightningBolt", "type" : "ENCHANTER", "val" : 0, @@ -2256,28 +2256,28 @@ "valueType" : "PERCENT_TO_BASE" }, { - "additionalInfo" : 1, + "addInfo" : 1, "subtype" : "spell.age", "type" : "SPELL_BEFORE_ATTACK", "val" : 50, "valueType" : "BASE_NUMBER" }, { - "additionalInfo" : 1, + "addInfo" : 1, "subtype" : "spell.berserk", "type" : "SPELL_AFTER_ATTACK", "val" : 50, "valueType" : "BASE_NUMBER" }, { - "additionalInfo" : 1, + "addInfo" : 1, "subtype" : "spell.poison", "type" : "SPELL_AFTER_ATTACK", "val" : 50, "valueType" : "BASE_NUMBER" }, { - "additionalInfo" : 1, + "addInfo" : 1, "subtype" : "spell.disruptingRay", "type" : "SPELL_AFTER_ATTACK", "val" : 50, @@ -2363,7 +2363,12 @@ [ { "level": 6, - "bonus": ["PRIMARY_SKILL", 1, "primSkill.attack", 0] + "bonus": + { + "type" : "PRIMARY_SKILL", + "subtype" : "primSkill.attack", + "val" : 1 + } } ] } @@ -2385,7 +2390,11 @@ [ { "level": 1, - "bonus": ["STACK_HEALTH", 1, 0, 0] + "bonus": + { + "type" : "STACK_HEALTH", + "val" : 1 + } } ] } @@ -2408,7 +2417,11 @@ [ { "level": 1, - "bonus": ["CREATURE_DAMAGE", 1, 0, 0] + "bonus": + { + "type" : "CREATURE_DAMAGE", + "val" : 1 + } } ] } @@ -2435,7 +2448,11 @@ [ { "level": 10, - "bonus": ["CREATURE_ENCHANT_POWER", 1, 0, 0] + "bonus": + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 1 + } } ] } @@ -2457,7 +2474,11 @@ [ { "level": 10, - "bonus": ["STACKS_SPEED", 1, 0, 0] + "bonus": + { + "type" : "STACKS_SPEED", + "val" : 1 + } } ] } @@ -2468,20 +2489,28 @@ "type" : ["COMMANDER"], "growing": { - "id": 152, //bow of seeking "thresholdBonuses": [ { "level": 5, - "bonus": ["SHOOTER", 0, 0, 0] + "bonus": + { + "type" : "SHOOTER" + } }, { "level": 25, - "bonus": ["NO_WALL_PENALTY", 0, 0, 0] + "bonus": + { + "type" : "NO_WALL_PENALTY" + } }, { "level": 50, - "bonus": ["NO_DISTANCE_PENALTY", 0, 0, 0] + "bonus": + { + "type" : "NO_DISTANCE_PENALTY" + } } ] } @@ -2505,12 +2534,16 @@ "type" : ["COMMANDER"], "growing": { - "id": 153, //hardened shield "bonusesPerLevel": [ { "level": 6, - "bonus": ["PRIMARY_SKILL", 1, "primSkill.defence", 0] + "bonus": + { + "type" : "PRIMARY_SKILL", + "subtype" : "primSkill.defence", + "val" : 1 + } } ] } diff --git a/config/creatures/castle.json b/config/creatures/castle.json index 818591e6b..bf7625982 100644 --- a/config/creatures/castle.json +++ b/config/creatures/castle.json @@ -5,7 +5,13 @@ "level": 1, "faction": "castle", "upgrades": ["halberdier"], - "abilities": [ [ "CHARGE_IMMUNITY", 0, 0, 0 ] ], //pikeman immunity to Champion charge bonus + "abilities": + { + "cavalryChargeImmunity" : + { + "type" : "CHARGE_IMMUNITY" + } + }, "graphics" : { "animation": "CPKMAN.DEF" @@ -24,7 +30,13 @@ "id": 1, "level": 1, "faction": "castle", - "abilities": [ [ "CHARGE_IMMUNITY", 0, 0, 0 ] ], //halberdier immunity to Champion charge bonus + "abilities": + { + "cavalryChargeImmunity" : + { + "type" : "CHARGE_IMMUNITY" + } + }, "graphics" : { "animation": "CHALBD.DEF" @@ -50,8 +62,7 @@ "animation": "CLCBOW.DEF", "missile" : { - "projectile": "PLCBOWX.DEF", - "spinning": false + "projectile": "PLCBOWX.DEF" } }, "sound" : @@ -69,20 +80,20 @@ "id": 3, "level": 2, "faction": "castle", - "abilities": [ - { - "type": "ADDITIONAL_ATTACK", - "val" : 1, - "effectRange": "ONLY_DISTANCE_FIGHT" - } - ], + "abilities": { + "extraAttack" : + { + "type": "ADDITIONAL_ATTACK", + "val" : 1, + "effectRange": "ONLY_DISTANCE_FIGHT" + } + }, "graphics" : { "animation": "CHCBOW.DEF", "missile" : { - "projectile": "PLCBOWX.DEF", - "spinning": false + "projectile": "PLCBOWX.DEF" } }, "sound" : @@ -100,7 +111,14 @@ "id": 4, "level": 3, "faction": "castle", - "abilities": [ [ "ADDITIONAL_RETALIATION", 1, 0, 0 ] ], //griffins retaliate twice + "abilities": + { + "extraRetaliation" : + { + "type" : "ADDITIONAL_RETALIATION", + "val" : 1 + } + }, "upgrades": ["royalGriffin"], "hasDoubleWeek": true, "graphics" : @@ -121,7 +139,13 @@ "id": 5, "level": 3, "faction": "castle", - "abilities": [ [ "UNLIMITED_RETALIATIONS", 0, 0, 0 ] ], //royal griffins retaliate always + "abilities": + { + "unlimitedRetaliation" : + { + "type" : "UNLIMITED_RETALIATIONS" + } + }, "graphics" : { "animation": "CRGRIF.DEF" @@ -159,7 +183,14 @@ "id": 7, "level": 4, "faction": "castle", - "abilities": [ [ "ADDITIONAL_ATTACK", 1, 0, 0 ] ], + "abilities": + { + "extraAttack" : + { + "type" : "ADDITIONAL_ATTACK", + "val" : 1 + } + }, "graphics" : { "animation": "CCRUSD.DEF" @@ -184,8 +215,7 @@ "animation": "CMONKK.DEF", "missile" : { - "projectile": "CPRZEAX.DEF", - "spinning": false + "projectile": "CPRZEAX.DEF" } }, "sound" : @@ -208,8 +238,7 @@ "animation": "CZEALT.DEF", "missile" : { - "projectile": "CPRZEAX.DEF", - "spinning": false + "projectile": "CPRZEAX.DEF" } }, "sound" : @@ -264,11 +293,21 @@ "id": 12, "level": 7, "faction": "castle", - "abilities": - [ - ["HATE", 50, "creature.archDevil", 0], //angels hate archdevils - ["HATE", 50, "creature.devil", 0] //angels hate devil - ], + "abilities": + { + "hateDevils" : + { + "type" : "HATE", + "subtype" : "creature.devil", + "val" : 50 + }, + "hateArchDevils" : + { + "type" : "HATE", + "subtype" : "creature.archDevil", + "val" : 50 + } + }, "upgrades": ["archangel"], "graphics" : { @@ -288,14 +327,37 @@ "id": 13, "level": 7, "faction": "castle", - "abilities": - [ - ["SPECIFIC_SPELL_POWER", 100, "spell.resurrection", 0], // 100 hp per Archangel - ["SPELLCASTER", 0, "spell.resurrection", 0 ], //archangels cast resurrection - ["HATE", 50, "creature.archDevil", 0], //archangels hate archdevils - ["HATE", 50, "creature.devil", 0] , //archangels hate devils - ["CASTS", 1, 0, 0] - ], + "abilities": + { + "resurrection100hp" : + { + "type" : "SPECIFIC_SPELL_POWER", + "subtype" : "spell.resurrection", + "val" : 100 + }, + "resurrects" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.resurrection" + }, + "spellpoints" : + { + "type" : "CASTS", + "val" : 1 + }, + "hateDevils" : + { + "type" : "HATE", + "subtype" : "creature.devil", + "val" : 50 + }, + "hateArchDevils" : + { + "type" : "HATE", + "subtype" : "creature.archDevil", + "val" : 50 + } + }, "graphics" : { "animation": "CRANGL.DEF" diff --git a/config/creatures/conflux.json b/config/creatures/conflux.json index ac1f8f39e..b88ebd118 100644 --- a/config/creatures/conflux.json +++ b/config/creatures/conflux.json @@ -5,14 +5,34 @@ "level": 2, "extraNames": [ "airElementals" ], "faction": "conflux", - "abilities": - [ - ["MIND_IMMUNITY", 0, 0, 0], //air elementals are immune to mind spells - ["SPELL_IMMUNITY", 0, "spell.meteorShower", 0], //air elementals are immune to meteor shower - ["NON_LIVING", 0, 0, 0 ], //air elementals are non-living - ["MORE_DAMAGE_FROM_SPELL", 100, "spell.chainLightning", 0],//air elementals are vulnerable to chain lightning - ["MORE_DAMAGE_FROM_SPELL", 100, "spell.lightningBolt", 0] //air elementals are vulnerable to lightning bolt - ], + "abilities": + { + "nonLiving" : + { + "type" : "NON_LIVING" + }, + "immuneToMind" : + { + "type" : "MIND_IMMUNITY" + }, + "meteorShowerImmunity" : + { + "type" : "SPELL_IMMUNITY", + "subtype" : "spell.meteorShower" + }, + "lightingVulnerablity" : + { + "type" : "MORE_DAMAGE_FROM_SPELL", + "subtype" : "spell.lightningBolt", + "val" : 100 + }, + "chainLightingVulnerablity" : + { + "type" : "MORE_DAMAGE_FROM_SPELL", + "subtype" : "spell.chainLightning", + "val" : 100 + } + }, "upgrades": ["stormElemental"], "graphics" : { @@ -32,14 +52,33 @@ "id": 113, "level": 5, "faction": "conflux", - "abilities": - [ - ["MIND_IMMUNITY", 0, 0, 0], //earth elementals are immune to mind spells - ["SPELL_IMMUNITY", 0, "spell.chainLightning", 0],//earth elementals are immune to chain lightning - ["SPELL_IMMUNITY", 0, "spell.lightningBolt", 0], //earth elementals are immune to lightning bolt - ["NON_LIVING", 0, 0, 0], - [ "MORE_DAMAGE_FROM_SPELL", 100, "spell.meteorShower", 0 ] //earth elementals are vulnerable to meteor shower - ], + "abilities": + { + "nonLiving" : + { + "type" : "NON_LIVING" + }, + "immuneToMind" : + { + "type" : "MIND_IMMUNITY" + }, + "meteorShowerVulnerability" : + { + "type" : "MORE_DAMAGE_FROM_SPELL", + "subtype" : "spell.meteorShower", + "val" : 100 + }, + "lightingImmunity" : + { + "type" : "SPELL_IMMUNITY", + "subtype" : "spell.lightningBolt" + }, + "chainLightingImmunity" : + { + "type" : "SPELL_IMMUNITY", + "subtype" : "spell.chainLightning" + } + }, "upgrades": ["magmaElemental"], "graphics" : { @@ -59,13 +98,33 @@ "id": 114, "level": 4, "faction": "conflux", - "abilities": - [ - ["MIND_IMMUNITY", 0, 0, 0],//fire elementals are immune to mind spells - ["NON_LIVING", 0, 0, 0 ], //fire elementals are non-living - [ "MORE_DAMAGE_FROM_SPELL", 100, "spell.frostRing", 0 ], //fire elementals are vulnerable to frost ring - [ "MORE_DAMAGE_FROM_SPELL", 100, "spell.iceBolt", 0 ], //fire elementals are vulnerable to ice bolt - [ "FIRE_IMMUNITY", 0, 0, 0 ] ], //fire elementals are immune to fire spells + "abilities": + { + "nonLiving" : + { + "type" : "NON_LIVING" + }, + "immuneToMind" : + { + "type" : "MIND_IMMUNITY" + }, + "immuneToFire" : + { + "type" : "FIRE_IMMUNITY" + }, + "frostRingVulnerablity" : + { + "type" : "MORE_DAMAGE_FROM_SPELL", + "subtype" : "spell.frostRing", + "val" : 100 + }, + "iceBoltVulnerablity" : + { + "type" : "MORE_DAMAGE_FROM_SPELL", + "subtype" : "spell.iceBolt", + "val" : 100 + } + }, "upgrades": ["energyElemental"], "graphics" : { @@ -86,17 +145,52 @@ "level": 3, "extraNames": [ "waterElementals" ], "faction": "conflux", - "abilities": [ - ["MIND_IMMUNITY", 0, 0, 0],//water elementals are immune to mind spells - ["SPELL_IMMUNITY", 0, "spell.frostRing", 0 ],//water elementals are immune to frost ring - ["SPELL_IMMUNITY", 0, "spell.iceBolt", 0 ],//water elementals are immune to ice bolt - ["NON_LIVING", 0, 0, 0 ], //water elementals are non-living - ["MORE_DAMAGE_FROM_SPELL", 100, "spell.fireShield", 0 ], //water elementals are vulnerable to fire shield - ["MORE_DAMAGE_FROM_SPELL", 100, "spell.inferno", 0 ], //water elementals are vulnerable to inferno - ["MORE_DAMAGE_FROM_SPELL", 100, "spell.fireball", 0 ], //water elementals are vulnerable to fireball - ["MORE_DAMAGE_FROM_SPELL", 100, "spell.fireWall", 0 ], //water elementals are vulnerable to fire wall - ["DOUBLE_WIDE", 0, 0, 0 ] - ], + "abilities": + { + "nonLiving" : + { + "type" : "NON_LIVING" + }, + "immuneToMind" : + { + "type" : "MIND_IMMUNITY" + }, + "fireShieldVulnerablity" : + { + "type" : "MORE_DAMAGE_FROM_SPELL", + "subtype" : "spell.fireShield", + "val" : 100 + }, + "infernoVulnerablity" : + { + "type" : "MORE_DAMAGE_FROM_SPELL", + "subtype" : "spell.inferno", + "val" : 100 + }, + "fireballVulnerablity" : + { + "type" : "MORE_DAMAGE_FROM_SPELL", + "subtype" : "spell.fireball", + "val" : 100 + }, + "fireWallVulnerablity" : + { + "type" : "MORE_DAMAGE_FROM_SPELL", + "subtype" : "spell.fireWall", + "val" : 100 + }, + "iceBoltImmunity" : + { + "type" : "SPELL_IMMUNITY", + "subtype" : "spell.iceBolt" + }, + "frostRingImmunity" : + { + "type" : "SPELL_IMMUNITY", + "subtype" : "spell.frostRing" + } + }, + "doubleWide" : true, "upgrades": ["iceElemental"], "graphics" : { @@ -154,8 +248,14 @@ "id": 120, "level": 6, "faction": "conflux", - "abilities": [ [ "NON_LIVING", 0, 0, 0 ] ], //magic elementals shouldn't get morale - "ability_remove": [ "DOUBLE_WIDE" ], + "abilities": + { + "nonLiving" : + { + "type" : "NON_LIVING" + } + }, + "doubleWide" : false, "upgrades": ["magicElemental"], "graphics" : { @@ -175,9 +275,19 @@ "id": 121, "level": 6, "faction": "conflux", - "abilities": [ [ "NON_LIVING", 0, 0, 0 ], //ice elementals shouldn't get morale - [ "LEVEL_SPELL_IMMUNITY", 5, 0, 0 ] ], //magic elementals are immune to all spells - "ability_remove": [ "DOUBLE_WIDE" ], + "abilities": + { + "nonLiving" : + { + "type" : "NON_LIVING" + }, + "magicImmunity" : + { + "type" : "LEVEL_SPELL_IMMUNITY", + "val" : 5 + } + }, + "doubleWide" : false, "graphics" : { "animation": "CMAGEL.DEF" @@ -196,18 +306,36 @@ "id": 123, "level": 3, "faction": "conflux", - "abilities": [ [ "NON_LIVING", 0, 0, 0 ], - [ "DOUBLE_WIDE", 0, 0, 0 ], //ice elemental should be treated as double-wide - [ "CREATURE_ENCHANT_POWER", 6, 0, 0 ], - [ "CASTS", 3, 0, 0 ], - [ "SPELLCASTER", 2, "spell.protectWater", 0 ]], + "abilities": + { + "nonLiving" : + { + "type" : "NON_LIVING" + }, + "spellPower" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 6 + }, + "spellPoints" : + { + "type" : "CASTS", + "val" : 3 + }, + "spellcaster": + { + "type" : "SPELLCASTER", + "subtype" : "spell.protectWater", + "val" : 2 + } + }, + "doubleWide" : true, "graphics" : { "animation": "CICEE.DEF", "missile" : { - "projectile": "PICEE.DEF", - "spinning": false + "projectile": "PICEE.DEF" } }, "sound" : @@ -225,10 +353,29 @@ "id": 125, "level": 5, "faction": "conflux", - "abilities": [ [ "NON_LIVING", 0, 0, 0 ], //magma elementals shouldn't get morale - [ "CREATURE_ENCHANT_POWER", 6, 0, 0 ], - [ "CASTS", 3, 0, 0 ], - [ "SPELLCASTER", 2, "spell.protectEarth", 0 ]], + "abilities": + { + "nonLiving" : + { + "type" : "NON_LIVING" + }, + "spellPower" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 6 + }, + "spellPoints" : + { + "type" : "CASTS", + "val" : 3 + }, + "spellcaster": + { + "type" : "SPELLCASTER", + "subtype" : "spell.protectEarth", + "val" : 2 + } + }, "graphics" : { "animation": "CSTONE.DEF" @@ -247,17 +394,35 @@ "id": 127, "level": 2, "faction": "conflux", - "abilities": [ [ "NON_LIVING", 0, 0, 0 ], //storm elementals shouldn't get morale - [ "CREATURE_ENCHANT_POWER", 6, 0, 0 ], - [ "CASTS", 3, 0, 0 ], - [ "SPELLCASTER", 2, "spell.protectAir", 0 ]], + "abilities": + { + "nonLiving" : + { + "type" : "NON_LIVING" + }, + "spellPower" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 6 + }, + "spellPoints" : + { + "type" : "CASTS", + "val" : 3 + }, + "spellcaster": + { + "type" : "SPELLCASTER", + "subtype" : "spell.protectAir", + "val" : 2 + } + }, "graphics" : { "animation": "CSTORM.DEF", "missile" : { - "projectile": "CPRGTIX.DEF", - "spinning": false + "projectile": "CPRGTIX.DEF" } }, "sound" : @@ -275,10 +440,29 @@ "id": 129, "level": 4, "faction": "conflux", - "abilities": [ [ "NON_LIVING", 0, 0, 0 ] , //energy elementals shouldn't get morale - [ "CREATURE_ENCHANT_POWER", 6, 0, 0 ], - [ "CASTS", 3, 0, 0 ], - [ "SPELLCASTER", 2, "spell.protectFire", 0 ]], + "abilities": + { + "nonLiving" : + { + "type" : "NON_LIVING" + }, + "spellPower" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 6 + }, + "spellPoints" : + { + "type" : "CASTS", + "val" : 3 + }, + "spellcaster": + { + "type" : "SPELLCASTER", + "subtype" : "spell.protectFire", + "val" : 2 + } + }, "graphics" : { "animation": "CNRG.DEF" @@ -298,7 +482,13 @@ "level": 7, "faction": "conflux", "upgrades": ["phoenix"], - "abilities": [ ["FIRE_IMMUNITY", 0, 0, 0] ], + "abilities": + { + "immuneToFire" : + { + "type" : "FIRE_IMMUNITY" + }, + }, "graphics" : { "animation": "CFBIRD.DEF" @@ -317,9 +507,23 @@ "id": 131, "level": 7, "faction": "conflux", - "abilities": [ [ "CASTS", 1, 0, 0 ], //Phoenix rebirths once - ["FIRE_IMMUNITY", 0, 0, 0], - [ "REBIRTH", 20, 0, 0 ] ], //20% of stack is resurrected + "abilities": + { + "rebirthOnce" : + { + "type" : "CASTS", + "val" : 1 + }, + "immuneToFire" : + { + "type" : "FIRE_IMMUNITY" + }, + "rebirth" : + { + "type" : "REBIRTH", + "val" : 20 + } + }, "graphics" : { "animation": "CPHX.DEF" diff --git a/config/creatures/dungeon.json b/config/creatures/dungeon.json index 68819d921..c88a4de13 100644 --- a/config/creatures/dungeon.json +++ b/config/creatures/dungeon.json @@ -4,7 +4,14 @@ "id": 70, "level": 1, "faction": "dungeon", - "abilities": [ [ "SPELL_IMMUNITY", 0, "spell.blind", 0 ] ], //troglodytes are immune to blind + "abilities": + { + "blindImmunity" : + { + "type" : "SPELL_IMMUNITY", + "subtype" : "spell.blind" + } + }, "upgrades": ["infernalTroglodyte"], "hasDoubleWeek": true, "graphics" : @@ -25,7 +32,14 @@ "id": 71, "level": 1, "faction": "dungeon", - "abilities": [ [ "SPELL_IMMUNITY", 0, "spell.blind", 0 ] ], //infernal troglodytes are immune to blind + "abilities": + { + "blindImmunity" : + { + "type" : "SPELL_IMMUNITY", + "subtype" : "spell.blind" + } + }, "graphics" : { "animation": "CITROG.DEF" @@ -44,7 +58,13 @@ "id": 72, "level": 2, "faction": "dungeon", - "abilities": [ [ "RETURN_AFTER_STRIKE", 0, 0, 0 ] ], //Harpies return after attack + "abilities": + { + "strikeAndReturn" : + { + "type" : "RETURN_AFTER_STRIKE" + } + }, "upgrades": ["harpyHag"], "hasDoubleWeek": true, "graphics" : @@ -66,8 +86,17 @@ "id": 73, "level": 2, "faction": "dungeon", - "abilities": [ [ "RETURN_AFTER_STRIKE", 0, 0, 0 ], //Harpy Hags return after attack - [ "BLOCKS_RETALIATION", 0, 0, 0 ] ], //Harpy Hags + "abilities": + { + "strikeAndReturn" : + { + "type" : "RETURN_AFTER_STRIKE" + }, + "noRetaliation" : + { + "type" : "BLOCKS_RETALIATION" + } + }, "graphics" : { "animation": "CHARPH.DEF" @@ -93,8 +122,7 @@ "animation": "CBEHOL.DEF", "missile" : { - "projectile": "SMBALX.DEF", - "spinning": false + "projectile": "SMBALX.DEF" } }, "sound" : @@ -104,8 +132,7 @@ "killed": "BHDRKILL.wav", "move": "BHDRMOVE.wav", "shoot": "BHDRSHOT.wav", - "wince": "BHDRWNCE.wav", - "ext1": "BHDRDETH.wav" + "wince": "BHDRWNCE.wav" } }, "evilEye" : @@ -118,8 +145,7 @@ "animation": "CEVEYE.DEF", "missile" : { - "projectile": "SMBALX.DEF", - "spinning": false + "projectile": "SMBALX.DEF" } }, "sound" : @@ -129,8 +155,7 @@ "killed": "EVLIKILL.wav", "move": "EVLIMOVE.wav", "shoot": "EVLISHOT.wav", - "wince": "EVLIWNCE.wav", - "ext1": "EVLIDETH.wav" + "wince": "EVLIWNCE.wav" } }, "medusa" : @@ -138,15 +163,23 @@ "id": 76, "level": 4, "faction": "dungeon", - "abilities": [ [ "SPELL_AFTER_ATTACK", 20, "spell.stoneGaze", 2000 ] ], + "abilities": + { + "petrification" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.stoneGaze", + "val" : 20, + "addInfo" : 2000 // FIXME: replace with range field? + } + }, "upgrades": ["medusaQueen"], "graphics" : { "animation": "CMEDUS.DEF", "missile" : { - "projectile": "PMEDUSX.DEF", - "spinning": false + "projectile": "PMEDUSX.DEF" } }, "sound" : @@ -164,14 +197,22 @@ "id": 77, "level": 4, "faction": "dungeon", - "abilities": [ [ "SPELL_AFTER_ATTACK", 20, "spell.stoneGaze", 2000 ] ], + "abilities": + { + "petrification" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.stoneGaze", + "val" : 20, + "addInfo" : 2000 // FIXME: replace with range? + } + }, "graphics" : { "animation": "CMEDUQ.DEF", "missile" : { - "projectile": "PMEDUSX.DEF", - "spinning": false + "projectile": "PMEDUSX.DEF" } }, "sound" : @@ -189,7 +230,13 @@ "id": 78, "level": 5, "faction": "dungeon", - "abilities": [ [ "SELF_MORALE", 0, 0, 0 ] ], + "abilities": + { + "fearless" : + { + "type" : "SELF_MORALE" + } + }, "upgrades": ["minotaurKing"], "graphics" : { @@ -209,7 +256,13 @@ "id": 79, "level": 5, "faction": "dungeon", - "abilities": [ [ "SELF_MORALE", 0, 0, 0 ] ], + "abilities": + { + "fearless" : + { + "type" : "SELF_MORALE" + } + }, "graphics" : { "animation": "CMINOK.DEF" @@ -249,7 +302,15 @@ "id": 81, "level": 6, "faction": "dungeon", - "abilities": [ [ "SPELL_AFTER_ATTACK", 20, "spell.paralyze", 0 ] ], + "abilities": + { + "paralize" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.paralyze", + "val" : 20 + } + }, "graphics" : { "animation": "CCMCOR.DEF" @@ -269,9 +330,22 @@ "id": 82, "level": 7, "faction": "dungeon", - "abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ], //red dragon is a dragon - [ "TWO_HEX_ATTACK_BREATH", 0, 0, 0 ], //Red Dragon has breath attack - [ "LEVEL_SPELL_IMMUNITY", 3, 0, 0 ] ], //red dragon's spell immunity + "abilities": + { + "dragon" : + { + "type" : "DRAGON_NATURE" + }, + "fireBreath" : + { + "type" : "TWO_HEX_ATTACK_BREATH" + }, + "spellImmunity" : + { + "type" : "LEVEL_SPELL_IMMUNITY", + "val" : 3 + } + }, "upgrades": ["blackDragon"], "graphics" : { @@ -291,11 +365,34 @@ "id": 83, "level": 7, "faction": "dungeon", - "abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ], //black dragon is a dragon - [ "TWO_HEX_ATTACK_BREATH", 0, 0, 0 ], //Black Dragon has breath attack - [ "HATE", 50, "creature.titan", 0 ], //Hate Titans - [ "HATE", 50, "creature.giant", 0 ], //Hate Giants - [ "LEVEL_SPELL_IMMUNITY", 5, 0, 0 ] ], //black dragon's spell immunity + "abilities": + { + "dragon" : + { + "type" : "DRAGON_NATURE" + }, + "fireBreath" : + { + "type" : "TWO_HEX_ATTACK_BREATH" + }, + "spellImmunity" : + { + "type" : "LEVEL_SPELL_IMMUNITY", + "val" : 5 + }, + "hateGiants" : + { + "type" : "HATE", + "subtype" : "creature.giant", + "val" : 50 + }, + "hateTitans" : + { + "type" : "HATE", + "subtype" : "creature.titan", + "val" : 50 + } + }, "graphics" : { "animation": "CBDRGN.DEF" diff --git a/config/creatures/fortress.json b/config/creatures/fortress.json index 5305436b4..1db38fcbb 100644 --- a/config/creatures/fortress.json +++ b/config/creatures/fortress.json @@ -49,8 +49,7 @@ "animation": "CPLIZA.DEF", "missile" : { - "projectile": "PPLIZAX.DEF", - "spinning": false + "projectile": "PPLIZAX.DEF" } }, "sound" : @@ -73,8 +72,7 @@ "animation": "CALIZA.DEF", "missile" : { - "projectile": "PPLIZAX.DEF", - "spinning": false + "projectile": "PPLIZAX.DEF" } }, "sound" : @@ -111,7 +109,14 @@ "id": 103, "level": 5, "faction": "fortress", - "abilities": [ [ "DEATH_STARE", 10, 0, 0 ] ], //mighty gorgons + "abilities": + { + "deathStare" : + { + "type" : "DEATH_STARE", + "val" : 10 + } + }, "graphics" : { "animation": "CBGOG.DEF" @@ -131,7 +136,15 @@ "level": 3, "extraNames": [ "dragonFly" ], "faction": "fortress", - "abilities": [ [ "SPELL_AFTER_ATTACK", 100, "spell.dispelHelpful", 0 ] ], + "abilities": + { + "dispellHelpful" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.dispelHelpful", + "val" : 100 + } + }, "upgrades": ["fireDragonFly"], "hasDoubleWeek": true, "graphics" : @@ -152,8 +165,21 @@ "id": 105, "level": 3, "faction": "fortress", - "abilities": [ [ "SPELL_AFTER_ATTACK", 100, "spell.dispelHelpful", 0 ], - [ "SPELL_AFTER_ATTACK", 100, "spell.weakness", 0 ] ], + "abilities": + { + "dispellHelpful" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.dispelHelpful", + "val" : 100 + }, + "castWeakness" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.weakness", + "val" : 100 + } + }, "graphics" : { "animation": "CDRFIR.DEF" @@ -173,7 +199,15 @@ "id": 106, "level": 4, "faction": "fortress", - "abilities": [ [ "SPELL_AFTER_ATTACK", 20, "spell.stoneGaze", 0 ] ], + "abilities": + { + "petrify" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.stoneGaze", + "val" : 20 + } + }, "upgrades": ["greaterBasilisk"], "graphics" : { @@ -193,7 +227,15 @@ "id": 107, "level": 4, "faction": "fortress", - "abilities": [ [ "SPELL_AFTER_ATTACK", 20, "spell.stoneGaze", 0 ] ], + "abilities": + { + "petrify" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.stoneGaze", + "val" : 20 + } + }, "graphics" : { "animation": "CGBASI.DEF" @@ -231,7 +273,15 @@ "id": 109, "level": 6, "faction": "fortress", - "abilities": [ [ "SPELL_AFTER_ATTACK", 50, "spell.poison", 0 ] ], //50% probability (from FizMiG) + "abilities": + { + "petrify" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.stoneGaze", + "val" : 50 + } + }, "graphics" : { "animation": "CWYVMN.DEF" @@ -250,8 +300,17 @@ "id": 110, "level": 7, "faction": "fortress", - "abilities": [ [ "BLOCKS_RETALIATION", 0, 0, 0 ], - [ "ATTACKS_ALL_ADJACENT", 0, 0, 0 ] ], + "abilities": + { + "noRetaliate" : + { + "type" : "BLOCKS_RETALIATION" + }, + "attackAll" : + { + "type" : "ATTACKS_ALL_ADJACENT" + } + }, "upgrades": ["chaosHydra"], "graphics" : { @@ -271,8 +330,17 @@ "id": 111, "level": 7, "faction": "fortress", - "abilities": [ [ "BLOCKS_RETALIATION", 0, 0, 0 ], - [ "ATTACKS_ALL_ADJACENT", 0, 0, 0 ] ], + "abilities": + { + "noRetaliate" : + { + "type" : "BLOCKS_RETALIATION" + }, + "attackAll" : + { + "type" : "ATTACKS_ALL_ADJACENT" + } + }, "graphics" : { "animation": "CCHYDR.DEF" diff --git a/config/creatures/inferno.json b/config/creatures/inferno.json index 6f73fbd01..3b4ff031a 100644 --- a/config/creatures/inferno.json +++ b/config/creatures/inferno.json @@ -23,7 +23,14 @@ "id": 43, "level": 1, "faction": "inferno", - "abilities": [ [ "MANA_CHANNELING", 20, 0, 0 ] ], //familiars + "abilities": + { + "manaChannel" : + { + "type" : "MANA_CHANNELING", + "val" : 20 + } + }, "graphics" : { "animation": "CFAMIL.DEF" @@ -49,8 +56,7 @@ "animation": "CGOG.DEF", "missile" : { - "projectile": "CPRGOGX.DEF", - "spinning": false + "projectile": "CPRGOGX.DEF" } }, "sound" : @@ -60,8 +66,7 @@ "killed": "GOGGKILL.wav", "move": "GOGGMOVE.wav", "shoot": "GOGGSHOT.wav", - "wince": "GOGGWNCE.wav", - "ext1": "GOGFLAME.wav" + "wince": "GOGGWNCE.wav" } }, "magog" : @@ -69,14 +74,20 @@ "id": 45, "level": 2, "faction": "inferno", - "abilities": [ [ "SPELL_LIKE_ATTACK", 0, 21, 0 ] ], //magogs fire with fireballs + "abilities": + { + "fireball" : + { + "type" : "SPELL_LIKE_ATTACK", + "subtype" : "spell.fireball" + } + }, "graphics" : { "animation": "CMAGOG.DEF", "missile" : { - "projectile": "CPRGOGX.DEF", - "spinning": false + "projectile": "CPRGOGX.DEF" } }, "sound" : @@ -86,8 +97,7 @@ "killed": "MGOGKILL.wav", "move": "MGOGMOVE.wav", "shoot": "MGOGSHOT.wav", - "wince": "MGOGWNCE.wav", - "ext1": "GOGFLAME.wav" + "wince": "MGOGWNCE.wav" } }, "hellHound" : @@ -96,7 +106,10 @@ "level": 3, "faction": "inferno", "upgrades": ["cerberus"], - "ability_remove": [ "FLYING" ], //hell hound doesn't fly + "abilities": + { + "FLYING_ARMY" : null //hell hound doesn't fly + }, "graphics" : { "animation": "CHHOUN.DEF" @@ -115,9 +128,18 @@ "id": 47, "level": 3, "faction": "inferno", - "abilities": [ [ "THREE_HEADED_ATTACK", 0, 0, 0 ], - [ "BLOCKS_RETALIATION", 0, 0, 0 ] ], - "ability_remove": [ "FLYING" ], //cerberus doesn't fly + "abilities": + { + "threeHeads" : + { + "type" : "THREE_HEADED_ATTACK" + }, + "noRetaliation" : + { + "type" : "BLOCKS_RETALIATION" + }, + "FLYING_ARMY" : null //cerberus doesn't fly + }, "graphics" : { "animation": "CCERBU.DEF" @@ -192,8 +214,20 @@ "id": 51, "level": 5, "faction": "inferno", - "abilities": [ [ "DAEMON_SUMMONING", 50, 48, 0 ], - [ "CASTS", 1, 0, 0] ], //pit lord + "abilities": + { + "demonSummon" : + { + "type" : "DAEMON_SUMMONING", + "subtype" : "creature.demon", + "val" : 50 + }, + "castsAmount" : + { + "type" : "CASTS", + "val" : 1 + } + }, "graphics" : { "animation": "CPFOE.DEF" @@ -211,11 +245,30 @@ { "id": 52, "level": 6, - "faction": "inferno", - "abilities": [ [ "HATE", 50, 37, 0 ], - [ "HATE", 50, 36, 0 ], - [ "FLYING", 0, 0, 0 ], //efreeti hate master genies - [ "FIRE_IMMUNITY", 0, 0, 0 ] ], //efreeti hate genies + "faction": "inferno", + "abilities": + { + "hateGenies" : + { + "type" : "HATE", + "subtype" : "creature.genie", + "val" : 50 + }, + "hateMasterGenies" : + { + "type" : "HATE", + "subtype" : "creature.masterGenie", + "val" : 50 + }, + "canFly" : + { + "type" : "FLYING" + }, + "immuneToFire" : + { + "type" : "FIRE_IMMUNITY" + } + }, "upgrades": ["efreetSultan"], "graphics" : { @@ -235,11 +288,34 @@ "id": 53, "level": 6, "faction": "inferno", - "abilities": [ [ "HATE", 50, 37, 0 ], - [ "HATE", 50, 36, 0 ], - [ "FLYING", 0, 0, 0 ], //efreet sultans hate master genies - [ "FIRE_SHIELD", 0, 36, 0 ], //efreet sultans hate genies - [ "FIRE_IMMUNITY", 0, 0, 0 ] ], //efreet sultan //Efreet Sultan + "abilities": + { + "hateGenies" : + { + "type" : "HATE", + "subtype" : "creature.genie", + "val" : 50 + }, + "hateMasterGenies" : + { + "type" : "HATE", + "subtype" : "creature.masterGenie", + "val" : 50 + }, + "canFly" : + { + "type" : "FLYING" + }, + "immuneToFire" : + { + "type" : "FIRE_IMMUNITY" + }, + "fireShield" : + { + "type" : "FIRE_SHIELD", + "subtype" : 36 //FIXME: what is this magic number for? + } + }, "graphics" : { "animation": "CEFRES.DEF" @@ -259,12 +335,36 @@ "id": 54, "level": 7, "faction": "inferno", - "ability_remove": [ "FLYING" ], //use teleport instead - "abilities": [ [ "HATE", 50, 13, 0 ], - [ "FLYING", 0, 1, 0], //teleport - [ "HATE", 50, 12, 0 ], - [ "ENEMY_LUCK_DECREASING", 1, 0, 0 ], //devils //devils hate archangles - [ "BLOCKS_RETALIATION", 0, 0, 0 ] ], //devils //devils hate angels + "abilities": + { + "hateAngels" : + { + "type" : "HATE", + "subtype" : "creature.angel", + "val" : 50 + }, + "hateArchAngels" : + { + "type" : "HATE", + "subtype" : "creature.angel", + "val" : 50 + }, + "FLYING_ARMY" : + { + // type loaded from crtraits + "subtype" : 1 // teleports + }, + "descreaseLuck" : + { + "type" : "LUCK", + "effectRange" : "ONLY_ENEMY_ARMY", + "val" : -1 + }, + "blockRetaliation" : + { + "type" : "BLOCKS_RETALIATION" + } + }, "upgrades": ["archDevil"], "graphics" : { @@ -277,8 +377,8 @@ "killed": "DEVLKILL.wav", "move": "DEVLMOVE.wav", "wince": "DEVLWNCE.wav", - "ext1": "DEVLEXT1.wav", - "ext2": "DEVLEXT2.wav" + "startMoving": "DEVLEXT1.wav", + "endMoving": "DEVLEXT2.wav" } }, "archDevil" : @@ -286,14 +386,39 @@ "id": 55, "level": 7, "faction": "inferno", - "ability_remove": [ "FLYING" ], //use teleport instead - "abilities": [ [ "HATE", 50, 13, 0 ], - [ "HATE", 50, 12, 0 ], - [ "FLYING", 0, 1, 0], - [ "ENEMY_LUCK_DECREASING", 1, 0, 0 ], //archdevils //archdevils hate archangles - [ "BLOCKS_RETALIATION", 0, 0, 0 ] ], //archdevils //archdevils hate angels + "abilities" : + { + "hateAngels" : + { + "type" : "HATE", + "subtype" : "creature.angel", + "val" : 50 + }, + "hateArchAngels" : + { + "type" : "HATE", + "subtype" : "creature.angel", + "val" : 50 + }, + "FLYING_ARMY" : + { + // type loaded from crtraits + "subtype" : 1 // teleports + }, + "descreaseLuck" : + { + "type" : "LUCK", + "effectRange" : "ONLY_ENEMY_ARMY", + "val" : -1 + }, + "blockRetaliation" : + { + "type" : "BLOCKS_RETALIATION" + } + }, "graphics" : { + "missile" : null, "animation": "CADEVL.DEF" }, "sound" : @@ -304,7 +429,7 @@ "move": "ADVLMOVE.wav", "wince": "ADVLWNCE.wav", "startMoving": "ADVLEXT1.wav", - "stopMoving": "ADVLEXT2.wav" + "endMoving": "ADVLEXT2.wav" } } } diff --git a/config/creatures/necropolis.json b/config/creatures/necropolis.json index 25dcc9f75..ca0875e95 100644 --- a/config/creatures/necropolis.json +++ b/config/creatures/necropolis.json @@ -79,7 +79,14 @@ "id": 60, "level": 3, "faction": "necropolis", - "abilities": [ [ "FULL_HP_REGENERATION", 0, 1, 0 ] ], + "abilities": + { + "regenerate" : + { + "type" : "FULL_HP_REGENERATION", + "subtype" : 1 + } + }, "upgrades": ["wraith"], "hasDoubleWeek": true, "graphics" : @@ -100,8 +107,19 @@ "id": 61, "level": 3, "faction": "necropolis", - "abilities": [ [ "FULL_HP_REGENERATION", 0, 1, 0 ], - [ "MANA_DRAIN", 2, 0, 0 ] ], + "abilities": + { + "regenerate" : + { + "type" : "FULL_HP_REGENERATION", + "subtype" : 1 + }, + "drainsMana" : + { + "type" : "MANA_DRAIN", + "val" : 2 + } + }, "graphics" : { "animation": "CWRAIT.DEF" @@ -120,7 +138,14 @@ "id": 62, "level": 4, "faction": "necropolis", - "abilities": [ [ "BLOCKS_RETALIATION", 0, 0, 0 ] ], + "abilities": + { + "noRetalitation" : + { + "type" : "BLOCKS_RETALIATION", + "subtype" : 1 + } + }, "upgrades": ["vampireLord"], "graphics" : { @@ -134,7 +159,7 @@ "move": "VAMPMOVE.wav", "wince": "VAMPWNCE.wav", "startMoving": "VAMPEXT1.wav", - "stopMoving": "VAMPEXT2.wav" + "endMoving": "VAMPEXT2.wav" } }, "vampireLord" : @@ -142,8 +167,19 @@ "id": 63, "level": 4, "faction": "necropolis", - "abilities": [ [ "LIFE_DRAIN", 100, 0, 0 ], //drain 100% of damage dealt - [ "BLOCKS_RETALIATION", 0, 0, 0 ] ], + "abilities": + { + "noRetalitation" : + { + "type" : "BLOCKS_RETALIATION", + "subtype" : 1 + }, + "drainsLife" : + { + "type" : "LIFE_DRAIN", + "val" : 100 + } + }, "graphics" : { "animation": "CNOSFE.DEF" @@ -156,8 +192,8 @@ "move": "NOSFMOVE.wav", "shoot": "NOSFSHOT.wav", "wince": "NOSFWNCE.wav", - "ext1": "NOSFEXT1.wav", - "ext2": "NOSFEXT2.wav" + "startMoving": "NOSFEXT1.wav", + "endMoving": "NOSFEXT2.wav" } }, "lich" : @@ -165,15 +201,21 @@ "id": 64, "level": 5, "faction": "necropolis", - "abilities": [ [ "SPELL_LIKE_ATTACK", 0, "spell.deathCloud", 0 ] ], + "abilities": + { + "deathCloud" : + { + "type" : "SPELL_LIKE_ATTACK", + "subtype" : "spell.deathCloud" + } + }, "upgrades": ["powerLich"], "graphics" : { "animation": "CLICH.DEF", "missile" : { - "projectile": "PLICH.DEF", - "spinning": false + "projectile": "PLICH.DEF" } }, "sound" : @@ -183,8 +225,7 @@ "killed": "LICHKILL.wav", "move": "LICHMOVE.wav", "shoot": "LICHSHOT.wav", - "wince": "LICHWNCE.wav", - "ext1": "LICHATK2.wav" + "wince": "LICHWNCE.wav" } }, "powerLich" : @@ -192,14 +233,20 @@ "id": 65, "level": 5, "faction": "necropolis", - "abilities": [ [ "SPELL_LIKE_ATTACK", 0, "spell.deathCloud", 0 ] ], //power liches + "abilities": + { + "deathCloud" : + { + "type" : "SPELL_LIKE_ATTACK", + "subtype" : "spell.deathCloud" + } + }, "graphics" : { "animation": "CPLICH.DEF", "missile" : { - "projectile": "PLICH.DEF", - "spinning": false + "projectile": "PLICH.DEF" } }, "sound" : @@ -217,7 +264,15 @@ "id": 66, "level": 6, "faction": "necropolis", - "abilities": [ [ "SPELL_AFTER_ATTACK", 20, "spell.curse", 0 ] ], + "abilities": + { + "curses" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.curse", + "val" : 20 + } + }, "upgrades": ["dreadKnight"], "graphics" : { @@ -237,8 +292,20 @@ "id": 67, "level": 6, "faction": "necropolis", - "abilities": [ [ "SPELL_AFTER_ATTACK", 20, "spell.curse", 0 ], - [ "DOUBLE_DAMAGE_CHANCE", 20, 0, 0 ] ], + "abilities": + { + "curses" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.curse", + "val" : 20 + }, + "deathStrike" : + { + "type" : "DOUBLE_DAMAGE_CHANCE", + "val" : 20 + } + }, "graphics" : { "animation": "CBLORD.DEF" @@ -257,7 +324,13 @@ "id": 68, "level": 7, "faction": "necropolis", - "abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ] ], //bone dragon is a dragon + "abilities" : + { + "dragon" : + { + "type" : "DRAGON_NATURE" + } + }, "upgrades": ["ghostDragon"], "graphics" : { @@ -277,8 +350,19 @@ "id": 69, "level": 7, "faction": "necropolis", - "abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ], //ghost dragon is a dragon - [ "SPELL_AFTER_ATTACK", 20, "spell.age", 0 ] ], + "abilities": + { + "dragon" : + { + "type" : "DRAGON_NATURE" + }, + "age" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.age", + "val" : 20 + } + }, "graphics" : { "animation": "CHDRGN.DEF" diff --git a/config/creatures/neutral.json b/config/creatures/neutral.json index 44ec57ac1..48e6f82f1 100644 --- a/config/creatures/neutral.json +++ b/config/creatures/neutral.json @@ -5,8 +5,19 @@ "id": 116, "level": 4, "faction": "neutral", - "abilities": [ [ "SPELL_DAMAGE_REDUCTION", 85, -1, 0 ], //gold golems reduce dmg from spells - [ "NON_LIVING", 0, 0, 0 ] ], //diamond golems are non-living + "abilities": + { + "magicResistance" : + { + "type" : "SPELL_DAMAGE_REDUCTION", + "subtype" : -1, + "val" : 85 + }, + "nonliving" : + { + "type" : "NON_LIVING" + } + }, "graphics" : { "animation": "CGGOLE.DEF" @@ -25,8 +36,19 @@ "id": 117, "level": 5, "faction": "neutral", - "abilities": [ [ "SPELL_DAMAGE_REDUCTION", 95, -1, 0 ], //diamond golems reduce dmg from spells - [ "NON_LIVING", 0, 0, 0 ] ], + "abilities": + { + "magicResistance" : + { + "type" : "SPELL_DAMAGE_REDUCTION", + "subtype" : -1, + "val" : 95 + }, + "nonliving" : + { + "type" : "NON_LIVING" + } + }, "graphics" : { "animation": "CDGOLE.DEF" @@ -46,11 +68,30 @@ "id": 132, "level": 10, "faction": "neutral", - "abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ], - [ "TWO_HEX_ATTACK_BREATH", 0, 0, 0 ], //azure dragon's breath - [ "FEARLESS", 0, 0, 0 ], //azure dragon is immune to fear - [ "LEVEL_SPELL_IMMUNITY", 3, 0, 0 ], //immunity spell levels 1-3 - [ "FEAR", 0, 0, 0]], //azure dragon is a dragon + "abilities": + { + "dragon" : + { + "type" : "DRAGON_NATURE" + }, + "fireBreath" : + { + "type" : "TWO_HEX_ATTACK_BREATH" + }, + "spellImmunity" : + { + "type" : "LEVEL_SPELL_IMMUNITY", + "val" : 3 + }, + "fearless" : + { + "type" : "FEARLESS" + }, + "fear" : + { + "type" : "FEAR" + } + }, "graphics" : { "animation": "CADRGN.DEF" @@ -70,8 +111,14 @@ "id": 133, "level": 10, "faction": "neutral", - "abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ] ], //crystal dragon is a dragon - "ability_remove": [ "FLYING" ], //Crystal Dragons do not fly + "abilities": + { + "dragon" : + { + "type" : "DRAGON_NATURE" + }, + "FLYING" : null + }, "graphics" : { "animation": "CCDRGN.DEF" @@ -91,18 +138,84 @@ "id": 134, "level": 8, "faction": "neutral", - "abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ], //faerie dragon is a dragon - [ "MAGIC_MIRROR", 30, 0, 0 ], - [ "CASTS", 5, 0, 0 ], - [ "CREATURE_SPELL_POWER", 500, 0, 0], //5 spell power per dragon - [ "SPELLCASTER", 2, "spell.magicArrow", 10 ], - [ "SPELLCASTER", 2, "spell.iceBolt", 22 ], - [ "SPELLCASTER", 2, "spell.lightningBolt", 22 ], - [ "SPELLCASTER", 2, "spell.chainLightning", 5 ], - [ "SPELLCASTER", 2, "spell.frostRing", 10 ], - [ "SPELLCASTER", 2, "spell.fireball", 21 ], - [ "SPELLCASTER", 2, "spell.inferno", 5 ], - [ "SPELLCASTER", 2, "spell.meteorShower", 5 ]], + "abilities": + { + "dragon" : + { + "type" : "DRAGON_NATURE", + }, + "mirror" : + { + "type" : "MAGIC_MIRROR", + "val" : 30 + }, + "casts" : + { + "type" : "CASTS", + "val" : 5 + }, + "spellpower" : + { + "type" : "CREATURE_SPELL_POWER", + "val" : 500 + }, + "castsMagicArrow" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.magicArrow", + "addInfo" : 22, + "val" : 2 + }, + "castsIceBolt" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.iceBolt", + "addInfo" : 22, + "val" : 2 + }, + "castsLightningBolt" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.lightningBolt", + "addInfo" : 22, + "val" : 2 + }, + "castsChainLightning" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.chainLightning", + "addInfo" : 5, + "val" : 2 + }, + "castsFrostRing" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.frostRing", + "addInfo" : 10, + "val" : 2 + }, + "castsFireball" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.fireball", + "addInfo" : 21, + "val" : 2 + }, + "castsInferno" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.inferno", + "addInfo" : 5, + "val" : 2 + }, + "castsMeteorShower" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.meteorShower", + "addInfo" : 5, + "val" : 2 + } + }, "graphics" : { "animation": "CFDRGN.DEF" @@ -123,9 +236,25 @@ "id": 135, "level": 10, "faction": "neutral", - "abilities": [ [ "SPELL_AFTER_ATTACK", 100, 80, 0 ], //always reduce defense - [ "ACID_BREATH", 25, 0, 20 ], //20% chance to do 25 damage - [ "DRAGON_NATURE", 0, 0, 0 ] ], //rust dragon is a dragon + "abilities": + { + "dragon" : + { + "type" : "DRAGON_NATURE" + }, + "acidBreath" : + { + "type" : "ACID_BREATH", + "val" : 25, + "addInfo" : 20 + }, + "reduceDefence" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.acidBreath", + "val" : 100 + } + }, "graphics" : { "animation": "CRSDGN.DEF" @@ -146,21 +275,67 @@ "level": 6, "extraNames": [ "enchanters" ], "faction": "neutral", - "abilities": [ [ "NO_WALL_PENALTY", 0, 0, 0 ], - [ "ENCHANTER", 3, "spell.airShield", 3], - [ "ENCHANTER", 3, "spell.bless", 3], - [ "ENCHANTER", 3, "spell.weakness", 3], - [ "ENCHANTER", 3, "spell.stoneSkin", 3], - [ "ENCHANTER", 3, "spell.slow", 3], - [ "ENCHANTER", 3, "spell.haste", 3], - [ "CASTS", 5, 0, 0]], + "abilities": + { + "noPenalty" : + { + "type" : "NO_WALL_PENALTY" + }, + "casts" : + { + "type" : "CASTS", + "val" : 5 + }, + "castsAirShield" : + { + "type" : "ENCHANTER", + "subtype" : "spell.airShield", + "val" : 3, + "addInfo" : 3 + }, + "castsBless" : + { + "type" : "ENCHANTER", + "subtype" : "spell.bless", + "val" : 3, + "addInfo" : 3 + }, + "castsWeakness" : + { + "type" : "ENCHANTER", + "subtype" : "spell.weakness", + "val" : 3, + "addInfo" : 3 + }, + "castsStoneSkin" : + { + "type" : "ENCHANTER", + "subtype" : "spell.stoneSkin", + "val" : 3, + "addInfo" : 3 + }, + "castsSlow" : + { + "type" : "ENCHANTER", + "subtype" : "spell.slow", + "val" : 3, + "addInfo" : 3 + }, + "castsHaste" : + { + "type" : "ENCHANTER", + "subtype" : "spell.haste", + "val" : 3, + "addInfo" : 3 + } + + }, "graphics" : { - "animation": "CENCH.DEF", + "animation": "CGTITA.DEF", "missile" : { - "projectile": "CPRZEAX.DEF", - "spinning": false + "projectile": "CPRZEAX.DEF" } }, "sound" : @@ -180,15 +355,23 @@ "level": 4, "extraNames": [ "sharpshooters" ], "faction": "neutral", - "abilities": [ [ "NO_WALL_PENALTY", 0, 0, 0 ], - [ "NO_DISTANCE_PENALTY", 0, 0, 0 ] ], + "abilities": + { + "noPenalty" : + { + "type" : "NO_WALL_PENALTY" + }, + "noDistancePenalty" : + { + "type" : "NO_DISTANCE_PENALTY" + } + }, "graphics" : { "animation": "CSHARP.DEF", "missile" : { - "projectile": "PELFX.DEF", - "spinning": false + "projectile": "PELFX.DEF" } }, "sound" : @@ -211,8 +394,7 @@ "animation": "CHALF.DEF", "missile" : { - "projectile": "PHALF.DEF", - "spinning": true + "projectile": "PHALF.DEF" } }, "sound" : @@ -248,7 +430,7 @@ "id": 140, "level": 2, "faction": "neutral", - "abilities": [ [ "DOUBLE_WIDE", 0, 0, 0 ] ], //boar should be treated as double-wide + "doubleWide" : true, "graphics" : { "animation": "CBOAR.DEF" @@ -267,7 +449,13 @@ "id": 141, "level": 3, "faction": "neutral", - "abilities": [ [ "UNDEAD", 0, 0, 0 ] ], + "abilities": + { + "undead" : + { + "type" : "UNDEAD" + } + }, "graphics" : { "animation": "CMUMMY.DEF" @@ -286,7 +474,7 @@ "id": 142, "level": 3, "faction": "neutral", - "abilities": [ [ "DOUBLE_WIDE", 0, 0, 0 ] ], //nomads should be treated as double-wide + "doubleWide" : true, "graphics" : { "animation": "CNOMAD.DEF" @@ -323,7 +511,13 @@ "id": 144, "level": 5, "faction": "neutral", - "abilities": [ [ "FULL_HP_REGENERATION", 0, 0, 0 ] ], + "abilities": + { + "regenerates" : + { + "type" : "FULL_HP_REGENERATION" + } + }, "graphics" : { "animation": "CTROLL.DEF" diff --git a/config/creatures/rampart.json b/config/creatures/rampart.json index c3474b903..6563ac6a2 100644 --- a/config/creatures/rampart.json +++ b/config/creatures/rampart.json @@ -8,6 +8,7 @@ "hasDoubleWeek": true, "graphics" : { + "missile" : null, "animation": "CCENTR.DEF" }, "sound" : @@ -27,6 +28,7 @@ "faction": "rampart", "graphics" : { + "missile" : null, "animation": "CECENT.DEF" }, "sound" : @@ -43,7 +45,14 @@ "id": 16, "level": 2, "faction": "rampart", - "abilities": [ [ "MAGIC_RESISTANCE", 20, 0, 0 ] ], //dwarf's magic resistance 20% + "abilities": + { + "magicResistance" : + { + "type" : "MAGIC_RESISTANCE", + "val" : 20 + } + }, "upgrades": ["battleDwarf"], "graphics" : { @@ -63,7 +72,14 @@ "id": 17, "level": 2, "faction": "rampart", - "abilities": [ [ "MAGIC_RESISTANCE", 40, 0, 0 ] ], //battle dwarf's magic resistance 40% + "abilities": + { + "magicResistance" : + { + "type" : "MAGIC_RESISTANCE", + "val" : 40 + } + }, "graphics" : { "animation": "CBDWAR.DEF" @@ -88,8 +104,7 @@ "animation": "CELF.DEF", "missile" : { - "projectile": "PELFX.DEF", - "spinning": false + "projectile": "PELFX.DEF" } }, "sound" : @@ -107,20 +122,21 @@ "id": 19, "level": 3, "faction": "rampart", - "abilities": [ - { - "type": "ADDITIONAL_ATTACK", - "val" : 1, - "effectRange": "ONLY_DISTANCE_FIGHT" - } - ], + "abilities": + { + "doubleShot" : + { + "type": "ADDITIONAL_ATTACK", + "val" : 1, + "effectRange": "ONLY_DISTANCE_FIGHT" + } + }, "graphics" : { "animation": "CGRELF.DEF", "missile" : { - "projectile": "PELFX.DEF", - "spinning": false + "projectile": "PELFX.DEF" } }, "sound" : @@ -138,7 +154,14 @@ "id": 20, "level": 4, "faction": "rampart", - "abilities": [ [ "CHANGES_SPELL_COST_FOR_ENEMY", 2, 0, 0 ] ], //pegasus makes spell cost higher for enemy mage + "abilities": + { + "increaseManaCost" : + { + "type" : "CHANGES_SPELL_COST_FOR_ENEMY", + "val" : 2 + } + }, "upgrades": ["silverPegasus"], "hasDoubleWeek": true, "graphics" : @@ -159,7 +182,14 @@ "id": 21, "level": 4, "faction": "rampart", - "abilities": [ [ "CHANGES_SPELL_COST_FOR_ENEMY", 2, 0, 0 ] ], //silver pegasus makes spell cost higher for enemy mage + "abilities": + { + "increaseManaCost" : + { + "type" : "CHANGES_SPELL_COST_FOR_ENEMY", + "val" : 2 + } + }, "graphics" : { "animation": "CAPEGS.DEF" @@ -178,7 +208,15 @@ "id": 22, "level": 5, "faction": "rampart", - "abilities": [ [ "SPELL_AFTER_ATTACK", 100, "spell.bind", 0 ] ], //dendroids cast bind + "abilities": + { + "binds" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.bind", + "val" : 100 + } + }, "upgrades": ["dendroidSoldier"], "graphics" : { @@ -198,7 +236,15 @@ "id": 23, "level": 5, "faction": "rampart", - "abilities": [ [ "SPELL_AFTER_ATTACK", 100, "spell.bind", 0 ] ], //dendroid guards cast bind + "abilities": + { + "binds" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.bind", + "val" : 100 + } + }, "graphics" : { "animation": "CBTREE.DEF" @@ -217,8 +263,20 @@ "id": 24, "level": 6, "faction": "rampart", - "abilities": [ [ "SPELL_RESISTANCE_AURA", 0, 55, 0 ], //unicorn - [ "SPELL_AFTER_ATTACK", 20, "spell.blind", 0 ] ], //unicorns cast blind with 20% probability + "abilities": + { + "spellResistAura" : + { + "type" : "SPELL_RESISTANCE_AURA", + "val" : 20 + }, + "blinds" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.blind", + "val" : 20 + } + }, "upgrades": ["warUnicorn"], "graphics" : { @@ -238,8 +296,20 @@ "id": 25, "level": 6, "faction": "rampart", - "abilities": [ [ "SPELL_RESISTANCE_AURA", 20, 55, 0 ], //war unicorn - [ "SPELL_AFTER_ATTACK", 20, "spell.blind", 0 ] ], //war unicorns cast blind with 20% probability + "abilities": + { + "spellResistAura" : + { + "type" : "SPELL_RESISTANCE_AURA", + "val" : 20 + }, + "blinds" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.blind", + "val" : 20 + } + }, "graphics" : { "animation": "CWUNIC.DEF" @@ -259,9 +329,22 @@ "id": 26, "level": 7, "faction": "rampart", - "abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ], //green dragon is a dragon - [ "TWO_HEX_ATTACK_BREATH", 0, 0, 0 ], //green dragon's breath - [ "LEVEL_SPELL_IMMUNITY", 3, 0, 0 ] ], //green dragon's spell immunity + "abilities": + { + "dragon" : + { + "type" : "DRAGON_NATURE" + }, + "fireBreath" : + { + "type" : "TWO_HEX_ATTACK_BREATH" + }, + "spellImmunity" : + { + "type" : "LEVEL_SPELL_IMMUNITY", + "val" : 3 + } + }, "upgrades": ["goldDragon"], "graphics" : { @@ -281,9 +364,22 @@ "id": 27, "level": 7, "faction": "rampart", - "abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ], //gold dragon is a dragon - [ "TWO_HEX_ATTACK_BREATH", 0, 0, 0 ], //gold dragon's breath - [ "LEVEL_SPELL_IMMUNITY", 4, 0, 0 ] ], //gold dragon's spell immunity + "abilities": + { + "dragon" : + { + "type" : "DRAGON_NATURE" + }, + "fireBreath" : + { + "type" : "TWO_HEX_ATTACK_BREATH" + }, + "spellImmunity" : + { + "type" : "LEVEL_SPELL_IMMUNITY", + "val" : 4 + } + }, "graphics" : { "animation": "CDDRAG.DEF" diff --git a/config/creatures/special.json b/config/creatures/special.json index 9eb7e2ea6..9c6b3ae7f 100644 --- a/config/creatures/special.json +++ b/config/creatures/special.json @@ -4,25 +4,29 @@ "unused122" : { "faction": "neutral", - "special" : true, + "disabled" : true, + "graphics" : null, "id" : 122 }, "unused124" : { "faction": "neutral", - "special" : true, + "disabled" : true, + "graphics" : null, "id" : 124 }, "unused126" : { "faction": "neutral", - "special" : true, + "disabled" : true, + "graphics" : null, "id" : 126 }, "unused128" : { "faction": "neutral", - "special" : true, + "disabled" : true, + "graphics" : null, "id" : 128 }, @@ -37,8 +41,7 @@ "animation": "SMCATA.DEF", "missile" : { - "projectile": "SMCATX.DEF", - "spinning": true + "projectile": "SMCATX.DEF" } }, "sound" : @@ -59,8 +62,7 @@ "animation": "SMBAL.DEF", "missile" : { - "projectile": "SMBALX.DEF", - "spinning": false + "projectile": "SMBALX.DEF" } }, "sound" : @@ -76,7 +78,7 @@ "id": 147, "level": 0, "faction": "neutral", - "abilities": [ [ "HEALER", 0, 0, 0 ] ], + "abilities": { "heals" : { "type" : "HEALER" } }, "graphics" : { "animation": "SMTENT.DEF" @@ -93,7 +95,7 @@ "id": 148, "level": 0, "faction": "neutral", - "abilities": [ [ "NOT_ACTIVE", 0, 0, 0 ] ], + "abilities": { "inactive" : { "type" : "NOT_ACTIVE" } }, "graphics" : { "animation": "SMCART.DEF" @@ -110,13 +112,11 @@ "id": 149, "level": 0, "faction": "neutral", - "abilities": [ [ "SHOOTER", 0, 0, 0 ] ], + "abilities": { "shooter" : { "type" : "SHOOTER" } }, "graphics" : { - "missile" : - { - "projectile": "SMBALX.DEF", //workaround for crash - } - } + "animation" : "This should never be used" + }, + "sound": {} } } diff --git a/config/creatures/stronghold.json b/config/creatures/stronghold.json index e071cc538..736c7509c 100644 --- a/config/creatures/stronghold.json +++ b/config/creatures/stronghold.json @@ -63,7 +63,14 @@ "id": 87, "level": 2, "faction": "stronghold", - "abilities": [ [ "ADDITIONAL_ATTACK", 1, 0, 0 ] ], + "abilities": + { + "extraAttack" : + { + "type" : "ADDITIONAL_ATTACK", + "val" : 1 + } + }, "graphics" : { "animation": "CUWLFR.DEF" @@ -88,8 +95,7 @@ "animation": "CORC.DEF", "missile" : { - "projectile": "PORCHX.DEF", - "spinning": true + "projectile": "PORCHX.DEF" } }, "sound" : @@ -112,8 +118,7 @@ "animation": "CORCCH.DEF", "missile" : { - "projectile": "PORCHX.DEF", - "spinning": true + "projectile": "PORCHX.DEF" } }, "sound" : @@ -150,9 +155,25 @@ "id": 91, "level": 4, "faction": "stronghold", - "abilities": [ [ "SPELLCASTER", 2, "spell.bloodlust", 0 ], - [ "CASTS", 3, 0, 0], - [ "CREATURE_ENCHANT_POWER", 3, 0, 0]], + "abilities": + { + "castsBloodlust" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.bloodlust", + "val" : 2 + }, + "castsCount" : + { + "type" : "CASTS", + "val" : 3 + }, + "castLength" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 3 + } + }, "graphics" : { "animation": "COGMAG.DEF" @@ -191,8 +212,21 @@ "id": 93, "level": 5, "faction": "stronghold", - "abilities": [ [ "SPECIFIC_SPELL_POWER", 10, "spell.thunderbolt", 0 ], //10 damage per unit - [ "SPELL_AFTER_ATTACK", 20, "spell.thunderbolt", 0 ] ], + "abilities": + { + "thunderStrength" : + { + "type" : "SPECIFIC_SPELL_POWER", + "subtype" : "spell.thunderbolt", + "val" : 10 + }, + "thunderOnAttack" : + { + "type" : "SPELL_AFTER_ATTACK", + "subtype" : "spell.thunderbolt", + "val" : 20 + } + }, "graphics" : { "animation": "CTBIRD.DEF" @@ -217,8 +251,7 @@ "animation": "CCYCLR.DEF", "missile" : { - "projectile": "PCYCLBX.DEF", - "spinning": true + "projectile": "PCYCLBX.DEF" } }, "sound" : @@ -241,8 +274,7 @@ "animation": "CCYCLLOR.DEF", "missile" : { - "projectile": "PCYCLBX.DEF", - "spinning": true + "projectile": "PCYCLBX.DEF" } }, "sound" : @@ -260,7 +292,14 @@ "id": 96, "level": 7, "faction": "stronghold", - "abilities": [ [ "ENEMY_DEFENCE_REDUCTION", 40, 0, 0 ] ], + "abilities": + { + "reduceDefence" : + { + "type" : "ENEMY_DEFENCE_REDUCTION", + "val" : 40 + } + }, "upgrades": ["ancientBehemoth"], "graphics" : { @@ -280,7 +319,14 @@ "id": 97, "level": 7, "faction": "stronghold", - "abilities": [ [ "ENEMY_DEFENCE_REDUCTION", 80, 0, 0 ] ], + "abilities": + { + "reduceDefence" : + { + "type" : "ENEMY_DEFENCE_REDUCTION", + "val" : 80 + } + }, "graphics" : { "animation": "CABEHE.DEF" diff --git a/config/creatures/tower.json b/config/creatures/tower.json index 046ad73a9..69d241669 100644 --- a/config/creatures/tower.json +++ b/config/creatures/tower.json @@ -31,8 +31,7 @@ "animation": "CGREMM.DEF", "missile" : { - "projectile": "CPRGRE.DEF", - "spinning": false + "projectile": "CPRGRE.DEF" } }, "sound" : @@ -50,7 +49,13 @@ "id": 30, "level": 2, "faction": "tower", - "abilities": [ [ "NON_LIVING", 0, 0, 0 ] ], //stone gargoyles are non-living + "abilities": + { + "nonliving" : + { + "type" : "NON_LIVING" + } + }, "upgrades": ["obsidianGargoyle"], "graphics" : { @@ -70,7 +75,13 @@ "id": 31, "level": 2, "faction": "tower", - "abilities": [ [ "NON_LIVING", 0, 0, 0 ] ], //obsidian gargoyles are non-living + "abilities": + { + "nonliving" : + { + "type" : "NON_LIVING" + } + }, "graphics" : { "animation": "COGARG.DEF" @@ -89,8 +100,19 @@ "id": 32, "level": 3, "faction": "tower", - "abilities": [ [ "SPELL_DAMAGE_REDUCTION", 50, -1, 0 ], //stone golems reduce dmg from spells - [ "NON_LIVING", 0, 0, 0 ] ], //stone golems are non-living + "abilities": + { + "magicResistance" : + { + "type" : "SPELL_DAMAGE_REDUCTION", + "subtype" : -1, + "val" : 50 + }, + "nonliving" : + { + "type" : "NON_LIVING" + } + }, "upgrades": ["stoneGolem"], "graphics" : { @@ -110,8 +132,19 @@ "id": 33, "level": 3, "faction": "tower", - "abilities": [ [ "SPELL_DAMAGE_REDUCTION", 75, -1, 0 ], //iron golems reduce dmg from spells - [ "NON_LIVING", 0, 0, 0 ] ], //iron golems are non-living + "abilities" : + { + "magicResistance" : + { + "type" : "SPELL_DAMAGE_REDUCTION", + "subtype" : -1, + "val" : 75 + }, + "nonliving" : + { + "type" : "NON_LIVING" + } + }, "graphics" : { "animation": "CIGOLE.DEF" @@ -130,15 +163,21 @@ "id": 34, "level": 4, "faction": "tower", - "abilities": [ [ "CHANGES_SPELL_COST_FOR_ALLY", 2, 0, 0 ] ], //mages reduce spell cost + "abilities": + { + "reduceSpellCost" : + { + "type" : "CHANGES_SPELL_COST_FOR_ALLY", + "val" : 2 + } + }, "upgrades": ["archMage"], "graphics" : { "animation": "CMAGE.DEF", "missile" : { - "projectile": "PMAGEX.DEF", - "spinning": false + "projectile": "PMAGEX.DEF" } }, "sound" : @@ -156,14 +195,20 @@ "id": 35, "level": 4, "faction": "tower", - "abilities": [ [ "CHANGES_SPELL_COST_FOR_ALLY", 2, 0, 0 ]], //archmages reduce spell cost + "abilities": + { + "reduceSpellCost" : + { + "type" : "CHANGES_SPELL_COST_FOR_ALLY", + "val" : 2 + } + }, "graphics" : { "animation": "CAMAGE.DEF", "missile" : { - "projectile": "PMAGEX.DEF", - "spinning": false + "projectile": "PMAGEX.DEF" } }, "sound" : @@ -181,8 +226,21 @@ "id": 36, "level": 5, "faction": "tower", - "abilities": [ [ "HATE", 50, 53, 0 ], //master genies hate efreets - [ "HATE", 50, 52, 0 ] ], //genies hate efreet sultans + "abilities": + { + "hateAngels" : + { + "type" : "HATE", + "subtype" : "creature.efreet", + "val" : 50 + }, + "hateArchAngels" : + { + "type" : "HATE", + "subtype" : "creature.efreetSultan", + "val" : 50 + } + }, "upgrades": ["masterGenie"], "graphics" : { @@ -202,11 +260,36 @@ "id": 37, "level": 5, "faction": "tower", - "abilities": [ [ "CREATURE_ENCHANT_POWER", 5, 0, 0 ], //spells last 5 turns - [ "RANDOM_SPELLCASTER", 2, 0, 0 ], //master genies cast spells on advanced level - [ "CASTS", 3, 0, 0], - [ "HATE", 50, 53, 0 ], - [ "HATE", 50, 52, 0 ] ], //master genies hate efreet sultans + "abilities": + { + "hateAngels" : + { + "type" : "HATE", + "subtype" : "creature.efreet", + "val" : 50 + }, + "hateArchAngels" : + { + "type" : "HATE", + "subtype" : "creature.efreetSultan", + "val" : 50 + }, + "spellsLength" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 5 + }, + "randomSpellcaster" : + { + "type" : "RANDOM_SPELLCASTER", + "val" : 2 + }, + "casts" : + { + "type" : "CASTS", + "val" : 3 + } + }, "graphics" : { "animation": "CSULTA.DEF" @@ -226,7 +309,13 @@ "id": 38, "level": 6, "faction": "tower", - "abilities": [ [ "BLOCKS_RETALIATION", 0, 0, 0 ] ], //nagas block retaliation + "abilities" : + { + "noRetaliation" : + { + "type" : "BLOCKS_RETALIATION" + } + }, "upgrades": ["nagaQueen"], "graphics" : { @@ -246,7 +335,13 @@ "id": 39, "level": 6, "faction": "tower", - "abilities": [ [ "BLOCKS_RETALIATION", 0, 0, 0 ] ], //naga queens block retaliation + "abilities" : + { + "noRetaliation" : + { + "type" : "BLOCKS_RETALIATION" + } + }, "graphics" : { "animation": "CNAGAG.DEF" @@ -265,7 +360,13 @@ "id": 40, "level": 7, "faction": "tower", - "abilities": [ ["MIND_IMMUNITY", 0, 0, 0] ], //giants are immune to mind spells + "abilities" : + { + "immuneToMind" : + { + "type" : "MIND_IMMUNITY" + } + }, "upgrades": ["titan"], "graphics" : { @@ -285,15 +386,25 @@ "id": 41, "level": 7, "faction": "tower", - "abilities": [ ["MIND_IMMUNITY", 0, 0, 0], //Titans are immune to mind spells - [ "HATE", 50, "creature.blackDragon", 0 ] ], //titans hate black dragons + "abilities" : + { + "immuneToMind" : + { + "type" : "MIND_IMMUNITY" + }, + "hateArchAngels" : + { + "type" : "HATE", + "subtype" : "creature.blackDragon", + "val" : 50 + } + }, "graphics" : { "animation": "CGTITA.DEF", "missile" : { - "projectile": "CPRGTIX.DEF", - "spinning": false + "projectile": "CPRGTIX.DEF" } }, "sound" : diff --git a/config/creatures/wog.json b/config/creatures/wog.json index 33bc3f7fd..a65ba9fcc 100644 --- a/config/creatures/wog.json +++ b/config/creatures/wog.json @@ -22,7 +22,13 @@ "id": 151, "level": 8, "faction": "rampart", - "abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ] ], //diamond dragon is a dragon + "abilities": + { + "dragon" : + { + "type" : "DRAGON_NATURE" + } + }, "graphics" : { "animation": "ZM151Z.DEF" @@ -46,8 +52,7 @@ "animation": "ZM152Z.DEF", "missile" : { - "projectile": "CPRGTIX.DEF", - "spinning": false + "projectile": "CPRGTIX.DEF" } }, "sound" : @@ -65,9 +70,17 @@ "id": 153, "level": 8, "faction": "inferno", - "abilities": [ [ "FLYING", 0, 1, 0 ] ], + "abilities": + { + "teleport" : + { + "type" : "FLYING", + "subtype" : 1 + } + }, "graphics" : { + "missile" : null, "animation": "ZM153Z.DEF" }, "sound" : @@ -78,7 +91,7 @@ "move": "ADVLMOVE.wav", "wince": "ADVLWNCE.wav", "startMoving": "ADVLEXT1.wav", - "stopMoving": "ADVLEXT2.wav" + "endMoving": "ADVLEXT2.wav" } }, "bloodDragon" : @@ -86,8 +99,18 @@ "id": 154, "level": 8, "faction": "necropolis", - "abilities": [ [ "LIFE_DRAIN", 40, 0, 0 ], //40% - [ "DRAGON_NATURE", 0, 0, 0 ] ], //blood dragon is a dragon + "abilities": + { + "drainsLife" : + { + "type" : "LIFE_DRAIN", + "val" : 40 + }, + "dragon" : + { + "type" : "DRAGON_NATURE" + } + }, "graphics" : { "animation": "ZM154Z.DEF" @@ -106,7 +129,13 @@ "id": 155, "level": 8, "faction": "dungeon", - "abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ] ], //darkness dragon is a dragon + "abilities": + { + "dragon" : + { + "type" : "DRAGON_NATURE" + } + }, "graphics" : { "animation": "ZM155Z.DEF" @@ -143,7 +172,10 @@ "id": 157, "level": 8, "faction": "fortress", - "ability_remove": [ "SHOOTER" ], //Hell Hydra certainly does not shoot + "abilities" : + { + "SHOOTER" : null + }, "graphics" : { "animation": "ZM157Z.DEF" @@ -195,7 +227,7 @@ }, "godWar" : { - "special" : true, + "disabled" : true, "id": 160, "level": 0, "faction": "neutral", @@ -206,7 +238,7 @@ }, "godPeace" : { - "special" : true, + "disabled" : true, "id": 161, "level": 0, "faction": "neutral", @@ -217,7 +249,7 @@ }, "godMana" : { - "special" : true, + "disabled" : true, "id": 162, "level": 0, "faction": "neutral", @@ -228,7 +260,7 @@ }, "godLore" : { - "special" : true, + "disabled" : true, "id": 163, "level": 0, "faction": "neutral", @@ -314,7 +346,13 @@ "id": 168, "level": 0, "faction": "neutral", - "abilities": [ [ "FLYING", 0, 0, 0 ] ], //Gorynyches fly + "abilities": + { + "canFly" : + { + "type" : "FLYING" + } + }, "graphics" : { "animation": "ZM168DG.DEF" @@ -338,8 +376,7 @@ "animation": "ZM169ZL.DEF", "missile" : { - "projectile": "CPRZEAX.DEF", - "spinning": false + "projectile": "CPRZEAX.DEF" } }, "sound" : @@ -362,8 +399,7 @@ "animation": "ZM170SW.DEF", "missile" : { - "projectile": "PLCBOWX.DEF", - "spinning": false + "projectile": "PLCBOWX.DEF" } }, "sound" : @@ -386,8 +422,7 @@ "animation": "ZM171SR.DEF", "missile" : { - "projectile": "PLCBOWX.DEF", - "spinning": false + "projectile": "PLCBOWX.DEF" } }, "sound" : @@ -425,12 +460,11 @@ "faction": "neutral", "graphics" : { - "animation": "ZM173M.DEF", - "missile" : - { - "projectile": "CPRGRE.DEF", - "spinning": true - } + "animation": "ZM173M.DEF" + //"missile" : + //{ + // "projectile": "CPRGRE.DEF" + //} }, "sound" : { @@ -460,7 +494,7 @@ "projectile": "PLCBOWX.DEF" } }, - "sounds" : + "sound" : { "attack": "CRUSATTK.wav", "defend": "CRUSDFND.wav", @@ -475,11 +509,35 @@ "id": 175, "level": 0, "faction": "neutral", - "abilities": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ], - [ "CASTS", 1, 0, 0 ] , - [ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] , - [ "CREATURE_SPELL_POWER", 100, 0, 0 ] , - [ "SPELLCASTER", 3, "spell.shield", 0 ] ], //expert shield + "abilities": + { + "magicResistance" : + { + "type" : "MAGIC_RESISTANCE", + "val" : 5 + }, + "castsAmount" : + { + "type" : "CASTS", + "val" : 1 + }, + "enchant" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 1 + }, + "spellpower" : + { + "type" : "CREATURE_SPELL_POWER", + "val" : 100 + }, + "canCast" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.shield", + "val" : 3 + } + }, "graphics" : { "animation": "ZM175NPC.DEF", @@ -488,7 +546,7 @@ "projectile": "CPRZEAX.DEF" } }, - "sounds" : + "sound" : { "attack": "MONKATTK.wav", "defend": "MONKDFND.wav", @@ -504,11 +562,35 @@ "id": 176, "level": 0, "faction": "neutral", - "abilities": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ], - [ "CASTS", 1, 0, 0 ] , - [ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] , - [ "CREATURE_SPELL_POWER", 100, 0, 0 ] , - [ "SPELLCASTER", 3, "spell.precision", 0 ] ], //expert precision + "abilities": + { + "magicResistance" : + { + "type" : "MAGIC_RESISTANCE", + "val" : 5 + }, + "castsAmount" : + { + "type" : "CASTS", + "val" : 1 + }, + "enchant" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 1 + }, + "spellpower" : + { + "type" : "CREATURE_SPELL_POWER", + "val" : 100 + }, + "canCast" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.precision", + "val" : 3 + } + }, "graphics" : { "animation": "ZM176NPC.DEF", @@ -517,15 +599,14 @@ "projectile": "PLCBOWX.DEF" } }, - "sounds" : + "sound" : { "attack": "LICHATTK.wav", "defend": "LICHDFND.wav", "killed": "LICHKILL.wav", "move": "LICHMOVE.wav", "shoot": "LICHSHOT.wav", - "wince": "LICHWNCE.wav", - "ext1": "LICHATK2.wav" + "wince": "LICHWNCE.wav" } }, "succubus1" : @@ -534,11 +615,35 @@ "id": 177, "level": 0, "faction": "neutral", - "abilities": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ], - [ "CASTS", 1, 0, 0 ] , - [ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] , - [ "CREATURE_SPELL_POWER", 100, 0, 0 ] , - [ "SPELLCASTER", 3, "spell.fireShield", 0 ] ], //expert fire shield + "abilities": + { + "magicResistance" : + { + "type" : "MAGIC_RESISTANCE", + "val" : 5 + }, + "castsAmount" : + { + "type" : "CASTS", + "val" : 1 + }, + "enchant" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 1 + }, + "spellpower" : + { + "type" : "CREATURE_SPELL_POWER", + "val" : 100 + }, + "canCast" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.fireShield", + "val" : 3 + } + }, "graphics" : { "animation": "ZM177NPC.DEF", @@ -547,7 +652,7 @@ "projectile": "PLCBOWX.DEF" } }, - "sounds" : + "sound" : { "attack": "SGRGATTK.wav", "defend": "SGRGDFND.wav", @@ -562,11 +667,35 @@ "id": 178, "level": 0, "faction": "neutral", - "abilities": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ], - [ "CASTS", 1, 0, 0 ] , - [ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] , - [ "CREATURE_SPELL_POWER", 100, 0, 0 ] , - [ "SPELLCASTER", 3, "spell.animateDead", 0 ] ], //expert animate dead + "abilities": + { + "magicResistance" : + { + "type" : "MAGIC_RESISTANCE", + "val" : 5 + }, + "castsAmount" : + { + "type" : "CASTS", + "val" : 1 + }, + "enchant" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 1 + }, + "spellpower" : + { + "type" : "CREATURE_SPELL_POWER", + "val" : 100 + }, + "canCast" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.animateDead", + "val" : 3 + } + }, "graphics" : { "animation": "ZM178NPC.DEF", @@ -575,7 +704,7 @@ "projectile": "PLCBOWX.DEF" } }, - "sounds" : + "sound" : { "attack": "GNOLATTK.wav", "defend": "GNOLDFND.wav", @@ -590,11 +719,35 @@ "id": 179, "level": 0, "faction": "neutral", - "abilities": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ], - [ "CASTS", 1, 0, 0 ] , - [ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] , - [ "CREATURE_SPELL_POWER", 100, 0, 0 ] , - [ "SPELLCASTER", 3, "spell.stoneSkin", 0 ] ], //expert stone skin + "abilities": + { + "magicResistance" : + { + "type" : "MAGIC_RESISTANCE", + "val" : 5 + }, + "castsAmount" : + { + "type" : "CASTS", + "val" : 1 + }, + "enchant" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 1 + }, + "spellpower" : + { + "type" : "CREATURE_SPELL_POWER", + "val" : 100 + }, + "canCast" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.stoneSkin", + "val" : 3 + } + }, "graphics" : { "animation": "ZM179NPC.DEF", @@ -603,7 +756,7 @@ "projectile": "PLCBOWX.DEF" } }, - "sounds" : + "sound" : { "attack": "PFOEATTK.wav", "defend": "PFOEDFND.wav", @@ -618,11 +771,35 @@ "id": 180, "level": 0, "faction": "neutral", - "abilities": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ], - [ "CASTS", 1, 0, 0 ] , - [ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] , - [ "CREATURE_SPELL_POWER", 100, 0, 0 ] , - [ "SPELLCASTER", 3, "spell.cure", 0 ] ], //expert cure + "abilities": + { + "magicResistance" : + { + "type" : "MAGIC_RESISTANCE", + "val" : 5 + }, + "castsAmount" : + { + "type" : "CASTS", + "val" : 1 + }, + "enchant" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 1 + }, + "spellpower" : + { + "type" : "CREATURE_SPELL_POWER", + "val" : 100 + }, + "canCast" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.cure", + "val" : 3 + } + }, "graphics" : { "animation": "ZM180NPC.DEF", @@ -631,7 +808,7 @@ "projectile": "PLCBOWX.DEF" } }, - "sounds" : + "sound" : { "attack": "TRLLATTK.wav", "defend": "TRLLDFND.wav", @@ -646,11 +823,35 @@ "id": 181, "level": 0, "faction": "neutral", - "abilities": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ], - [ "CASTS", 1, 0, 0 ] , - [ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] , - [ "CREATURE_SPELL_POWER", 100, 0, 0 ] , - [ "SPELLCASTER", 3, "spell.haste", 0 ] ], //expert haste + "abilities": + { + "magicResistance" : + { + "type" : "MAGIC_RESISTANCE", + "val" : 5 + }, + "castsAmount" : + { + "type" : "CASTS", + "val" : 1 + }, + "enchant" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 1 + }, + "spellpower" : + { + "type" : "CREATURE_SPELL_POWER", + "val" : 100 + }, + "canCast" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.haste", + "val" : 3 + } + }, "graphics" : { "animation": "ZM181NPC.DEF", @@ -659,7 +860,7 @@ "projectile": "PLCBOWX.DEF" } }, - "sounds" : + "sound" : { "attack": "AMAGATTK.wav", "defend": "AMAGDFND.wav", @@ -675,11 +876,35 @@ "id": 182, "level": 0, "faction": "neutral", - "abilities": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ], - [ "CASTS", 1, 0, 0 ] , - [ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] , - [ "CREATURE_SPELL_POWER", 100, 0, 0 ] , - [ "SPELLCASTER", 3, "spell.counterstrike", 0 ] ], //expert counterstrike + "abilities": + { + "magicResistance" : + { + "type" : "MAGIC_RESISTANCE", + "val" : 5 + }, + "castsAmount" : + { + "type" : "CASTS", + "val" : 1 + }, + "enchant" : + { + "type" : "CREATURE_ENCHANT_POWER", + "val" : 1 + }, + "spellpower" : + { + "type" : "CREATURE_SPELL_POWER", + "val" : 100 + }, + "canCast" : + { + "type" : "SPELLCASTER", + "subtype" : "spell.counterstrike", + "val" : 3 + } + }, "graphics" : { "animation": "ZM182NPC.DEF", @@ -688,7 +913,7 @@ "projectile": "PLCBOWX.DEF" } }, - "sounds" : + "sound" : { "attack": "GENIATTK.wav", "defend": "GENIDFND.wav", @@ -705,95 +930,139 @@ "faction": "neutral", "graphics" : { - "animation": "ZM174NPC.DEF" + "animation": "ZM174NPC.DEF", + "missile" : + { + "projectile": "PLCBOWX.DEF" + } } }, "hierophant2" : { "special" : true, + "disabled" : true, "id": 184, "level": 0, "faction": "neutral", "graphics" : { - "animation": "ZM175NPC.DEF" + "animation": "ZM175NPC.DEF", + "missile" : + { + "projectile": "CPRZEAX.DEF" + } } }, "templeGuardian2" : { "special" : true, + "disabled" : true, "id": 185, "level": 0, "faction": "neutral", "graphics" : { - "animation": "ZM176NPC.DEF" + "animation": "ZM176NPC.DEF", + "missile" : + { + "projectile": "PLCBOWX.DEF" + } } }, "succubus2" : { "special" : true, + "disabled" : true, "id": 186, "level": 0, "faction": "neutral", "graphics" : { - "animation": "ZM177NPC.DEF" + "animation": "ZM177NPC.DEF", + "missile" : + { + "projectile": "PLCBOWX.DEF" + } } }, "soulEater2" : { "special" : true, + "disabled" : true, "id": 187, "level": 0, "faction": "neutral", "graphics" : { - "animation": "ZM178NPC.DEF" + "animation": "ZM178NPC.DEF", + "missile" : + { + "projectile": "PLCBOWX.DEF" + } } }, "brute2" : { "special" : true, + "disabled" : true, "id": 188, "level": 0, "faction": "neutral", "graphics" : { - "animation": "ZM179NPC.DEF" + "animation": "ZM179NPC.DEF", + "missile" : + { + "projectile": "PLCBOWX.DEF" + } } }, "ogreLeader2" : { "special" : true, + "disabled" : true, "id": 189, "level": 0, "faction": "neutral", "graphics" : { - "animation": "ZM180NPC.DEF" + "animation": "ZM180NPC.DEF", + "missile" : + { + "projectile": "PLCBOWX.DEF" + } } }, "shaman2" : { "special" : true, + "disabled" : true, "id": 190, "level": 0, "faction": "neutral", "graphics" : { - "animation": "ZM181NPC.DEF" + "animation": "ZM181NPC.DEF", + "missile" : + { + "projectile": "PLCBOWX.DEF" + } } }, "astralSpirit2" : { "special" : true, + "disabled" : true, "id": 191, "level": 0, "faction": "neutral", "graphics" : { - "animation": "ZM182NPC.DEF" + "animation": "ZM182NPC.DEF", + "missile" : + { + "projectile": "PLCBOWX.DEF" + } } }, "sylvanCentaur" : @@ -806,8 +1075,7 @@ "animation": "ZM192Z.DEF", "missile" : { - "projectile": "PELFX.DEF", - "spinning": true + "projectile": "PELFX.DEF" } }, "sound" : @@ -830,8 +1098,7 @@ "animation": "ZM193Z.DEF", "missile" : { - "projectile": "CPRZEAX.DEF", - "spinning": false + "projectile": "CPRZEAX.DEF" } }, "sound" : @@ -878,20 +1145,40 @@ "id": 196, "level": 10, "faction": "neutral", - "abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ], - [ "TWO_HEX_ATTACK_BREATH", 0, 0, 0 ], - [ "DRAGON_NATURE", 0, 0, 0 ], - [ "UNDEAD", 0, 0, 0 ], - [ "FLYING", 0, 0, 0 ], - [ "SPELL_LIKE_ATTACK", 0, "spell.deathCloud", 0 ], - [ "SHOOTER", 0, 0, 0 ] ], + "abilities": + { + "dragon" : + { + "type" : "DRAGON_NATURE", + }, + "dragonBreath" : + { + "type" : "TWO_HEX_ATTACK_BREATH" + }, + "undead" : + { + "type" : "UNDEAD" + }, + "canFly" : + { + "type" : "FLYING" + }, + "deathCloud" : + { + "type" : "SPELL_LIKE_ATTACK", + "subtype" : "spell.deathCloud" + }, + "canShoot" : + { + "type" : "SHOOTER" + } + }, "graphics" : { "animation": "ZM196Z.DEF", "missile" : { - "projectile": "ZSHOT195.DEF", - "spinning": false + "projectile": "ZSHOT195.DEF" } }, "sound" : diff --git a/config/factions/neutral.json b/config/factions/neutral.json index 4683da4ea..6fa4ccc61 100644 --- a/config/factions/neutral.json +++ b/config/factions/neutral.json @@ -1,6 +1,7 @@ { "neutral" : { + "name" : "Neutral", "index" : 9, "alignment" : "neutral", "creatureBackground" : diff --git a/config/schemas/artifact.json b/config/schemas/artifact.json index 687c99716..10b39d8ae 100644 --- a/config/schemas/artifact.json +++ b/config/schemas/artifact.json @@ -4,6 +4,24 @@ "title" : "VCMI artifact format", "description" : "Format used to define new artifacts in VCMI", "required" : [ "class", "graphics", "text", "type", "value" ], + + "definitions" : { + "growingBonusList" : { + "type" : "array", + "items" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "level" : { + "type" : "number" + }, + "bonus" : { "$ref" : "vcmi:bonus" } + } + } + } + }, + + "additionalProperties" : false, "properties":{ "bonuses": { "type":"array", @@ -15,6 +33,10 @@ "enum" : [ "SPECIAL", "TREASURE", "MINOR", "MAJOR", "RELIC" ], "description": "Artifact class, treasure, minor, major or relic" }, + "id" : { + "type" : "number", + "description" : "Private field to break things, do not use." + }, "components": { "type":"array", "description": "Optional, list of components for combinational artifacts", @@ -22,8 +44,10 @@ }, "graphics": { "type":"object", + "additionalProperties" : false, "description": "Graphical files associated with the artifact", - "required" : [ "iconIndex", "image", "map" ], + //"required" : [ "iconIndex", "image", "map" ], + "required" : [ "iconIndex" ], "properties":{ "iconIndex": { "type":"number", @@ -43,12 +67,30 @@ } } }, + "growing" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "bonusesPerLevel" : { "$ref" : "#/definitions/growingBonusList"}, + "thresholdBonuses" : { "$ref" : "#/definitions/growingBonusList"} + } + }, "slot": { - "type":"string", - "description": "Slot to which this artifact can be put, if applicable" + "description": "Slot to which this artifact can be put, if applicable", + "oneOf" : [ + { + "type":"string" + }, + { + "type" : "array", + "minItems" : 1, + "additionalItems" : { "type" : "string" } + } + ] }, "text": { "type":"object", + "additionalProperties" : false, "description": "Texts associated with artifact", "required" : [ "description", "event", "name" ], "properties":{ diff --git a/config/schemas/bonus.json b/config/schemas/bonus.json index 7b05d8362..2ef25d990 100644 --- a/config/schemas/bonus.json +++ b/config/schemas/bonus.json @@ -4,6 +4,8 @@ "title" : "VCMI bonus system format", "description" : "Subsection of several formats, used to add generic bonuses to objects", "required": ["type"], + + "additionalProperties" : false, "properties":{ "addInfo": { "anyOf" : [ @@ -28,18 +30,26 @@ "type":"array", "description": "limiters", "items": { - "type":"object", - "properties" : { - "parameters": { - "type":"array", - "description" : "parameters", - "additionalItems": true + "oneOf" : [ + { + "type":"object", + "additionalProperties" : false, + "properties" : { + "parameters": { + "type":"array", + "description" : "parameters", + "additionalItems": true + }, + "type": { + "type":"string", + "description": "type", + } + } }, - "type": { - "type":"string", - "description": "type", + { + "type" : "string" } - } + ] } }, "propagator": { diff --git a/config/schemas/creature.json b/config/schemas/creature.json index 3ebc7a7a2..054ad33e6 100644 --- a/config/schemas/creature.json +++ b/config/schemas/creature.json @@ -3,14 +3,25 @@ "$schema": "http://json-schema.org/draft-04/schema", "title" : "VCMI creature format", "description": "Json format for defining new creatures in VCMI", - "required" : [ - "name", "faction", "cost", "level", "fightValue", "aiValue", - "attack", "defense", "hitPoints", "speed", "damage", "advMapAmount", - "graphics", "sound" + "required" : [ "faction" ], + "anyOf" : [ + { + "disabled" : { "enum" : [ true ] } + }, + { + "required" : [ + "name", "cost", "level", "fightValue", "aiValue", + "attack", "defense", "hitPoints", "speed", "damage", "advMapAmount", + "graphics", "sound" + ] + } ], + + "additionalProperties" : false, "properties":{ "name": { "type":"object", + "additionalProperties" : false, "description": "Translatable names for this creature", "required" : [ "singular", "plural" ], "properties":{ @@ -24,12 +35,26 @@ } } }, + "abilityText" : { + "type" : "string", + "description" : "Text version of creature abilities. Used only with original creature window" + }, + "id" : { + "type" : "number", + "description" : "Private field to break things, do not use." + }, + "extraNames" : { + "type" : "array", + "items" : { "type" : "string" }, + "description" : "Private field to break things, do not use." + }, "faction": { "type":"string", "description": "Faction this creature belongs to. Examples: castle, rampart" }, "cost": { "type":"object", + "additionalProperties" : false, "description": "Cost to recruit this creature", "properties":{ "wood": { "type":"number"}, @@ -45,6 +70,10 @@ "type":"boolean", "description": "Marks this object as special and not available by default" }, + "disabled": { + "type":"boolean", + "description": "Object is competely disabled and may not be even loaded in-game" + }, "level": { "type":"number"}, "fightValue": { "type":"number", @@ -70,6 +99,7 @@ "damage": { "type":"object", + "additionalProperties" : false, "properties":{ "max": { "type":"number" }, "min": { "type":"number" } @@ -81,6 +111,7 @@ }, "advMapAmount": { "type":"object", + "additionalProperties" : false, "description" : "Initial size of random stacks on adventure map", "properties":{ "min": { "type":"number" }, @@ -101,15 +132,18 @@ "description": "creature may receive \"week of\" events" }, "abilities": { - "type":"array", "description": "Creature abilities described using Bonus system", - "items": { "$ref" : "vcmi:bonus" } + "type":"object", + "additionalProperties": { + "$ref" : "vcmi:bonus" + } }, "stackExperience": { "type":"array", "description": "Stack experience, using bonus system", "items":{ "type":"object", + "additionalProperties" : false, "required" : [ "bonus", "values" ], "description": "0", "properties":{ @@ -119,7 +153,6 @@ "minItems" : 10, "maxItems" : 10, "description": "Strength of the bonus", - "additionalItems" : true, "anyof" : [ { "items": { "type" : "number" } }, { "items": { "type" : "boolean" } } @@ -130,14 +163,16 @@ }, "graphics": { "type":"object", + "additionalProperties" : false, "description": "Describes how this creature looks like during battles", "required" : [ - "animationTime", "iconLarge", "iconSmall", "iconIndex", - "map", "animation", "attackClimaxFrame", "timeBetweenFidgets" + "animationTime", "iconIndex", + "map", "animation", "timeBetweenFidgets" ], "properties":{ "animationTime": { "type":"object", + "additionalProperties" : false, "required" : [ "attack", "flight", "walk" ], "description": "Length of several animations", "properties":{ @@ -176,13 +211,10 @@ "type":"string", "description": ".def file with animation of this creature in battles" }, - "attackClimaxFrame": { - "type":"number", - "description": "Frame from attack animation during which creature deals damage" - }, "missile": { "type":"object", - "required" : [ "projectile", "frameAngles", "offset" ], + "additionalProperties" : false, + "required" : [ "projectile", "frameAngles", "offset", "attackClimaxFrame" ], "description": "Missile description for archers", "properties":{ "projectile": { @@ -201,6 +233,7 @@ }, "offset": { "type":"object", + "additionalProperties" : false, "required" : [ "lowerX", "lowerY", "middleX", "middleY", "upperX", "upperY" ], "description": "Position where projectile image appears during shooting in specific direction", "properties":{ @@ -211,6 +244,10 @@ "upperX": { "type":"number" }, "upperY": { "type":"number" } } + }, + "attackClimaxFrame": { + "type":"number", + "description": "Frame from attack animation during which creature deals damage" } } }, @@ -226,18 +263,17 @@ }, "sound": { "type":"object", + "additionalProperties" : false, "description": "Various sound files associated with this creature", "properties":{ - "attack": { "type":"string" }, - "defend": { "type":"string" }, - "killed": { "type":"string" }, - "moveEnd": { "type":"string" }, - "moveStart": { "type":"string" }, - "move": { "type":"string" }, - "shoot": { "type":"string" }, - "wince": { "type":"string" }, - "ext1": { "type":"string" }, - "ext2": { "type":"string" } + "attack": { "type":"string" }, + "defend": { "type":"string" }, + "killed": { "type":"string" }, + "startMoving": { "type":"string" }, + "endMoving": { "type":"string" }, + "move": { "type":"string" }, + "shoot": { "type":"string" }, + "wince": { "type":"string" } } } } diff --git a/config/schemas/faction.json b/config/schemas/faction.json index 113b2b805..6ecbe0344 100644 --- a/config/schemas/faction.json +++ b/config/schemas/faction.json @@ -7,11 +7,17 @@ "dependencies" : { "town" : [ "puzzleMap", "commander" ] }, + + "additionalProperties" : false, "properties":{ "name" : { "type" : "string", "description" : "Translatable name of town" }, + "index" : { + "type" : "number", + "description" : "Private field to break things, do not use." + }, "alignment": { "type":"string", "enum" : [ "good", "neutral", "evil" ], @@ -23,6 +29,7 @@ }, "creatureBackground": { "type":"object", + "additionalProperties" : false, "required" : [ "120px", "130px" ], "description": "Backgrounds for creature info card", "properties":{ @@ -42,6 +49,7 @@ }, "puzzleMap": { "type":"object", + "additionalProperties" : false, "required" : [ "prefix", "pieces" ], "description": "Puzzle map from obelisks for this town. Must contain 48 pieces", "properties":{ @@ -52,6 +60,7 @@ "maxItems" : 48, "items": { "type":"object", + "additionalProperties" : false, "properties":{ "index": { "type":"number", "description" : "Order in which images will be opened" }, "x": { "type":"number", "description" : "X coordinate on screen" }, @@ -67,15 +76,17 @@ }, "town": { "type":"object", + "additionalProperties" : false, "required" : [ "adventureMap", "buildingsIcons", "buildings", "creatures", "guildWindow", "names", "hallBackground", "hallSlots", "horde", "icons", "mageGuild", "moatDamage", - "musicTheme", "siege", "structures", "townBackground", "warMachine", "primaryResource" + "musicTheme", "siege", "structures", "townBackground", "warMachine" ], "description": "town", "properties":{ "adventureMap": { "type":"object", + "additionalProperties" : false, "description": "Paths to images of object on adventure map", "required" : [ "capitol", "castle", "village" ], "properties":{ @@ -96,6 +107,7 @@ "description" : "Dwellings on adventure map", "items" : { "type" : "object", + "additionalProperties" : false, "properties" : { "name": { "type":"string" }, "graphics": { "type":"string" } @@ -176,11 +188,13 @@ }, "icons": { "type":"object", + "additionalProperties" : false, "description": "Town icons", "required" : [ "fort", "village" ], "properties":{ "fort": { "type":"object", + "additionalProperties" : false, "required" : [ "normal", "built" ], "description": "Icons for town with built fort", "properties":{ @@ -196,6 +210,7 @@ }, "village": { "type":"object", + "additionalProperties" : false, "required" : [ "normal", "built" ], "description": "Icons for town without fort", "properties":{ diff --git a/config/schemas/hero.json b/config/schemas/hero.json index e87607d4e..7c2bd3f62 100644 --- a/config/schemas/hero.json +++ b/config/schemas/hero.json @@ -4,6 +4,8 @@ "title" : "VCMI hero format", "description" : "Format used to define new heroes in VCMI", "required": [ "army", "class", "images", "skills", "texts" ], + + "additionalProperties" : false, "properties":{ "army": { "type":"array", @@ -12,6 +14,7 @@ "maxItems" : 3, "items": { "type":"object", + "additionalProperties" : false, "required" : [ "creature", "min", "max" ], "properties":{ "creature": { @@ -29,10 +32,14 @@ } } }, + "id" : { + "type" : "number", + "description" : "Private field to break things, do not use." + }, "special": { "type":"boolean", "description": "Marks this object as special and not available by default" - }, + }, "class": { "type":"string", "description": "Hero class, e.g. knight or battleMage" @@ -43,8 +50,9 @@ }, "images": { "type":"object", + "additionalProperties" : false, "description": "images", - "required": [ "index", "large", "small", "specialtyLarge", "specialtySmall" ], + "required": [ "index" ], "properties":{ "index": { "type":"number", @@ -74,6 +82,7 @@ "maxItems" : 8, "items": { "type":"object", + "additionalProperties" : false, "required" : [ "level", "skill" ], "properties":{ "level": { @@ -88,11 +97,18 @@ } } }, + "specialties" : + { + "type" : "array", + "description" : "Specialty format used for OH3 heroes. Use \"specialty\" instead", + "additionalItems" : true + }, "specialty": { "type":"array", "description": "Description of hero specialty using bonus system", "items": { "type":"object", + "additionalProperties" : false, "required" : [ "bonuses" ], "properties":{ "growsWithLevel" : { @@ -114,6 +130,7 @@ }, "texts": { "type":"object", + "additionalProperties" : false, "description": "All translatable texts related to hero", "required" : [ "biography", "name", "specialty" ], "properties":{ @@ -127,6 +144,7 @@ }, "specialty": { "type":"object", + "additionalProperties" : false, "description": "Hero specialty information", "required" : [ "description", "name", "tooltip" ], "properties":{ diff --git a/config/schemas/heroClass.json b/config/schemas/heroClass.json index 202169cc4..37265b028 100644 --- a/config/schemas/heroClass.json +++ b/config/schemas/heroClass.json @@ -7,14 +7,18 @@ "animation", "faction", "highLevelChance", "lowLevelChance", "name", "primarySkills", "secondarySkills", "tavern" ], + + "additionalProperties" : false, "properties":{ "animation": { "type":"object", + "additionalProperties" : false, "description": "Files related to hero animation", "required": [ "battle", "map" ], "properties":{ "battle": { "type":"object", + "additionalProperties" : false, "description": "Hero animations for battle", "required": [ "female", "male" ], "properties":{ @@ -30,6 +34,7 @@ }, "map": { "type":"object", + "additionalProperties" : false, "description": "Hero animations for adventure map", "required": [ "female", "male" ], "properties":{ @@ -45,6 +50,10 @@ } } }, + "id" : { + "type" : "number", + "description" : "Private field to break things, do not use." + }, "faction": { "type":"string", "description": "Faction this hero class belongs to" diff --git a/config/schemas/mod.json b/config/schemas/mod.json index c7758cd49..17a91a576 100644 --- a/config/schemas/mod.json +++ b/config/schemas/mod.json @@ -4,8 +4,9 @@ "title" : "VCMI mod file format", "description" : "Format used to define main mod file (mod.json) in VCMI", "required" : [ "name", "description" ], - "properties":{ + "additionalProperties" : false, + "properties":{ "name": { "type":"string", "description": "Short name of your mod. No more than 2-3 words" @@ -60,6 +61,7 @@ "description" : "list of data sources attached to this mount point", "items": { "type":"object", + "additionalProperties" : false, "properties":{ "path": { "type":"string", diff --git a/config/schemas/settings.json b/config/schemas/settings.json index 5897bf10b..73b878b44 100644 --- a/config/schemas/settings.json +++ b/config/schemas/settings.json @@ -9,12 +9,14 @@ "type" : "string", "enum" : [ "trace", "debug", "info", "warn", "error" ] } - }, + }, + "additionalProperties" : false, "properties": { "general" : { "type" : "object", "default": {}, + "additionalProperties" : false, "required" : [ "classicCreatureWindow", "playerName", "showfps", "music", "sound" ], "properties" : { "classicCreatureWindow" : { @@ -41,11 +43,13 @@ }, "video" : { "type" : "object", + "additionalProperties" : false, "default": {}, "required" : [ "screenRes", "bitsPerPixel", "fullscreen" ], "properties" : { "screenRes" : { "type" : "object", + "additionalProperties" : false, "required" : [ "width", "height" ], "properties" : { "width" : { "type" : "number" }, @@ -65,6 +69,7 @@ }, "adventure" : { "type" : "object", + "additionalProperties" : false, "default": {}, "required" : [ "heroSpeed", "enemySpeed", "scrollSpeed", "heroReminder" ], "properties" : { @@ -88,6 +93,7 @@ }, "battle" : { "type" : "object", + "additionalProperties" : false, "default": {}, "required" : [ "animationSpeed", "mouseShadow", "cellBorders", "stackRange", "showQueue" ], "properties" : { @@ -115,6 +121,7 @@ }, "server" : { "type" : "object", + "additionalProperties" : false, "default": {}, "required" : [ "server", "port", "localInformation", "playerAI", "neutralAI" ], "properties" : { @@ -142,6 +149,7 @@ }, "logging" : { "type" : "object", + "additionalProperties" : false, "default" : {}, "required" : [ "console", "file", "loggers" ], "properties" : { @@ -152,7 +160,7 @@ "properties" : { "format" : { "type" : "string", - "default" : "%l %n [%t] - %m" + "default" : "%m" }, "threshold" : { "$ref" : "#/definitions/logLevelEnum", @@ -173,6 +181,7 @@ ], "items" : { "type" : "object", + "additionalProperties" : false, "default" : {}, "required" : [ "domain", "level", "color" ], "properties" : { @@ -186,6 +195,7 @@ }, "file" : { "type" : "object", + "additionalProperties" : false, "default" : {}, "required" : [ "format" ], "properties" : { @@ -200,6 +210,7 @@ "default" : [ { "domain" : "global", "level" : "info" } ], "items" : { "type" : "object", + "additionalProperties" : false, "required" : [ "level", "domain" ], "properties" : { "domain" : { "type" : "string" }, diff --git a/config/schemas/townBuilding.json b/config/schemas/townBuilding.json index 99bf622a1..eccaf52ea 100644 --- a/config/schemas/townBuilding.json +++ b/config/schemas/townBuilding.json @@ -1,5 +1,6 @@ { "type":"object", + "additionalProperties" : false, "$schema": "http://json-schema.org/draft-04/schema", "title" : "VCMI town building format", "description" : "Format used to define town buildings in VCMI", @@ -35,6 +36,7 @@ }, "cost": { "type":"object", + "additionalProperties" : false, "description": "Cost to build this building", "properties":{ "wood": { "type":"number"}, diff --git a/config/schemas/townSiege.json b/config/schemas/townSiege.json index e6c633580..35236e22f 100644 --- a/config/schemas/townSiege.json +++ b/config/schemas/townSiege.json @@ -1,5 +1,6 @@ { "type":"object", + "additionalProperties" : false, "$schema": "http://json-schema.org/draft-04/schema", "title" : "VCMI siege screen format", "description" : "Format used to define town siege screen in VCMI", @@ -12,6 +13,7 @@ { "point" : { "type" : "object", + "additionalProperties" : false, "required" : [ "x", "y" ], "properties":{ "x": { "type":"number" }, @@ -20,6 +22,7 @@ }, "tower" : { "type" : "object", + "additionalProperties" : false, "required" : [ "battlement", "creature", "tower" ], "properties":{ "battlement": { @@ -41,6 +44,7 @@ "properties":{ "gate": { "type":"object", + "additionalProperties" : false, "description" : "Town gates", "properties":{ "arch": { @@ -59,6 +63,7 @@ }, "moat": { "type":"object", + "additionalProperties" : false, "description" : "Castle moat description", "properties":{ "bank": { @@ -81,6 +86,7 @@ }, "static": { "type":"object", + "additionalProperties" : false, "description" : "Static sections of walls", "properties":{ "background": { @@ -99,6 +105,7 @@ }, "towers": { "type":"object", + "additionalProperties" : false, "description" : "Decription of towers", "properties":{ "bottom": { "$ref" : "#/definitions/tower", "description" : "Bottom tower" }, @@ -108,6 +115,7 @@ }, "walls": { "type":"object", + "additionalProperties" : false, "description" : "Destructible sections of the walls", "properties":{ "bottomMid": { diff --git a/config/schemas/townStructure.json b/config/schemas/townStructure.json index eedd9970e..f381cb127 100644 --- a/config/schemas/townStructure.json +++ b/config/schemas/townStructure.json @@ -4,6 +4,7 @@ "title" : "VCMI town structures format", "description" : "Format used to define structures visible on town screen in VCMI", "required": [ "animation", "x", "y"], + "additionalProperties" : false, "properties":{ "animation": { "type":"string", diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp index b22cf6a55..d7662c568 100644 --- a/lib/CArtHandler.cpp +++ b/lib/CArtHandler.cpp @@ -205,6 +205,7 @@ void CArtHandler::load(bool onlyTxt) JsonNode & artData = h3Data[numeric]; JsonUtils::merge(artData, node.second); + //JsonUtils::validate(artData, "vcmi:artifact", node.first); artifacts[numeric] = loadArtifact(artData); artifacts[numeric]->id = ArtifactID(numeric); @@ -386,11 +387,11 @@ void CArtHandler::loadGrowingArt(CGrowingArtifact * art, const JsonNode & node) { BOOST_FOREACH (auto b, node["growing"]["bonusesPerLevel"].Vector()) { - art->bonusesPerLevel.push_back (std::pair (b["level"].Float(), *JsonUtils::parseBonus (b["bonus"].Vector()))); + art->bonusesPerLevel.push_back (std::pair (b["level"].Float(), *JsonUtils::parseBonus (b["bonus"]))); } BOOST_FOREACH (auto b, node["growing"]["thresholdBonuses"].Vector()) { - art->thresholdBonuses.push_back (std::pair (b["level"].Float(), *JsonUtils::parseBonus (b["bonus"].Vector()))); + art->thresholdBonuses.push_back (std::pair (b["level"].Float(), *JsonUtils::parseBonus (b["bonus"]))); } } diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 4215c1b5d..d1c7e0302 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -7,6 +7,7 @@ #include "CGameState.h" #include "CTownHandler.h" #include "CModHandler.h" +#include "StringConstants.h" using namespace boost::assign; @@ -19,24 +20,6 @@ using namespace boost::assign; * Full text of license available in license.txt file, in main folder * */ - -static inline void registerCreature(const std::string &name, const si32 id) -{ - const std::string fullname = "creature." + name; - VLC->modh->identifiers.registerObject(fullname,id); -} - -///CCreatureHandler - -CCreatureHandler::CCreatureHandler() -{ - VLC->creh = this; - - allCreatures.setDescription("All creatures"); - creaturesOfLevel[0].setDescription("Creatures of unnormalized tier"); - for(int i = 1; i < ARRAY_COUNT(creaturesOfLevel); i++) - creaturesOfLevel[i].setDescription("Creatures of tier " + boost::lexical_cast(i)); -} int CCreature::getQuantityID(const int & quantity) { @@ -182,78 +165,108 @@ static void AddAbility(CCreature *cre, const JsonVector &ability_vec) cre->addNewBonus(nsf); } -static void RemoveAbility(CCreature *cre, const JsonNode &ability) +CCreatureHandler::CCreatureHandler() { - const std::string type = ability.String(); + VLC->creh = this; - auto it = bonusNameMap.find(type); + allCreatures.setDescription("All creatures"); + creaturesOfLevel[0].setDescription("Creatures of unnormalized tier"); + for(int i = 1; i < ARRAY_COUNT(creaturesOfLevel); i++) + creaturesOfLevel[i].setDescription("Creatures of tier " + boost::lexical_cast(i)); - if (it == bonusNameMap.end()) { - if (type == "DOUBLE_WIDE") - cre->doubleWide = false; - else - logGlobal->errorStream() << "Error: invalid ability type " << type << " in creatures config"; - - return; - } - - const int typeNo = it->second; - - Bonus::BonusType ecf = static_cast(typeNo); - - Bonus *b = cre->getBonusLocalFirst(Selector::type(ecf)); - cre->removeBonus(b); + loadCommanders(); } -void CCreatureHandler::loadBonuses(CCreature & ncre, std::string bonuses) +void CCreatureHandler::loadCommanders() { - static const std::map abilityMap = + const JsonNode config(ResourceID("config/commanders.json")); + + BOOST_FOREACH (auto bonus, config["bonusPerLevel"].Vector()) + { + commanderLevelPremy.push_back(JsonUtils::parseBonus (bonus.Vector())); + } + + int i = 0; + BOOST_FOREACH (auto skill, config["skillLevels"].Vector()) + { + skillLevels.push_back (std::vector()); + BOOST_FOREACH (auto skillLevel, skill["levels"].Vector()) + { + skillLevels[i].push_back (skillLevel.Float()); + } + ++i; + } + + BOOST_FOREACH (auto ability, config["abilityRequirements"].Vector()) + { + std::pair > a; + a.first = *JsonUtils::parseBonus (ability["ability"].Vector()); + a.second.first = ability["skills"].Vector()[0].Float(); + a.second.second = ability["skills"].Vector()[1].Float(); + skillRequirements.push_back (a); + } +} + +void CCreatureHandler::loadBonuses(JsonNode & creature, std::string bonuses) +{ + auto makeBonusNode = [&](std::string type) -> JsonNode + { + JsonNode ret; + ret["type"].String() = type; + return ret; + }; + + static const std::map abilityMap = boost::assign::map_list_of - ("FLYING_ARMY", Bonus::FLYING) - ("SHOOTING_ARMY", Bonus::SHOOTER) - ("SIEGE_WEAPON", Bonus::SIEGE_WEAPON) - ("const_free_attack", Bonus::BLOCKS_RETALIATION) - ("IS_UNDEAD", Bonus::UNDEAD) - ("const_no_melee_penalty",Bonus::NO_MELEE_PENALTY) - ("const_jousting",Bonus::JOUSTING) - ("KING_1",Bonus::KING1) - ("KING_2",Bonus::KING2) - ("KING_3",Bonus::KING3) - ("const_no_wall_penalty",Bonus::NO_WALL_PENALTY) - ("CATAPULT",Bonus::CATAPULT) - ("MULTI_HEADED",Bonus::ATTACKS_ALL_ADJACENT) - ("IMMUNE_TO_MIND_SPELLS",Bonus::MIND_IMMUNITY) - ("HAS_EXTENDED_ATTACK",Bonus::TWO_HEX_ATTACK_BREATH); + ("FLYING_ARMY", makeBonusNode("FLYING")) + ("SHOOTING_ARMY", makeBonusNode("SHOOTER")) + ("SIEGE_WEAPON", makeBonusNode("SIEGE_WEAPON")) + ("const_free_attack", makeBonusNode("BLOCKS_RETALIATION")) + ("IS_UNDEAD", makeBonusNode("UNDEAD")) + ("const_no_melee_penalty", makeBonusNode("NO_MELEE_PENALTY")) + ("const_jousting", makeBonusNode("JOUSTING")) + ("KING_1", makeBonusNode("KING1")) + ("KING_2", makeBonusNode("KING2")) + ("KING_3", makeBonusNode("KING3")) + ("const_no_wall_penalty", makeBonusNode("NO_WALL_PENALTY")) + ("CATAPULT", makeBonusNode("CATAPULT")) + ("MULTI_HEADED", makeBonusNode("ATTACKS_ALL_ADJACENT")) + ("IMMUNE_TO_MIND_SPELLS", makeBonusNode("MIND_IMMUNITY")) + ("HAS_EXTENDED_ATTACK", makeBonusNode("TWO_HEX_ATTACK_BREATH")); auto hasAbility = [&](const std::string name) -> bool { return boost::algorithm::find_first(bonuses, name); }; + BOOST_FOREACH(auto a, abilityMap) { if(hasAbility(a.first)) - ncre.addBonus(0, a.second); + creature["abilities"][a.first] = a.second; } if(hasAbility("DOUBLE_WIDE")) - ncre.doubleWide = true; + creature["doubleWide"].Bool() = true; + if(hasAbility("const_raises_morale")) { - ncre.addBonus(+1, Bonus::MORALE);; - ncre.getBonusList().back()->addPropagator(make_shared(CBonusSystemNode::HERO)); + JsonNode node = makeBonusNode("MORALE"); + node["val"].Float() = 1; + node["propagator"].String() = "HERO"; + creature["abilities"]["const_raises_morale"] = node; } if(hasAbility("const_lowers_morale")) { - ncre.addBonus(-1, Bonus::MORALE);; - ncre.getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY; + JsonNode node = makeBonusNode("MORALE"); + node["val"].Float() = 1; + node["effectRange"].String() = "ONLY_ENEMY_ARMY"; + creature["abilities"]["const_lowers_morale"] = node; } } - void CCreatureHandler::load() { - logGlobal->traceStream() << "\t\tReading ZCRTRAIT.TXT"; + std::vector h3Data; - ////////////reading ZCRTRAIT.TXT /////////////////// CLegacyConfigParser parser("DATA/ZCRTRAIT.TXT"); parser.endLine(); // header @@ -265,70 +278,80 @@ void CCreatureHandler::load() while (parser.isNextEntryEmpty()) parser.endLine(); - CCreature &ncre = *new CCreature; - ncre.idNumber = CreatureID(creatures.size()); - ncre.cost.resize(GameConstants::RESOURCE_QUANTITY); - ncre.level=0; - ncre.iconIndex = ncre.idNumber + 2; // +2 for empty\selection images + JsonNode data; - ncre.nameSing = parser.readString(); - ncre.namePl = parser.readString(); + data["graphics"]["iconIndex"].Float() = h3Data.size() + 2; // +2 for empty\selection images + + data["name"]["singular"].String() = parser.readString(); + data["name"]["plural"].String() = parser.readString(); for(int v=0; v<7; ++v) - { - ncre.cost[v] = parser.readNumber(); - } - ncre.fightValue = parser.readNumber(); - ncre.AIValue = parser.readNumber(); - ncre.growth = parser.readNumber(); - ncre.hordeGrowth = parser.readNumber(); + data["cost"][GameConstants::RESOURCE_NAMES[v]].Float() = parser.readNumber(); - ncre.addBonus(parser.readNumber(), Bonus::STACK_HEALTH); - ncre.addBonus(parser.readNumber(), Bonus::STACKS_SPEED); - ncre.addBonus(parser.readNumber(), Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK); - ncre.addBonus(parser.readNumber(), Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE); - ncre.addBonus(parser.readNumber(), Bonus::CREATURE_DAMAGE, 1); - ncre.addBonus(parser.readNumber(), Bonus::CREATURE_DAMAGE, 2); - ncre.addBonus(parser.readNumber(), Bonus::SHOTS); + data["fightValue"].Float() = parser.readNumber(); + data["aiValue"].Float() = parser.readNumber(); + data["growth"].Float() = parser.readNumber(); + data["horde"].Float() = parser.readNumber(); - //spells - not used? - parser.readNumber(); - ncre.ammMin = parser.readNumber(); - ncre.ammMax = parser.readNumber(); - - ncre.abilityText = parser.readString(); - loadBonuses(ncre, parser.readString()); //Attributes + data["hitPoints"].Float() = parser.readNumber(); + data["speed"].Float() = parser.readNumber(); + data["attack"].Float() = parser.readNumber(); + data["defense"].Float() = parser.readNumber(); + data["damage"]["min"].Float() = parser.readNumber(); + data["damage"]["max"].Float() = parser.readNumber(); - creatures.push_back(&ncre); + if (float shots = parser.readNumber()) + data["shots"].Float() = shots; + + if (float spells = parser.readNumber()) + data["spellPoints"].Float() = spells; + + data["advMapAmount"]["min"].Float() = parser.readNumber(); + data["advMapAmount"]["max"].Float() = parser.readNumber(); + + data["abilityText"].String() = parser.readString(); + loadBonuses(data, parser.readString()); //Attributes + + h3Data.push_back(data); } while (parser.endLine()); - // loading creatures properties - logGlobal->traceStream() << "\t\tReading creatures json configs"; + loadAnimationInfo(h3Data); const JsonNode gameConf(ResourceID("config/gameConfig.json")); - const JsonNode config(JsonUtils::assembleFromFiles(gameConf["creatures"].convertTo >())); + JsonNode config(JsonUtils::assembleFromFiles(gameConf["creatures"].convertTo >())); + + creatures.resize(GameConstants::CREATURES_COUNT); BOOST_FOREACH(auto & node, config.Struct()) { - int creatureID = node.second["id"].Float(); - CCreature *c = creatures[creatureID]; + int numeric = node.second["id"].Float(); - loadCreatureJson(c, node.second); + JsonUtils::merge(h3Data[numeric], node.second); - // Main reference name, e.g. royalGriffin - c->nameRef = node.first; - registerCreature(node.first, c->idNumber); + //JsonUtils::validate(h3Data[numeric], "vcmi:creature", node.first); + + creatures[numeric] = loadCreature(h3Data[numeric]); + creatures[numeric]->idNumber = CreatureID(numeric); + + VLC->modh->identifiers.registerObject ("creature." + node.first, numeric); // Alternative names, if any - BOOST_FOREACH(const JsonNode &name, node.second["extraNames"].Vector()) - { - registerCreature(name.String(), c->idNumber); - } + BOOST_FOREACH(const JsonNode &name, h3Data[numeric]["extraNames"].Vector()) + VLC->modh->identifiers.registerObject ("creature." + name.String(), numeric); } - loadAnimationInfo(); + for (size_t i=0; i < creatures.size(); i++) + { + if (creatures[i] == nullptr) + logGlobal->warnStream() << "Warning: creature with id " << i << " is missing!"; + } + loadCrExpBon(); +} + +void CCreatureHandler::loadCrExpBon() +{ if (VLC->modh->modules.STACK_EXP) //reading default stack experience bonuses { CLegacyConfigParser parser("DATA/CREXPBON.TXT"); @@ -429,76 +452,60 @@ void CCreatureHandler::load() maxExpPerBattle[0] = maxExpPerBattle[7]; }//end of Stack Experience - - logGlobal->traceStream() << "\t\tReading config/commanders.json"; - const JsonNode config3(ResourceID("config/commanders.json")); - - BOOST_FOREACH (auto bonus, config3["bonusPerLevel"].Vector()) - { - commanderLevelPremy.push_back(JsonUtils::parseBonus (bonus.Vector())); - } - - int i = 0; - BOOST_FOREACH (auto skill, config3["skillLevels"].Vector()) - { - skillLevels.push_back (std::vector()); - BOOST_FOREACH (auto skillLevel, skill["levels"].Vector()) - { - skillLevels[i].push_back (skillLevel.Float()); - } - ++i; - } - - BOOST_FOREACH (auto ability, config3["abilityRequirements"].Vector()) - { - std::pair > a; - a.first = *JsonUtils::parseBonus (ability["ability"].Vector()); - a.second.first = ability["skills"].Vector()[0].Float(); - a.second.second = ability["skills"].Vector()[1].Float(); - skillRequirements.push_back (a); - } } -void CCreatureHandler::loadAnimationInfo() +void CCreatureHandler::loadAnimationInfo(std::vector &h3Data) { CLegacyConfigParser parser("DATA/CRANIM.TXT"); parser.endLine(); // header parser.endLine(); - for(int dd=0; ddtraceStream() << "Added creature: " << creatureID; - registerCreature(creature->nameRef, creature->idNumber); + + VLC->modh->identifiers.registerObject ("creature." + creature->nameRef, creature->idNumber); } CCreature * CCreatureHandler::loadCreature(const JsonNode & node) @@ -531,13 +539,12 @@ CCreature * CCreatureHandler::loadCreature(const JsonNode & node) cre->addBonus(node["speed"].Float(), Bonus::STACKS_SPEED); cre->addBonus(node["attack"].Float(), Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK); cre->addBonus(node["defense"].Float(), Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE); - const JsonNode & vec = node["damage"]; - cre->addBonus(vec["min"].Float(), Bonus::CREATURE_DAMAGE, 1); - cre->addBonus(vec["max"].Float(), Bonus::CREATURE_DAMAGE, 2); + cre->addBonus(node["damage"]["min"].Float(), Bonus::CREATURE_DAMAGE, 1); + cre->addBonus(node["damage"]["max"].Float(), Bonus::CREATURE_DAMAGE, 2); - auto & amounts = node ["advMapAmount"]; - cre->ammMin = amounts["min"].Float(); - cre->ammMax = amounts["max"].Float(); + cre->ammMin = node["advMapAmount"]["min"].Float(); + cre->ammMax = node["advMapAmount"]["max"].Float(); + assert(cre->ammMin <= cre->ammMax); if (!node["shots"].isNull()) cre->addBonus(node["shots"].Float(), Bonus::SHOTS); @@ -547,13 +554,16 @@ CCreature * CCreatureHandler::loadCreature(const JsonNode & node) cre->doubleWide = node["doubleWide"].Bool(); - //graphics loadStackExperience(cre, node["stackExperience"]); + loadJsonAnimation(cre, node["graphics"]); + loadCreatureJson(cre, node); + return cre; +} - const JsonNode & graphics = node["graphics"]; +void CCreatureHandler::loadJsonAnimation(CCreature * cre, const JsonNode & graphics) +{ cre->animation.timeBetweenFidgets = graphics["timeBetweenFidgets"].Float(); cre->animation.troopCountLocationOffset = graphics["troopCountLocationOffset"].Float(); - cre->animation.attackClimaxFrame = graphics["attackClimaxFrame"].Float(); const JsonNode & animationTime = graphics["animationTime"]; cre->animation.walkAnimationTime = animationTime["walk"].Float(); @@ -569,13 +579,11 @@ CCreature * CCreatureHandler::loadCreature(const JsonNode & node) cre->animation.lowerRightMissleOffsetX = offsets["lowerX"].Float(); cre->animation.lowerRightMissleOffsetY = offsets["lowerY"].Float(); - cre->animation.missleFrameAngles = missile["frameAngles"].convertTo>(); + cre->animation.attackClimaxFrame = missile["attackClimaxFrame"].Float(); + cre->animation.missleFrameAngles = missile["frameAngles"].convertTo >(); cre->advMapDef = graphics["map"].String(); cre->iconIndex = graphics["iconIndex"].Float(); - - loadCreatureJson(cre, node); - return cre; } void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & config) @@ -583,21 +591,32 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c creature->level = config["level"].Float(); creature->animDefName = config["graphics"]["animation"].String(); - BOOST_FOREACH(const JsonNode &ability, config["ability_remove"].Vector()) + if (config["abilities"].getType() == JsonNode::DATA_STRUCT) { - RemoveAbility(creature, ability); - } - - BOOST_FOREACH(const JsonNode &ability, config["abilities"].Vector()) - { - if (ability.getType() == JsonNode::DATA_VECTOR) - AddAbility(creature, ability.Vector()); // used only for H3 creatures - else + BOOST_FOREACH(auto &ability, config["abilities"].Struct()) { - auto b = JsonUtils::parseBonus(ability); - b->source = Bonus::CREATURE_ABILITY; - b->duration = Bonus::PERMANENT; - creature->addNewBonus(b); + if (!ability.second.isNull()) + { + auto b = JsonUtils::parseBonus(ability.second); + b->source = Bonus::CREATURE_ABILITY; + b->duration = Bonus::PERMANENT; + creature->addNewBonus(b); + } + } + } + else + { + BOOST_FOREACH(const JsonNode &ability, config["abilities"].Vector()) + { + if (ability.getType() == JsonNode::DATA_VECTOR) + AddAbility(creature, ability.Vector()); // used only for H3 creatures + else + { + auto b = JsonUtils::parseBonus(ability); + b->source = Bonus::CREATURE_ABILITY; + b->duration = Bonus::PERMANENT; + creature->addNewBonus(b); + } } } @@ -618,9 +637,8 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c doubledCreatures.insert(creature->idNumber); creature->animation.projectileImageName = config["graphics"]["missile"]["projectile"].String(); - //creature->animation.projectileSpin = config["graphics"]["missile"]["spinning"].Bool(); - creature->special = config["special"].Bool(); + creature->special = config["special"].Bool() || config["disabled"].Bool(); const JsonNode & sounds = config["sound"]; @@ -631,8 +649,6 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c GET_SOUND_VALUE(move); GET_SOUND_VALUE(shoot); GET_SOUND_VALUE(wince); - GET_SOUND_VALUE(ext1); - GET_SOUND_VALUE(ext2); GET_SOUND_VALUE(startMoving); GET_SOUND_VALUE(endMoving); #undef GET_SOUND_VALUE diff --git a/lib/CCreatureHandler.h b/lib/CCreatureHandler.h index 7e980026d..9d53d0d8a 100644 --- a/lib/CCreatureHandler.h +++ b/lib/CCreatureHandler.h @@ -79,14 +79,12 @@ public: std::string move; std::string shoot; // range attack std::string wince; // attacked but did not die - std::string ext1; // creature specific extension - std::string ext2; // creature specific extension - std::string startMoving; // usually same as ext1 - std::string endMoving; // usually same as ext2 + std::string startMoving; + std::string endMoving; template void serialize(Handler &h, const int version) { - h & attack & defend & killed & move & shoot & wince & ext1 & ext2 & startMoving & endMoving; + h & attack & defend & killed & move & shoot & wince & startMoving & endMoving; } } sounds; @@ -140,6 +138,7 @@ private: CBonusSystemNode allCreatures; CBonusSystemNode creaturesOfLevel[GameConstants::CREATURES_PER_TOWN + 1];//index 0 is used for creatures of unknown tier or outside <1-7> range + void loadJsonAnimation(CCreature * creature, const JsonNode & graphics); void loadStackExperience(CCreature * creature, const JsonNode &input); void loadCreatureJson(CCreature * creature, const JsonNode & config); public: @@ -159,9 +158,10 @@ public: /// loading functions /// adding abilities from ZCRTRAIT.TXT - void loadBonuses(CCreature & creature, std::string bonuses); + void loadBonuses(JsonNode & creature, std::string bonuses); /// load all creatures from H3 files void load(); + void loadCommanders(); /// load creature from json structure void load(std::string creatureID, const JsonNode & node); /// load one creature from json config @@ -169,9 +169,11 @@ public: /// generates tier-specific bonus tree entries void buildBonusTreeForTiers(); /// read cranim.txt file from H3 - void loadAnimationInfo(); + void loadAnimationInfo(std::vector & h3Data); /// read one line from cranim.txt - void loadUnitAnimInfo(CCreature & unit, CLegacyConfigParser &parser); + void loadUnitAnimInfo(JsonNode & unit, CLegacyConfigParser &parser); + /// load all creatures from H3 files + void loadCrExpBon(); /// parse crexpbon.txt file from H3 void loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser &parser); /// help function for parsing CREXPBON.txt diff --git a/lib/CHeroHandler.cpp b/lib/CHeroHandler.cpp index 3e6cdf81b..d6c7052c7 100644 --- a/lib/CHeroHandler.cpp +++ b/lib/CHeroHandler.cpp @@ -123,6 +123,7 @@ void CHeroClassHandler::load() JsonNode & classData = h3Data[numeric]; JsonUtils::merge(classData, node.second); + //JsonUtils::validate(classData, "vcmi:heroClass", node.first); heroClasses[numeric] = loadClass(classData); heroClasses[numeric]->id = numeric; @@ -457,6 +458,8 @@ void CHeroHandler::loadHeroes() { ui32 identifier = entry.second["id"].Float(); JsonUtils::merge(h3Data[identifier], entry.second); + + //JsonUtils::validate(h3Data[identifier], "vcmi:hero", entry.first); CHero * hero = loadHero(h3Data[identifier]); hero->ID = identifier; heroes[identifier] = hero; diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp index d4f39431e..afaf66cfa 100644 --- a/lib/CTownHandler.cpp +++ b/lib/CTownHandler.cpp @@ -70,6 +70,8 @@ JsonNode readBuilding(CLegacyConfigParser & parser) BOOST_FOREACH(const std::string & resID, GameConstants::RESOURCE_NAMES) cost[resID].Float() = parser.readNumber(); + cost.Struct().erase("mithril"); // erase mithril to avoid confusing validator + parser.endLine(); return ret; } @@ -588,6 +590,7 @@ void CTownHandler::load() } BOOST_FOREACH(auto & entry, buildingsConf.Struct()) { + //JsonUtils::validate(entry.second, "vcmi:faction", entry.first); load(entry.first, entry.second); } } diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index 0ae6b307f..bae9e8c22 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -66,7 +66,8 @@ const bmap bonusLimiterMap = boost::assign::map_list_o const bmap bonusPropagatorMap = boost::assign::map_list_of ("BATTLE_WIDE", make_shared(CBonusSystemNode::BATTLE)) ("VISITED_TOWN_AND_VISITOR", make_shared(CBonusSystemNode::TOWN_AND_VISITOR)) - ("PLAYER_PROPAGATOR", make_shared(CBonusSystemNode::PLAYER)); + ("PLAYER_PROPAGATOR", make_shared(CBonusSystemNode::PLAYER)) + ("HERO", make_shared(CBonusSystemNode::HERO)); #define BONUS_LOG_LINE(x) logBonus->traceStream() << x diff --git a/lib/JsonNode.cpp b/lib/JsonNode.cpp index a00796241..187e33cb7 100644 --- a/lib/JsonNode.cpp +++ b/lib/JsonNode.cpp @@ -755,18 +755,23 @@ std::string JsonValidator::validateEnum(const JsonNode &node, const JsonVector & std::string JsonValidator::validatesSchemaList(const JsonNode &node, const JsonNode &schemas, std::string errorMsg, std::function isValid) { - std::string errors; if (!schemas.isNull()) { + std::string errors = "\n"; size_t result = 0; BOOST_FOREACH(auto & schema, schemas.Vector()) { std::string error = validateNode(node, schema); if (error.empty()) + { result++; + } else - errors += fail(error); + { + errors += error; + errors += "\n"; + } } if (isValid(result)) { @@ -794,7 +799,7 @@ std::string JsonValidator::validateNodeType(const JsonNode &node, const JsonNode }); // data must be valid against one and only one schema - errors += validatesSchemaList(node, schema["oneOf"], "Failed to pass only one and only one schema", [&](size_t count) + errors += validatesSchemaList(node, schema["oneOf"], "Failed to pass one and only one schema", [&](size_t count) { return count == 1; }); @@ -805,13 +810,6 @@ std::string JsonValidator::validateNodeType(const JsonNode &node, const JsonNode if (validateNode(node, schema["not"]).empty()) errors += fail("Successful validation against negative check"); } - // basic schema check - if (!schema["type"].isNull()) - { - JsonNode::JsonType type = stringToType.find(schema["type"].String())->second; - if(type != node.getType()) - errors += fail("Type mismatch!"); - } return errors; } @@ -822,6 +820,9 @@ std::string JsonValidator::validateNode(const JsonNode &node, const JsonNode &sc assert(!schema.isNull()); // can this error be triggered? + if (node.isNull()) + return ""; // node not present. consider to be "valid" + if (!schema["$ref"].isNull()) { std::string URI = schema["$ref"].String(); @@ -833,6 +834,14 @@ std::string JsonValidator::validateNode(const JsonNode &node, const JsonNode &sc return validateRoot(node, URI); } + // basic schema check + if (!schema["type"].isNull()) + { + JsonNode::JsonType type = stringToType.find(schema["type"].String())->second; + if(type != node.getType()) + return errors + fail("Type mismatch!"); // different type. Any other checks are useless + } + errors += validateNodeType(node, schema); // enumeration - data must be equeal to one of items in list @@ -876,10 +885,10 @@ std::string JsonValidator::validateVectorItem(const JsonVector items, const Json return validateNode(items[index], additional); // or, additionalItems field can be bool which indicates if such items are allowed - // default = false, so case if additionalItems is not present will be handled as well - if (!additional.Bool()) + if (!additional.isNull() && additional.Bool() == false) // present and set to false - error return fail("Unknown entry found"); + // by default - additional items are allowed return ""; } @@ -930,9 +939,11 @@ std::string JsonValidator::validateStructItem(const JsonNode &node, const JsonNo if (additional.getType() == JsonNode::DATA_STRUCT) return validateNode(node, additional); - if (!additional.Bool()) + // or, additionalItems field can be bool which indicates if such items are allowed + if (!additional.isNull() && additional.Bool() == false) // present and set to false - error return fail("Unknown entry found: " + nodeName); + // by default - additional items are allowed return ""; } @@ -947,7 +958,7 @@ std::string JsonValidator::validateStruct(const JsonNode &node, const JsonNode & BOOST_FOREACH(auto & required, schema["required"].Vector()) { - if (!vstd::contains(map, required.String())) + if (node[required.String()].isNull()) errors += fail("Required entry " + required.String() + " is missing"); } diff --git a/lib/filesystem/CResourceLoader.cpp b/lib/filesystem/CResourceLoader.cpp index 939fc53dc..c2029c848 100644 --- a/lib/filesystem/CResourceLoader.cpp +++ b/lib/filesystem/CResourceLoader.cpp @@ -174,9 +174,6 @@ void CResourceLoader::addLoader(std::string mountPoint, shared_ptrwarnStream() << "Warning: unknown file type: " << entry.second; - resources[ident].push_back(locator); } } diff --git a/lib/logging/CLogger.cpp b/lib/logging/CLogger.cpp index 7cd56e156..7e32cf884 100644 --- a/lib/logging/CLogger.cpp +++ b/lib/logging/CLogger.cpp @@ -266,9 +266,9 @@ CLogFormatter::CLogFormatter() : pattern("%m") } -CLogFormatter::CLogFormatter(const std::string & pattern) : pattern(pattern) +CLogFormatter::CLogFormatter(const std::string & pattern) { - + setPattern(pattern); } std::string CLogFormatter::format(const LogRecord & record) const @@ -370,7 +370,10 @@ EConsoleTextColor::EConsoleTextColor CColorMapping::getColorFor(const CLoggerDom CLogConsoleTarget::CLogConsoleTarget(CConsoleHandler * console) : console(console), threshold(ELogLevel::INFO), coloredOutputEnabled(true) { - formatter.setPattern("%l %n [%t] - %m"); + // more verbose version: + //formatter.setPattern("%l %n [%t] - %m"); + + formatter.setPattern("%m"); } void CLogConsoleTarget::write(const LogRecord & record)