mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +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:
		| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			} | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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" | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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": {} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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" : | ||||
|   | ||||
| @@ -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" : | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| { | ||||
| 	"neutral" : | ||||
| 	{ | ||||
| 		"name" : "Neutral", | ||||
| 		"index" : 9, | ||||
| 		"alignment" : "neutral", | ||||
| 		"creatureBackground" : | ||||
|   | ||||
| @@ -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":{ | ||||
|   | ||||
| @@ -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": { | ||||
|   | ||||
| @@ -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" } | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -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":{ | ||||
|   | ||||
| @@ -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":{ | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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" }, | ||||
|   | ||||
| @@ -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"}, | ||||
|   | ||||
| @@ -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": { | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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"]))); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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"); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user