1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

- 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)
This commit is contained in:
Ivan Savenko 2013-04-11 19:24:14 +00:00
parent f10ba48c77
commit 0cf969d508
36 changed files with 2315 additions and 717 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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
}
}
]
}

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"
}
}
}

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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": {}
}
}

View File

@ -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"

View File

@ -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" :

View File

@ -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" :

View File

@ -1,6 +1,7 @@
{
"neutral" :
{
"name" : "Neutral",
"index" : 9,
"alignment" : "neutral",
"creatureBackground" :

View File

@ -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":{

View File

@ -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": {

View File

@ -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" }
}
}
}

View File

@ -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":{

View File

@ -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":{

View File

@ -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"

View File

@ -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",

View File

@ -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" },

View File

@ -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"},

View File

@ -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": {

View File

@ -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",

View File

@ -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 <ui16, Bonus> (b["level"].Float(), *JsonUtils::parseBonus (b["bonus"].Vector())));
art->bonusesPerLevel.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *JsonUtils::parseBonus (b["bonus"])));
}
BOOST_FOREACH (auto b, node["growing"]["thresholdBonuses"].Vector())
{
art->thresholdBonuses.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *JsonUtils::parseBonus (b["bonus"].Vector())));
art->thresholdBonuses.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *JsonUtils::parseBonus (b["bonus"])));
}
}

View File

@ -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<std::string>(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<std::string>(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<Bonus::BonusType>(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<std::string,Bonus::BonusType> 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<ui8>());
BOOST_FOREACH (auto skillLevel, skill["levels"].Vector())
{
skillLevels[i].push_back (skillLevel.Float());
}
++i;
}
BOOST_FOREACH (auto ability, config["abilityRequirements"].Vector())
{
std::pair <Bonus, std::pair <ui8, ui8> > 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<std::string, JsonNode> 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<CPropagatorNodeType>(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<JsonNode> 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<std::vector<std::string> >()));
JsonNode config(JsonUtils::assembleFromFiles(gameConf["creatures"].convertTo<std::vector<std::string> >()));
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<ui8>());
BOOST_FOREACH (auto skillLevel, skill["levels"].Vector())
{
skillLevels[i].push_back (skillLevel.Float());
}
++i;
}
BOOST_FOREACH (auto ability, config3["abilityRequirements"].Vector())
{
std::pair <Bonus, std::pair <ui8, ui8> > 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<JsonNode> &h3Data)
{
CLegacyConfigParser parser("DATA/CRANIM.TXT");
parser.endLine(); // header
parser.endLine();
for(int dd=0; dd<creatures.size(); ++dd)
for(int dd=0; dd<GameConstants::CREATURES_COUNT; ++dd)
{
while (parser.isNextEntryEmpty() && parser.endLine()) // skip empty lines
;
loadUnitAnimInfo(*creatures[dd], parser);
loadUnitAnimInfo(h3Data[dd]["graphics"], parser);
parser.endLine();
}
}
void CCreatureHandler::loadUnitAnimInfo(CCreature & unit, CLegacyConfigParser & parser)
void CCreatureHandler::loadUnitAnimInfo(JsonNode & graphics, CLegacyConfigParser & parser)
{
unit.animation.timeBetweenFidgets = parser.readNumber();
unit.animation.walkAnimationTime = parser.readNumber();
unit.animation.attackAnimationTime = parser.readNumber();
unit.animation.flightAnimationDistance = parser.readNumber();
///////////////////////
graphics["map"].String(); //create empty string. Real value will be loaded from H3 txt's
graphics["timeBetweenFidgets"].Float() = parser.readNumber();
unit.animation.upperRightMissleOffsetX = parser.readNumber();
unit.animation.upperRightMissleOffsetY = parser.readNumber();
unit.animation.rightMissleOffsetX = parser.readNumber();
unit.animation.rightMissleOffsetY = parser.readNumber();
unit.animation.lowerRightMissleOffsetX = parser.readNumber();
unit.animation.lowerRightMissleOffsetY = parser.readNumber();
JsonNode & animationTime = graphics["animationTime"];
animationTime["walk"].Float() = parser.readNumber();
animationTime["attack"].Float() = parser.readNumber();
animationTime["flight"].Float() = parser.readNumber();
///////////////////////
JsonNode & missile = graphics["missile"];
JsonNode & offsets = missile["offset"];
for(int jjj=0; jjj<12; ++jjj)
unit.animation.missleFrameAngles.push_back(parser.readNumber());
offsets["upperX"].Float() = parser.readNumber();
offsets["upperY"].Float() = parser.readNumber();
offsets["middleX"].Float() = parser.readNumber();
offsets["middleY"].Float() = parser.readNumber();
offsets["lowerX"].Float() = parser.readNumber();
offsets["lowerY"].Float() = parser.readNumber();
unit.animation.troopCountLocationOffset= parser.readNumber();
unit.animation.attackClimaxFrame = parser.readNumber();
for(int i=0; i<12; i++)
{
JsonNode entry;
entry.Float() = parser.readNumber();
missile["frameAngles"].Vector().push_back(entry);
}
parser.endLine();
graphics["troopCountLocationOffset"].Float() = parser.readNumber();
missile["attackClimaxFrame"].Float() = parser.readNumber();
// assume that creature is not a shooter and should not have whole missile field
if (missile["frameAngles"].Vector()[0].Float() == 0 &&
missile["attackClimaxFrame"].Float() == 0)
graphics.Struct().erase("missile");
}
void CCreatureHandler::load(std::string creatureID, const JsonNode & node)
@ -509,7 +516,8 @@ void CCreatureHandler::load(std::string creatureID, const JsonNode & node)
creatures.push_back(creature);
logGlobal->traceStream() << "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<std::vector<double>>();
cre->animation.attackClimaxFrame = missile["attackClimaxFrame"].Float();
cre->animation.missleFrameAngles = missile["frameAngles"].convertTo<std::vector<double> >();
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

View File

@ -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 <typename Handler> 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<JsonNode> & 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

View File

@ -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;

View File

@ -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);
}
}

View File

@ -66,7 +66,8 @@ const bmap<std::string, TLimiterPtr> bonusLimiterMap = boost::assign::map_list_o
const bmap<std::string, TPropagatorPtr> bonusPropagatorMap = boost::assign::map_list_of
("BATTLE_WIDE", make_shared<CPropagatorNodeType>(CBonusSystemNode::BATTLE))
("VISITED_TOWN_AND_VISITOR", make_shared<CPropagatorNodeType>(CBonusSystemNode::TOWN_AND_VISITOR))
("PLAYER_PROPAGATOR", make_shared<CPropagatorNodeType>(CBonusSystemNode::PLAYER));
("PLAYER_PROPAGATOR", make_shared<CPropagatorNodeType>(CBonusSystemNode::PLAYER))
("HERO", make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO));
#define BONUS_LOG_LINE(x) logBonus->traceStream() << x

View File

@ -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<bool(size_t)> isValid)
{
std::string errors;
if (!schemas.isNull())
{
std::string errors = "<tested schemas>\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 += "<end of schema>\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");
}

View File

@ -174,9 +174,6 @@ void CResourceLoader::addLoader(std::string mountPoint, shared_ptr<ISimpleResour
ResourceID ident(mountPoint, entry.first.getName(), entry.first.getType());
ResourceLocator locator(loader.get(), entry.second);
if (ident.getType() == EResType::OTHER)
logGlobal->warnStream() << "Warning: unknown file type: " << entry.second;
resources[ident].push_back(locator);
}
}

View File

@ -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)