mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	some changes towards editing H3 objects via mods. Should be stable, report if not.
- removed duplicated json loading code in handlers - simpler and mod-friendly handling of combined artifacts - reorganized CCreature to avoid huge number of fields in one structure
This commit is contained in:
		| @@ -137,7 +137,10 @@ bool CDefenceAnimation::init() | ||||
| 		if(attacker != NULL) | ||||
| 		{ | ||||
| 			int attackerAnimType = owner->creAnims[attacker->ID]->getType(); | ||||
| 			if( attackerAnimType == 11 && attackerAnimType == 12 && attackerAnimType == 13 && owner->creAnims[attacker->ID]->getFrame() < attacker->getCreature()->attackClimaxFrame ) | ||||
| 			if( ( attackerAnimType == CCreatureAnim::ATTACK_UP || | ||||
| 			    attackerAnimType == CCreatureAnim::ATTACK_FRONT || | ||||
| 			    attackerAnimType == CCreatureAnim::ATTACK_DOWN ) && | ||||
| 			    owner->creAnims[attacker->ID]->getFrame() < attacker->getCreature()->animation.attackClimaxFrame ) | ||||
| 				return false; | ||||
| 		} | ||||
|  | ||||
| @@ -738,7 +741,7 @@ bool CShootingAnimation::init() | ||||
|  | ||||
| 	spi.step = 0; | ||||
| 	spi.frameNum = 0; | ||||
| 	spi.spin = shooterInfo->projectileSpin; | ||||
| 	spi.spin = shooterInfo->animation.projectileSpin; | ||||
|  | ||||
| 	Point xycoord = CClickableHex::getXYUnitAnim(shooter->position, true, shooter, owner); | ||||
| 	Point destcoord; | ||||
| @@ -756,20 +759,20 @@ bool CShootingAnimation::init() | ||||
| 		if (projectileAngle > straightAngle) | ||||
| 		{ | ||||
| 			//upper shot | ||||
| 			spi.x = xycoord.x + projectileOrigin.x + shooterInfo->upperRightMissleOffsetX; | ||||
| 			spi.y = xycoord.y + projectileOrigin.y + shooterInfo->upperRightMissleOffsetY; | ||||
| 			spi.x = xycoord.x + projectileOrigin.x + shooterInfo->animation.upperRightMissleOffsetX; | ||||
| 			spi.y = xycoord.y + projectileOrigin.y + shooterInfo->animation.upperRightMissleOffsetY; | ||||
| 		} | ||||
| 		else if (projectileAngle < -straightAngle)  | ||||
| 		{ | ||||
| 			//lower shot | ||||
| 			spi.x = xycoord.x + projectileOrigin.x + shooterInfo->lowerRightMissleOffsetX; | ||||
| 			spi.y = xycoord.y + projectileOrigin.y + shooterInfo->lowerRightMissleOffsetY; | ||||
| 			spi.x = xycoord.x + projectileOrigin.x + shooterInfo->animation.lowerRightMissleOffsetX; | ||||
| 			spi.y = xycoord.y + projectileOrigin.y + shooterInfo->animation.lowerRightMissleOffsetY; | ||||
| 		} | ||||
| 		else  | ||||
| 		{ | ||||
| 			//straight shot | ||||
| 			spi.x = xycoord.x + projectileOrigin.x + shooterInfo->rightMissleOffsetX; | ||||
| 			spi.y = xycoord.y + projectileOrigin.y + shooterInfo->rightMissleOffsetY; | ||||
| 			spi.x = xycoord.x + projectileOrigin.x + shooterInfo->animation.rightMissleOffsetX; | ||||
| 			spi.y = xycoord.y + projectileOrigin.y + shooterInfo->animation.rightMissleOffsetY; | ||||
| 		} | ||||
|  | ||||
| 		double animSpeed = 23.0 * owner->getAnimSpeed(); // flight speed of projectile | ||||
| @@ -808,8 +811,8 @@ bool CShootingAnimation::init() | ||||
| 			spi.lastStep = static_cast<int>((spi.catapultInfo->toX - spi.catapultInfo->fromX) / animSpeed); | ||||
| 			spi.dx = animSpeed; | ||||
| 			spi.dy = 0; | ||||
| 			spi.x = xycoord.x + projectileOrigin.x + shooterInfo->rightMissleOffsetX + 17.; | ||||
| 			spi.y = xycoord.y + projectileOrigin.y + shooterInfo->rightMissleOffsetY + 10.; | ||||
| 			spi.x = xycoord.x + projectileOrigin.x + shooterInfo->animation.rightMissleOffsetX + 17.; | ||||
| 			spi.y = xycoord.y + projectileOrigin.y + shooterInfo->animation.rightMissleOffsetY + 10.; | ||||
|  | ||||
| 			// Add explosion anim | ||||
| 			int xEnd = static_cast<int>(spi.x + spi.lastStep * spi.dx); | ||||
| @@ -830,7 +833,7 @@ bool CShootingAnimation::init() | ||||
| 	} | ||||
|  | ||||
| 	// Set projectile animation start delay which is specified in frames | ||||
| 	spi.animStartDelay = shooterInfo->attackClimaxFrame; | ||||
| 	spi.animStartDelay = shooterInfo->animation.attackClimaxFrame; | ||||
| 	owner->projectiles.push_back(spi); | ||||
|  | ||||
| 	//attack animation | ||||
|   | ||||
| @@ -300,7 +300,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe | ||||
| 			else | ||||
| 				creature = s->getCreature(); | ||||
|  | ||||
| 			projectile = CDefHandler::giveDef(creature->projectile); | ||||
| 			projectile = CDefHandler::giveDef(creature->animation.projectileImageName); | ||||
|  | ||||
| 			if(projectile->ourImages.size() > 2) //add symmetric images | ||||
| 			{ | ||||
|   | ||||
| @@ -123,7 +123,7 @@ | ||||
| 			"id": 8, | ||||
| 			"class" : "cleric", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 46 ], | ||||
| 			"spellbook": [ "stoneSkin" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -138,7 +138,7 @@ | ||||
| 			"id": 9, | ||||
| 			"class" : "cleric", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 41 ], | ||||
| 			"spellbook": [ "bless" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -153,7 +153,7 @@ | ||||
| 			"id": 10, | ||||
| 			"class" : "cleric", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 45 ], | ||||
| 			"spellbook": [ "weakness" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -168,7 +168,7 @@ | ||||
| 			"id": 11, | ||||
| 			"class" : "cleric", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 20 ], | ||||
| 			"spellbook": [ "frostRing" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "advanced" } | ||||
| @@ -182,7 +182,7 @@ | ||||
| 			"id": 12, | ||||
| 			"class" : "cleric", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 42 ], | ||||
| 			"spellbook": [ "curse" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -197,7 +197,7 @@ | ||||
| 			"id": 13, | ||||
| 			"class" : "cleric", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 35 ], | ||||
| 			"spellbook": [ "dispel" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -211,7 +211,7 @@ | ||||
| 		{ | ||||
| 			"id": 14, | ||||
| 			"class" : "cleric", | ||||
| 			"spellbook": [ 48 ], | ||||
| 			"spellbook": [ "prayer" ], | ||||
| 			"female": false, | ||||
| 			"skills": | ||||
| 			[ | ||||
| @@ -227,7 +227,7 @@ | ||||
| 			"id": 15, | ||||
| 			"class" : "cleric", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 37 ], | ||||
| 			"spellbook": [ "cure" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -351,7 +351,7 @@ | ||||
| 		{ | ||||
| 			"id": 24, | ||||
| 			"class" : "druid", | ||||
| 			"spellbook": [ 55 ], | ||||
| 			"spellbook": [ "slayer" ], | ||||
| 			"female": false, | ||||
| 			"skills": | ||||
| 			[ | ||||
| @@ -367,7 +367,7 @@ | ||||
| 			"id": 25, | ||||
| 			"class" : "druid", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 37 ], | ||||
| 			"spellbook": [ "cure" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "advanced" }, | ||||
| @@ -382,7 +382,7 @@ | ||||
| 			"id": 26, | ||||
| 			"class" : "druid", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 42 ], | ||||
| 			"spellbook": [ "curse" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -397,7 +397,7 @@ | ||||
| 			"id": 27, | ||||
| 			"class" : "druid", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 0 ], | ||||
| 			"spellbook": [ "summonBoat" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -412,7 +412,7 @@ | ||||
| 			"id": 28, | ||||
| 			"class" : "druid", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -426,7 +426,7 @@ | ||||
| 		{ | ||||
| 			"id": 29, | ||||
| 			"class" : "druid", | ||||
| 			"spellbook": [ 51 ], | ||||
| 			"spellbook": [ "fortune" ], | ||||
| 			"female": true, | ||||
| 			"skills": | ||||
| 			[ | ||||
| @@ -442,7 +442,7 @@ | ||||
| 			"id": 30, | ||||
| 			"class" : "druid", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 16 ], | ||||
| 			"spellbook": [ "iceBolt" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -457,7 +457,7 @@ | ||||
| 			"id": 31, | ||||
| 			"class" : "druid", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 30 ], | ||||
| 			"spellbook": [ "protectAir" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -472,7 +472,7 @@ | ||||
| 			"id": 32, | ||||
| 			"class" : "alchemist", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 27 ], | ||||
| 			"spellbook": [ "shield" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "scouting", "level": "basic" }, | ||||
| @@ -487,7 +487,7 @@ | ||||
| 			"id": 33, | ||||
| 			"class" : "alchemist", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "scholar", "level": "advanced" } | ||||
| @@ -500,7 +500,7 @@ | ||||
| 		{ | ||||
| 			"id": 34, | ||||
| 			"class" : "alchemist", | ||||
| 			"spellbook": [ 53 ], | ||||
| 			"spellbook": [ "haste" ], | ||||
| 			"female": true, | ||||
| 			"skills": | ||||
| 			[ | ||||
| @@ -516,7 +516,7 @@ | ||||
| 			"id": 35, | ||||
| 			"class" : "alchemist", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 27 ], | ||||
| 			"spellbook": [ "shield" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "scholar", "level": "basic" }, | ||||
| @@ -531,7 +531,7 @@ | ||||
| 			"id": 36, | ||||
| 			"class" : "alchemist", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "mysticism", "level": "basic" }, | ||||
| @@ -546,7 +546,7 @@ | ||||
| 			"id": 37, | ||||
| 			"class" : "alchemist", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 53 ], | ||||
| 			"spellbook": [ "haste" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "scholar", "level": "basic" }, | ||||
| @@ -561,7 +561,7 @@ | ||||
| 			"id": 38, | ||||
| 			"class" : "alchemist", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "mysticism", "level": "basic" }, | ||||
| @@ -575,7 +575,7 @@ | ||||
| 		{ | ||||
| 			"id": 39, | ||||
| 			"class" : "alchemist", | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"female": true, | ||||
| 			"skills": | ||||
| 			[ | ||||
| @@ -591,7 +591,7 @@ | ||||
| 			"id": 40, | ||||
| 			"class" : "wizard", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 60 ], | ||||
| 			"spellbook": [ "hypnotize" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "advanced" } | ||||
| @@ -605,7 +605,7 @@ | ||||
| 			"id": 41, | ||||
| 			"class" : "wizard", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 46 ], | ||||
| 			"spellbook": [ "stoneSkin" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -620,7 +620,7 @@ | ||||
| 			"id": 42, | ||||
| 			"class" : "wizard", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 35 ], | ||||
| 			"spellbook": [ "dispel" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -635,7 +635,7 @@ | ||||
| 			"id": 43, | ||||
| 			"class" : "wizard", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 51 ], | ||||
| 			"spellbook": [ "fortune" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -649,7 +649,7 @@ | ||||
| 		{ | ||||
| 			"id": 44, | ||||
| 			"class" : "wizard", | ||||
| 			"spellbook": [ 27 ], | ||||
| 			"spellbook": [ "shield" ], | ||||
| 			"female": false, | ||||
| 			"skills": | ||||
| 			[ | ||||
| @@ -665,7 +665,7 @@ | ||||
| 			"id": 45, | ||||
| 			"class" : "wizard", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 19 ], | ||||
| 			"spellbook": [ "chainLightning" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -680,7 +680,7 @@ | ||||
| 			"id": 46, | ||||
| 			"class" : "wizard", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 53 ], | ||||
| 			"spellbook": [ "haste" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -695,7 +695,7 @@ | ||||
| 			"id": 47, | ||||
| 			"class" : "wizard", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 42 ], | ||||
| 			"spellbook": [ "curse" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -818,7 +818,7 @@ | ||||
| 		{ | ||||
| 			"id": 56, | ||||
| 			"class" : "heretic", | ||||
| 			"spellbook": [ 3 ], | ||||
| 			"spellbook": [ "viewEarth" ], | ||||
| 			"female": false, | ||||
| 			"skills": | ||||
| 			[ | ||||
| @@ -834,7 +834,7 @@ | ||||
| 			"id": 57, | ||||
| 			"class" : "heretic", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 22 ], | ||||
| 			"spellbook": [ "inferno" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -849,7 +849,7 @@ | ||||
| 			"id": 58, | ||||
| 			"class" : "heretic", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 30 ], | ||||
| 			"spellbook": [ "protectAir" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -864,7 +864,7 @@ | ||||
| 			"id": 59, | ||||
| 			"class" : "heretic", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 45 ], | ||||
| 			"spellbook": [ "weakness" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -879,7 +879,7 @@ | ||||
| 			"id": 60, | ||||
| 			"class" : "heretic", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 53 ], | ||||
| 			"spellbook": [ "haste" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -894,7 +894,7 @@ | ||||
| 			"id": 61, | ||||
| 			"class" : "heretic", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 43 ], | ||||
| 			"spellbook": [ "bloodlust" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -909,7 +909,7 @@ | ||||
| 			"id": 62, | ||||
| 			"class" : "heretic", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 46 ], | ||||
| 			"spellbook": [ "stoneSkin" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -924,7 +924,7 @@ | ||||
| 			"id": 63, | ||||
| 			"class" : "heretic", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 21 ], | ||||
| 			"spellbook": [ "fireball" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -939,7 +939,7 @@ | ||||
| 			"id": 64, | ||||
| 			"class" : "deathknight", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 53 ], | ||||
| 			"spellbook": [ "haste" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -954,7 +954,7 @@ | ||||
| 			"id": 65, | ||||
| 			"class" : "deathknight", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 46 ], | ||||
| 			"spellbook": [ "stoneSkin" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -969,7 +969,7 @@ | ||||
| 			"id": 66, | ||||
| 			"class" : "deathknight", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 54 ], | ||||
| 			"spellbook": [ "slow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -984,7 +984,7 @@ | ||||
| 			"id": 67, | ||||
| 			"class" : "deathknight", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -999,7 +999,7 @@ | ||||
| 			"id": 68, | ||||
| 			"class" : "deathknight", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -1014,7 +1014,7 @@ | ||||
| 			"id": 69, | ||||
| 			"class" : "deathknight", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "advanced" } | ||||
| @@ -1028,7 +1028,7 @@ | ||||
| 			"id": 70, | ||||
| 			"class" : "deathknight", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -1043,7 +1043,7 @@ | ||||
| 			"id": 71, | ||||
| 			"class" : "deathknight", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 27 ], | ||||
| 			"spellbook": [ "shield" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -1058,7 +1058,7 @@ | ||||
| 			"id": 72, | ||||
| 			"class" : "necromancer", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 24 ], | ||||
| 			"spellbook": [ "deathRipple" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -1073,7 +1073,7 @@ | ||||
| 			"id": 73, | ||||
| 			"class" : "necromancer", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 23 ], | ||||
| 			"spellbook": [ "meteorShower" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -1088,7 +1088,7 @@ | ||||
| 			"id": 74, | ||||
| 			"class" : "necromancer", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 54 ], | ||||
| 			"spellbook": [ "slow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -1103,7 +1103,7 @@ | ||||
| 			"id": 75, | ||||
| 			"class" : "necromancer", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 27 ], | ||||
| 			"spellbook": [ "shield" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -1118,7 +1118,7 @@ | ||||
| 			"id": 76, | ||||
| 			"class" : "necromancer", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 39 ], | ||||
| 			"spellbook": [ "animateDead" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -1133,7 +1133,7 @@ | ||||
| 			"id": 77, | ||||
| 			"class" : "necromancer", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 46 ], | ||||
| 			"spellbook": [ "stoneSkin" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -1148,7 +1148,7 @@ | ||||
| 			"id": 78, | ||||
| 			"class" : "necromancer", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 42 ], | ||||
| 			"spellbook": [ "curse" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "advanced" } | ||||
| @@ -1162,7 +1162,7 @@ | ||||
| 			"id": 79, | ||||
| 			"class" : "necromancer", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 30 ], | ||||
| 			"spellbook": [ "protectAir" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "basic" }, | ||||
| @@ -1287,7 +1287,7 @@ | ||||
| 		{ | ||||
| 			"id": 88, | ||||
| 			"class" : "overlord", | ||||
| 			"spellbook": [ 38 ], | ||||
| 			"spellbook": [ "resurrection" ], | ||||
| 			"female": false, | ||||
| 			"skills": | ||||
| 			[ | ||||
| @@ -1303,7 +1303,7 @@ | ||||
| 			"id": 89, | ||||
| 			"class" : "overlord", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 27 ], | ||||
| 			"spellbook": [ "shield" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1318,7 +1318,7 @@ | ||||
| 			"id": 90, | ||||
| 			"class" : "overlord", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 43 ], | ||||
| 			"spellbook": [ "bloodlust" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1333,7 +1333,7 @@ | ||||
| 			"id": 91, | ||||
| 			"class" : "overlord", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 38 ], | ||||
| 			"spellbook": [ "resurrection" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "advanced" } | ||||
| @@ -1347,7 +1347,7 @@ | ||||
| 			"id": 92, | ||||
| 			"class" : "overlord", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 54 ], | ||||
| 			"spellbook": [ "slow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1362,7 +1362,7 @@ | ||||
| 			"id": 93, | ||||
| 			"class" : "overlord", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 23 ], | ||||
| 			"spellbook": [ "meteorShower" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1377,7 +1377,7 @@ | ||||
| 			"id": 94, | ||||
| 			"class" : "overlord", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 30 ], | ||||
| 			"spellbook": [ "protectAir" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1392,7 +1392,7 @@ | ||||
| 			"id": 95, | ||||
| 			"class" : "overlord", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 46 ], | ||||
| 			"spellbook": [ "stoneSkin" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1513,7 +1513,7 @@ | ||||
| 		{ | ||||
| 			"id": 104, | ||||
| 			"class" : "battlemage", | ||||
| 			"spellbook": [ 43 ], | ||||
| 			"spellbook": [ "bloodlust" ], | ||||
| 			"female": true, | ||||
| 			"skills": | ||||
| 			[ | ||||
| @@ -1529,7 +1529,7 @@ | ||||
| 			"id": 105, | ||||
| 			"class" : "battlemage", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1544,7 +1544,7 @@ | ||||
| 			"id": 106, | ||||
| 			"class" : "battlemage", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 46 ], | ||||
| 			"spellbook": [ "stoneSkin" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1559,7 +1559,7 @@ | ||||
| 			"id": 107, | ||||
| 			"class" : "battlemage", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 53 ], | ||||
| 			"spellbook": [ "haste" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1574,7 +1574,7 @@ | ||||
| 			"id": 108, | ||||
| 			"class" : "battlemage", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 44 ], | ||||
| 			"spellbook": [ "precision" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1588,7 +1588,7 @@ | ||||
| 		{ | ||||
| 			"id": 109, | ||||
| 			"class" : "battlemage", | ||||
| 			"spellbook": [ 54 ], | ||||
| 			"spellbook": [ "slow" ], | ||||
| 			"female": true, | ||||
| 			"skills": | ||||
| 			[ | ||||
| @@ -1604,7 +1604,7 @@ | ||||
| 			"id": 110, | ||||
| 			"class" : "battlemage", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 30 ], | ||||
| 			"spellbook": [ "protectAir" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1619,7 +1619,7 @@ | ||||
| 			"id": 111, | ||||
| 			"class" : "battlemage", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 43 ], | ||||
| 			"spellbook": [ "bloodlust" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1744,7 +1744,7 @@ | ||||
| 		{ | ||||
| 			"id": 120, | ||||
| 			"class" : "witch", | ||||
| 			"spellbook": [ 45 ], | ||||
| 			"spellbook": [ "weakness" ], | ||||
| 			"female": true, | ||||
| 			"skills": | ||||
| 			[ | ||||
| @@ -1759,7 +1759,7 @@ | ||||
| 			"id": 121, | ||||
| 			"class" : "witch", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1774,7 +1774,7 @@ | ||||
| 			"id": 122, | ||||
| 			"class" : "witch", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 54 ], | ||||
| 			"spellbook": [ "slow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1789,7 +1789,7 @@ | ||||
| 			"id": 123, | ||||
| 			"class" : "witch", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 31 ], | ||||
| 			"spellbook": [ "protectFire" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1804,7 +1804,7 @@ | ||||
| 			"id": 124, | ||||
| 			"class" : "witch", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 46 ], | ||||
| 			"spellbook": [ "stoneSkin" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1819,7 +1819,7 @@ | ||||
| 			"id": 125, | ||||
| 			"class" : "witch", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 27 ], | ||||
| 			"spellbook": [ "shield" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1834,7 +1834,7 @@ | ||||
| 			"id": 126, | ||||
| 			"class" : "witch", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 35 ], | ||||
| 			"spellbook": [ "dispel" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1849,7 +1849,7 @@ | ||||
| 			"id": 127, | ||||
| 			"class" : "witch", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 46 ], | ||||
| 			"spellbook": [ "stoneSkin" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -1983,7 +1983,7 @@ | ||||
| 		{ | ||||
| 			"id": 136, | ||||
| 			"class" : "elementalist", | ||||
| 			"spellbook": [ 13 ], | ||||
| 			"spellbook": [ "fireWall" ], | ||||
| 			"female": true, | ||||
| 			"skills": | ||||
| 			[ | ||||
| @@ -1999,7 +1999,7 @@ | ||||
| 			"id": 137, | ||||
| 			"class" : "elementalist", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 53 ], | ||||
| 			"spellbook": [ "haste" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -2014,7 +2014,7 @@ | ||||
| 			"id": 138, | ||||
| 			"class" : "elementalist", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -2029,7 +2029,7 @@ | ||||
| 			"id": 139, | ||||
| 			"class" : "elementalist", | ||||
| 			"female": true, | ||||
| 			"spellbook": [ 46 ], | ||||
| 			"spellbook": [ "stoneSkin" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -2044,7 +2044,7 @@ | ||||
| 			"id": 140, | ||||
| 			"class" : "elementalist", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 43 ], | ||||
| 			"spellbook": [ "bloodlust" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -2059,7 +2059,7 @@ | ||||
| 			"id": 141, | ||||
| 			"class" : "elementalist", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 47 ], | ||||
| 			"spellbook": [ "disruptingRay" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -2074,7 +2074,7 @@ | ||||
| 			"id": 142, | ||||
| 			"class" : "elementalist", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 35 ], | ||||
| 			"spellbook": [ "dispel" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -2089,7 +2089,7 @@ | ||||
| 			"id": 143, | ||||
| 			"class" : "elementalist", | ||||
| 			"female": false, | ||||
| 			"spellbook": [ 54 ], | ||||
| 			"spellbook": [ "slow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -2119,7 +2119,7 @@ | ||||
| 			"class" : "witch", | ||||
| 			"female": true, | ||||
| 			"special" : true, | ||||
| 			"spellbook": [ 22 ], | ||||
| 			"spellbook": [ "inferno" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "basic" }, | ||||
| @@ -2149,7 +2149,7 @@ | ||||
| 			"class" : "wizard", | ||||
| 			"female": false, | ||||
| 			"special" : true, | ||||
| 			"spellbook": [ 53 ], | ||||
| 			"spellbook": [ "haste" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "wisdom", "level": "advanced" } | ||||
| @@ -2197,7 +2197,7 @@ | ||||
| 			"class" : "deathknight", | ||||
| 			"female": false, | ||||
| 			"special" : true, | ||||
| 			"spellbook": [ 54 ], | ||||
| 			"spellbook": [ "slow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "necromancy", "level": "advanced" } | ||||
| @@ -2214,7 +2214,7 @@ | ||||
| 			"class" : "warlock", | ||||
| 			"female": true, | ||||
| 			"special" : true, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "estates", "level": "basic" }, | ||||
| @@ -2246,7 +2246,7 @@ | ||||
| 			"class" : "warlock", | ||||
| 			"female": true, | ||||
| 			"special" : true, | ||||
| 			"spellbook": [ 15 ], | ||||
| 			"spellbook": [ "magicArrow" ], | ||||
| 			"skills": | ||||
| 			[ | ||||
| 				{ "skill" : "estates", "level": "basic" }, | ||||
|   | ||||
| @@ -78,102 +78,12 @@ bool CArtifact::isBig () const | ||||
| 	return VLC->arth->isBigArtifact(id); | ||||
| } | ||||
|  | ||||
| // /** | ||||
| //  * Checks whether the artifact fits at a given slot. | ||||
| //  * @param artifWorn A hero's set of worn artifacts. | ||||
| //  */ | ||||
| // bool CArtifact::fitsAt (const std::map<ui16, const CArtifact*> &artifWorn, ui16 slotID) const | ||||
| // { | ||||
| // 	if (!vstd::contains(possibleSlots, slotID)) | ||||
| // 		return false; | ||||
| // | ||||
| // 	// Can't put an artifact in a locked slot. | ||||
| // 	std::map<ui16, const CArtifact*>::const_iterator it = artifWorn.find(slotID); | ||||
| // 	if (it != artifWorn.end() && it->second->id == 145) | ||||
| // 		return false; | ||||
| // | ||||
| // 	// Check if a combination artifact fits. | ||||
| // 	// TODO: Might want a more general algorithm? | ||||
| // 	//       Assumes that misc & rings fits only in their slots, and others in only one slot and no duplicates. | ||||
| // 	if (constituents != NULL) | ||||
| // 	{ | ||||
| // 		std::map<ui16, const CArtifact*> tempArtifWorn = artifWorn; | ||||
| // 		const ui16 ringSlots[] = {6, 7}; | ||||
| // 		const ui16 miscSlots[] = {9, 10, 11, 12, 18}; | ||||
| // 		int rings = 0; | ||||
| // 		int misc = 0; | ||||
| // | ||||
| // 		VLC->arth->unequipArtifact(tempArtifWorn, slotID); | ||||
| // | ||||
| // 		BOOST_FOREACH(ui32 constituentID, *constituents) | ||||
| // 		{ | ||||
| // 			const CArtifact& constituent = *VLC->arth->artifacts[constituentID]; | ||||
| // 			const int slot = constituent.possibleSlots[0]; | ||||
| // | ||||
| // 			if (slot == 6 || slot == 7) | ||||
| // 				rings++; | ||||
| // 			else if ((slot >= 9 && slot <= 12) || slot == 18) | ||||
| // 				misc++; | ||||
| // 			else if (tempArtifWorn.find(slot) != tempArtifWorn.end()) | ||||
| // 				return false; | ||||
| // 		} | ||||
| // | ||||
| // 		// Ensure enough ring slots are free | ||||
| // 		for (int i = 0; i < sizeof(ringSlots)/sizeof(*ringSlots); i++) | ||||
| // 		{ | ||||
| // 			if (tempArtifWorn.find(ringSlots[i]) == tempArtifWorn.end() || ringSlots[i] == slotID) | ||||
| // 				rings--; | ||||
| // 		} | ||||
| // 		if (rings > 0) | ||||
| // 			return false; | ||||
| // | ||||
| // 		// Ensure enough misc slots are free. | ||||
| // 		for (int i = 0; i < sizeof(miscSlots)/sizeof(*miscSlots); i++) | ||||
| // 		{ | ||||
| // 			if (tempArtifWorn.find(miscSlots[i]) == tempArtifWorn.end() || miscSlots[i] == slotID) | ||||
| // 				misc--; | ||||
| // 		} | ||||
| // 		if (misc > 0) | ||||
| // 			return false; | ||||
| // 	} | ||||
| // | ||||
| // 	return true; | ||||
| // } | ||||
|  | ||||
| // bool CArtifact::canBeAssembledTo (const std::map<ui16, const CArtifact*> &artifWorn, ui32 artifactID) const | ||||
| // { | ||||
| // 	if (constituentOf == NULL || !vstd::contains(*constituentOf, artifactID)) | ||||
| // 		return false; | ||||
| // | ||||
| // 	const CArtifact &artifact = *VLC->arth->artifacts[artifactID]; | ||||
| // 	assert(artifact.constituents); | ||||
| // | ||||
| // 	BOOST_FOREACH(ui32 constituentID, *artifact.constituents) | ||||
| // 	{ | ||||
| // 		bool found = false; | ||||
| // 		for (std::map<ui16, const CArtifact*>::const_iterator it = artifWorn.begin(); it != artifWorn.end(); ++it) | ||||
| // 		{ | ||||
| // 			if (it->second->id == constituentID) | ||||
| // 			{ | ||||
| // 				found = true; | ||||
| // 				break; | ||||
| // 			} | ||||
| // 		} | ||||
| // 		if (!found) | ||||
| // 			return false; | ||||
| // 	} | ||||
| // | ||||
| // 	return true; | ||||
| // } | ||||
|  | ||||
| CArtifact::CArtifact() | ||||
| { | ||||
| 	setNodeType(ARTIFACT); | ||||
| 	possibleSlots[ArtBearer::HERO]; //we want to generate map entry even if it will be empty | ||||
| 	possibleSlots[ArtBearer::CREATURE]; //we want to generate map entry even if it will be empty | ||||
| 	possibleSlots[ArtBearer::COMMANDER]; | ||||
| 	constituents = NULL; //default pointer to zero | ||||
| 	constituentOf = NULL; | ||||
| } | ||||
|  | ||||
| CArtifact::~CArtifact() | ||||
| @@ -205,21 +115,6 @@ std::string CArtifact::nodeName() const | ||||
| { | ||||
| 	return "Artifact: " + Name(); | ||||
| } | ||||
| // void CArtifact::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const | ||||
| // { | ||||
| // 	//combined artifact carries bonuses from its parts | ||||
| // 	if(constituents) | ||||
| // 	{ | ||||
| // 		BOOST_FOREACH(ui32 id, *constituents) | ||||
| // 			out.insert(VLC->arth->artifacts[id]); | ||||
| // 	} | ||||
| // } | ||||
|  | ||||
| // void CScroll::Init() | ||||
| // { | ||||
| // // 	addNewBonus (Bonus (Bonus::PERMANENT, Bonus::SPELL, Bonus::ARTIFACT, 1, id, spellid, Bonus::INDEPENDENT_MAX)); | ||||
| // // 	//boost::algorithm::replace_first(description, "[spell name]", VLC->spellh->spells[spellid].name); | ||||
| // } | ||||
|  | ||||
| void CArtifact::addNewBonus(Bonus *b) | ||||
| { | ||||
| @@ -229,19 +124,6 @@ void CArtifact::addNewBonus(Bonus *b) | ||||
| 	CBonusSystemNode::addNewBonus(b); | ||||
| } | ||||
|  | ||||
| void CArtifact::setName (std::string desc) | ||||
| { | ||||
| 	name = desc; | ||||
| } | ||||
| void CArtifact::setDescription (std::string desc) | ||||
| { | ||||
| 	description = desc; | ||||
| } | ||||
| void CArtifact::setEventText (std::string desc) | ||||
| { | ||||
| 	eventText = desc; | ||||
| } | ||||
|  | ||||
| void CGrowingArtifact::levelUpArtifact (CArtifactInstance * art) | ||||
| { | ||||
| 	Bonus b; | ||||
| @@ -277,20 +159,20 @@ CArtHandler::CArtHandler() | ||||
|  | ||||
| CArtHandler::~CArtHandler() | ||||
| { | ||||
| 	for (std::vector< ConstTransitivePtr<CArtifact> >::iterator it = artifacts.begin(); it != artifacts.end(); ++it) | ||||
| 	{ | ||||
| 		delete (*it)->constituents; | ||||
| 		delete (*it)->constituentOf; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CArtHandler::loadArtifacts(bool onlyTxt) | ||||
| { | ||||
| 	std::vector<ui16> slots; | ||||
| 	slots += 17, 16, 15, 14, 13, 18, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0; | ||||
| 	if (onlyTxt) | ||||
| 		return; // looks to be broken anyway... | ||||
|  | ||||
| 	std::vector<ui16> artSlots; | ||||
| 	artSlots += 17, 16, 15, 14, 13, 18, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0; | ||||
|  | ||||
| 	growingArtifacts += ArtifactID::AXE_OF_SMASHING, ArtifactID::MITHRIL_MAIL, | ||||
| 		ArtifactID::SWORD_OF_SHARPNESS, ArtifactID::PENDANT_OF_SORCERY, ArtifactID::BOOTS_OF_HASTE, | ||||
| 		ArtifactID::BOW_OF_SEEKING, ArtifactID::DRAGON_EYE_RING; | ||||
|  | ||||
| 	static std::map<char, CArtifact::EartClass> classes = | ||||
| 	  map_list_of('S',CArtifact::ART_SPECIAL)('T',CArtifact::ART_TREASURE)('N',CArtifact::ART_MINOR)('J',CArtifact::ART_MAJOR)('R',CArtifact::ART_RELIC); | ||||
|  | ||||
| @@ -313,32 +195,32 @@ void CArtHandler::loadArtifacts(bool onlyTxt) | ||||
| 		{ | ||||
| 			art = new CArtifact(); | ||||
| 		} | ||||
| 		CArtifact &nart = *art; | ||||
| 		nart.id=i; | ||||
| 		nart.iconIndex=i; | ||||
| 		nart.setName (parser.readString()); | ||||
| 		nart.setEventText (events.readString()); | ||||
| 		art->id=i; | ||||
| 		art->iconIndex=i; | ||||
| 		art->name = parser.readString(); | ||||
| 		art->eventText = events.readString(); | ||||
| 		events.endLine(); | ||||
|  | ||||
| 		nart.price= parser.readNumber(); | ||||
| 		art->price= parser.readNumber(); | ||||
|  | ||||
| 		for(int j=0;j<slots.size();j++) | ||||
| 		for(int j=0; j<artSlots.size(); j++) | ||||
| 		{ | ||||
| 			if(parser.readString() == "x") | ||||
| 				nart.possibleSlots[ArtBearer::HERO].push_back(ArtifactPosition(slots[j])); | ||||
| 				art->possibleSlots[ArtBearer::HERO].push_back(ArtifactPosition(artSlots[j])); | ||||
| 		} | ||||
| 		nart.aClass = classes[parser.readString()[0]]; | ||||
| 		art->aClass = classes[parser.readString()[0]]; | ||||
|  | ||||
| 		//load description and remove quotation marks | ||||
| 		nart.setDescription (parser.readString()); | ||||
| 		art->description = parser.readString(); | ||||
|  | ||||
| 		parser.endLine(); | ||||
|  | ||||
| 		if(onlyTxt) | ||||
| 		if(onlyTxt) // FIXME: pointer to art will be lost. Bug? | ||||
| 			continue; | ||||
|  | ||||
| 		artifacts.push_back(&nart); | ||||
| 		artifacts.push_back(art); | ||||
| 	} | ||||
|  | ||||
| 	if (VLC->modh->modules.COMMANDERS) | ||||
| 	{ //TODO: move all artifacts config to separate json file | ||||
| 		const JsonNode config(ResourceID("config/commanders.json")); | ||||
| @@ -356,65 +238,51 @@ void CArtHandler::loadArtifacts(bool onlyTxt) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	sortArts(); | ||||
| 	if(onlyTxt) | ||||
| 		return; | ||||
|  | ||||
| 	addBonuses(); | ||||
| } | ||||
| 	JsonNode config(ResourceID("config/artifacts.json")); | ||||
|  | ||||
| void CArtHandler::reverseMapArtifactConstituents() // Populate reverse mappings of combinational artifacts. | ||||
| { | ||||
| 	BOOST_FOREACH(CArtifact *artifact, artifacts) | ||||
| 	BOOST_FOREACH(auto & node, config["artifacts"].Struct()) | ||||
| 	{ | ||||
| 		if (artifact->constituents != NULL) | ||||
| 		{ | ||||
| 			BOOST_FOREACH(ui32 constituentID, *artifact->constituents) | ||||
| 			{ | ||||
| 				if (artifacts[constituentID]->constituentOf == NULL) | ||||
| 					artifacts[constituentID]->constituentOf = new std::vector<ArtifactID>(); | ||||
| 				artifacts[constituentID]->constituentOf->push_back(artifact->id); | ||||
| 			} | ||||
| 		} | ||||
| 		int numeric = node.second["id"].Float(); | ||||
| 		CArtifact * art = artifacts[numeric]; | ||||
|  | ||||
| 		loadArtifactJson(art, node.second); | ||||
|  | ||||
| 		VLC->modh->identifiers.registerObject ("artifact." + node.first, numeric); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CArtHandler::load(const JsonNode & node) | ||||
| void CArtHandler::load(std::string objectID, const JsonNode & node) | ||||
| { | ||||
| 	BOOST_FOREACH(auto & entry, node.Struct()) | ||||
| 	{ | ||||
| 		if (!entry.second.isNull()) // may happens if mod removed creature by setting json entry to null | ||||
| 		{ | ||||
| 			CArtifact * art = loadArtifact(entry.second); | ||||
| 			art->id = ArtifactID(artifacts.size()); | ||||
| 	CArtifact * art = loadArtifact(node); | ||||
| 	art->id = ArtifactID(artifacts.size()); | ||||
|  | ||||
| 			artifacts.push_back(art); | ||||
| 			tlog5 << "Added artifact: " << entry.first << "\n"; | ||||
| 			VLC->modh->identifiers.registerObject (std::string("artifact.") + entry.first, art->id); | ||||
| 		} | ||||
| 	} | ||||
| 	artifacts.push_back(art); | ||||
| 	tlog5 << "Added artifact: " << objectID << "\n"; | ||||
| 	VLC->modh->identifiers.registerObject ("artifact." + objectID, art->id); | ||||
| } | ||||
|  | ||||
| CArtifact * CArtHandler::loadArtifact(const JsonNode & node) | ||||
| { | ||||
| 	CArtifact * art = new CArtifact; | ||||
| 	const JsonNode *value; | ||||
|  | ||||
| 	const JsonNode & text = node["text"]; | ||||
| 	art->setName		(text["name"].String()); | ||||
| 	art->setDescription	(text["description"].String()); | ||||
| 	art->setEventText		(text["event"].String()); | ||||
| 	art->name        = text["name"].String(); | ||||
| 	art->description = text["description"].String(); | ||||
| 	art->eventText   = text["event"].String(); | ||||
|  | ||||
| 	const JsonNode & graphics = node["graphics"]; | ||||
| 	art->iconIndex = graphics["iconIndex"].Float(); | ||||
| 	art->image = graphics["image"].String(); | ||||
| 	value = &graphics["large"]; | ||||
| 	if (!value->isNull()) | ||||
| 		art->large = value->String(); | ||||
|  | ||||
| 	if (!graphics["large"].loadTo(art->large)) | ||||
| 		art->large = art->image; | ||||
|  | ||||
| 	art->advMapDef = graphics["map"].String(); | ||||
|  | ||||
| 	art->price = node["value"].Float(); | ||||
|  | ||||
| 	{ | ||||
| 		auto it = artifactClassMap.find (node["class"].String()); | ||||
| 		if (it != artifactClassMap.end()) | ||||
| @@ -423,44 +291,14 @@ CArtifact * CArtHandler::loadArtifact(const JsonNode & node) | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			tlog2 << "Warning! Artifact rarity " << value->String() << " not recognized!"; | ||||
| 			tlog2 << "Warning! Artifact rarity " << node["class"].String() << " not recognized!"; | ||||
| 			art->aClass = CArtifact::ART_SPECIAL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	int bearerType = -1; | ||||
| 	bool heroArt = false; | ||||
|  | ||||
| 	if (!node["slot"].isNull()) //we assume non-hero slots are irrelevant? | ||||
| 	{ | ||||
| 		const JsonNode & bearer = node["type"]; | ||||
| 		BOOST_FOREACH (const JsonNode & b, bearer.Vector()) | ||||
| 		{ | ||||
| 			auto it = artifactBearerMap.find (b.String()); | ||||
| 			if (it != artifactBearerMap.end()) | ||||
| 			{ | ||||
| 				bearerType = it->second; | ||||
| 				switch (bearerType) | ||||
| 				{ | ||||
| 					case ArtBearer::HERO: //TODO: allow arts having several possible bearers | ||||
| 						heroArt = true; | ||||
| 						break; | ||||
| 					case ArtBearer::COMMANDER: | ||||
| 						makeItCommanderArt (art, false); //do not erase already existing slots | ||||
| 						break; | ||||
| 					case ArtBearer::CREATURE: | ||||
| 						makeItCreatureArt (art, false); | ||||
| 						break; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 				tlog2 << "Warning! Artifact type " << b.String() << " not recognized!"; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	value = &node["slot"]; | ||||
| 	if (!value->isNull() && heroArt) //we assume non-hero slots are irrelevant? | ||||
| 	{ | ||||
| 		std::string slotName = value->String(); | ||||
| 		std::string slotName = node["slot"].String(); | ||||
| 		if (slotName == "MISC") | ||||
| 		{ | ||||
| 			//unfortunatelly slot ids aare not continuous | ||||
| @@ -480,25 +318,64 @@ CArtifact * CArtHandler::loadArtifact(const JsonNode & node) | ||||
| 				art->possibleSlots[ArtBearer::HERO].push_back (slot); | ||||
| 			} | ||||
| 			else | ||||
| 				tlog2 << "Warning! Artifact slot " << value->String() << " not recognized!"; | ||||
| 				tlog2 << "Warning! Artifact slot " << node["slot"].String() << " not recognized!"; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	readComponents (node, art); | ||||
|  | ||||
| 	BOOST_FOREACH (const JsonNode &bonus, node["bonuses"].Vector()) | ||||
| 	{ | ||||
| 		auto b = JsonUtils::parseBonus(bonus); | ||||
| 		//TODO: bonus->sid = art->id; | ||||
| 		art->addNewBonus(b); | ||||
| 	} | ||||
| 	loadArtifactJson(art, node); | ||||
|  | ||||
| 	return art; | ||||
| } | ||||
|  | ||||
| void CArtHandler::loadArtifactJson(CArtifact * art, const JsonNode & artifact) | ||||
| { | ||||
| 	BOOST_FOREACH (auto b, artifact["bonuses"].Vector()) | ||||
| 	{ | ||||
| 		auto bonus = JsonUtils::parseBonus (b); | ||||
| 		bonus->sid = art->id; | ||||
| 		art->addNewBonus (bonus); | ||||
| 	} | ||||
| 	BOOST_FOREACH (const JsonNode & b, artifact["type"].Vector()) | ||||
| 	{ | ||||
| 		auto it = artifactBearerMap.find (b.String()); | ||||
| 		if (it != artifactBearerMap.end()) | ||||
| 		{ | ||||
| 			int bearerType = it->second; | ||||
| 			switch (bearerType) | ||||
| 			{ | ||||
| 				case ArtBearer::HERO://TODO: allow arts having several possible bearers | ||||
| 					break; | ||||
| 				case ArtBearer::COMMANDER: | ||||
| 					makeItCommanderArt (art); //original artifacts should have only one bearer type | ||||
| 					break; | ||||
| 				case ArtBearer::CREATURE: | ||||
| 					makeItCreatureArt (art); | ||||
| 					break; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 			tlog2 << "Warning! Artifact type " << b.String() << " not recognized!"; | ||||
| 	} | ||||
|  | ||||
| 	if (!artifact["components"].isNull()) | ||||
| 	{ | ||||
| 		art->constituents.reset(new std::vector<ArtifactID>()); | ||||
| 		BOOST_FOREACH (auto component, artifact["components"].Vector()) | ||||
| 		{ | ||||
| 			VLC->modh->identifiers.requestIdentifier("artifact." + component.String(), [art](si32 id) | ||||
| 			{ | ||||
| 				// when this code is called both combinational art as well as component are loaded | ||||
| 				// so it is safe to access any of them | ||||
| 				art->addConstituent(ArtifactID(id)); | ||||
| 				VLC->arth->artifacts[id]->constituentOf.push_back(art->id); | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CArtifact::addConstituent (ArtifactID component) | ||||
| { | ||||
| 	assert (constituents); | ||||
| 	assert (constituents); // not a combinational art | ||||
| 	constituents->push_back (component); | ||||
| } | ||||
|  | ||||
| @@ -534,28 +411,6 @@ CreatureID CArtHandler::machineIDToCreature(ArtifactID id) | ||||
| 	return CreatureID(id + dif); | ||||
| } | ||||
|  | ||||
| void CArtHandler::sortArts() | ||||
| { | ||||
|  	//for (int i=0; i<allowedArtifacts.size(); ++i) //do 144, bo nie chcemy bzdurek | ||||
|  	//{ | ||||
|  	//	switch (allowedArtifacts[i]->aClass) | ||||
|  	//	{ | ||||
|  	//	case CArtifact::ART_TREASURE: | ||||
|  	//		treasures.push_back(allowedArtifacts[i]); | ||||
|  	//		break; | ||||
|  	//	case CArtifact::ART_MINOR: | ||||
|  	//		minors.push_back(allowedArtifacts[i]); | ||||
|  	//		break; | ||||
|  	//	case CArtifact::ART_MAJOR: | ||||
|  	//		majors.push_back(allowedArtifacts[i]); | ||||
|  	//		break; | ||||
|  	//	case CArtifact::ART_RELIC: | ||||
|  	//		relics.push_back(allowedArtifacts[i]); | ||||
|  	//		break; | ||||
|  	//	} | ||||
|  	//} | ||||
| } | ||||
|  | ||||
| ArtifactID CArtHandler::getRandomArt(int flags) | ||||
| { | ||||
| 	return getArtSync(ran(), flags, true); | ||||
| @@ -679,84 +534,6 @@ void CArtHandler::makeItCommanderArt( ArtifactID aid, bool onlyCommander /*= tru | ||||
| 	makeItCommanderArt (a, onlyCommander); | ||||
| } | ||||
|  | ||||
| void CArtHandler::addBonuses() | ||||
| { | ||||
| 	const JsonNode config(ResourceID("config/artifacts.json")); | ||||
| 	BOOST_FOREACH (auto & artifact, config["artifacts"].Struct()) //pair <string, JsonNode> (id, properties) | ||||
| 	{ | ||||
| 		auto ga = artifacts[artifact.second["id"].Float()].get(); | ||||
|  | ||||
| 		BOOST_FOREACH (auto b, artifact.second["bonuses"].Vector()) | ||||
| 		{ | ||||
| 			auto bonus = JsonUtils::parseBonus (b); | ||||
| 			bonus->sid = ga->id; | ||||
| 			ga->addNewBonus (bonus); | ||||
| 		} | ||||
| 		BOOST_FOREACH (const JsonNode & b, artifact.second["type"].Vector()) //TODO: remove duplicate code | ||||
| 		{ | ||||
| 			auto it = artifactBearerMap.find (b.String()); | ||||
| 			if (it != artifactBearerMap.end()) | ||||
| 			{ | ||||
| 				int bearerType = it->second; | ||||
| 				switch (bearerType) | ||||
| 				{ | ||||
| 					case ArtBearer::HERO: | ||||
| 						break; | ||||
| 					case ArtBearer::COMMANDER: | ||||
| 						makeItCommanderArt (ga); //original artifacts should have only one bearer type | ||||
| 						break; | ||||
| 					case ArtBearer::CREATURE: | ||||
| 						makeItCreatureArt (ga); | ||||
| 						break; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 				tlog2 << "Warning! Artifact type " << b.String() << " not recognized!"; | ||||
| 		} | ||||
| 		readComponents (artifact.second, ga); | ||||
|  | ||||
| 		VLC->modh->identifiers.registerObject ("artifact." + artifact.first, ga->id); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CArtHandler::readComponents (const JsonNode & node, CArtifact * art) | ||||
| { | ||||
| 	const JsonNode *value; | ||||
| 	value = &node["components"]; | ||||
| 	if (!value->isNull()) | ||||
| 	{ | ||||
| 		art->constituents = new std::vector<ArtifactID>(); | ||||
| 		BOOST_FOREACH (auto component, value->Vector()) | ||||
| 		{ | ||||
| 			VLC->modh->identifiers.requestIdentifier(std::string("artifact.") + component.String(), | ||||
| 				[art](si32 id) | ||||
| 				{ | ||||
| 					art->addConstituent(ArtifactID(id)); | ||||
| 				} | ||||
| 			); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| void CArtHandler::clear() | ||||
| { | ||||
| 	BOOST_FOREACH(CArtifact *art, artifacts) | ||||
| 		delete art; | ||||
| 	artifacts.clear(); | ||||
|  | ||||
| 	clearHlpLists(); | ||||
|  | ||||
| } | ||||
|  | ||||
| void CArtHandler::clearHlpLists() | ||||
| { | ||||
| 	treasures.clear(); | ||||
| 	minors.clear(); | ||||
| 	majors.clear(); | ||||
| 	relics.clear(); | ||||
| } | ||||
|  | ||||
| bool CArtHandler::legalArtifact(ArtifactID id) | ||||
| { | ||||
| 	auto art = artifacts[id]; | ||||
| @@ -770,7 +547,6 @@ bool CArtHandler::legalArtifact(ArtifactID id) | ||||
| void CArtHandler::initAllowedArtifactsList(const std::vector<bool> &allowed) | ||||
| { | ||||
| 	allowedArtifacts.clear(); | ||||
| 	clearHlpLists(); | ||||
| 	for (ArtifactID i=ArtifactID::SPELLBOOK; i<ArtifactID::ART_SELECTION; i.advance(1)) | ||||
| 	{ | ||||
| 		if (allowed[i] && legalArtifact(i)) | ||||
| @@ -860,12 +636,6 @@ CArtifactInstance::CArtifactInstance( CArtifact *Art) | ||||
| 	setType(Art); | ||||
| } | ||||
|  | ||||
| // CArtifactInstance::CArtifactInstance(int aid) | ||||
| // { | ||||
| // 	init(); | ||||
| // 	setType(VLC->arth->artifacts[aid]); | ||||
| // } | ||||
|  | ||||
| void CArtifactInstance::setType( CArtifact *Art ) | ||||
| { | ||||
| 	artType = Art; | ||||
| @@ -966,17 +736,16 @@ void CArtifactInstance::removeFrom(ArtifactLocation al) | ||||
|  | ||||
| bool CArtifactInstance::canBeDisassembled() const | ||||
| { | ||||
| 	return artType->constituents && artType->constituentOf->size(); | ||||
| 	return artType->constituents != nullptr; | ||||
| } | ||||
|  | ||||
| std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CArtifactSet *h) const | ||||
| { | ||||
| 	std::vector<const CArtifact *> ret; | ||||
| 	if(!artType->constituentOf //not a part of combined artifact | ||||
| 		|| artType->constituents) //combined artifact already: no combining of combined artifacts... for now. | ||||
| 	if(artType->constituents) //combined artifact already: no combining of combined artifacts... for now. | ||||
| 		return ret; | ||||
|  | ||||
| 	BOOST_FOREACH(ui32 possibleCombinedArt, *artType->constituentOf) | ||||
| 	BOOST_FOREACH(ui32 possibleCombinedArt, artType->constituentOf) | ||||
| 	{ | ||||
| 		const CArtifact * const artifact = VLC->arth->artifacts[possibleCombinedArt]; | ||||
| 		assert(artifact->constituents); | ||||
|   | ||||
| @@ -15,6 +15,8 @@ | ||||
|  * Full text of license available in license.txt file, in main folder | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| class CArtHandler; | ||||
| class CDefHandler; | ||||
| class CArtifact; | ||||
| class CGHeroInstance; | ||||
| @@ -53,22 +55,20 @@ public: | ||||
| 	const std::string &Name() const; //getter | ||||
| 	const std::string &Description() const; //getter | ||||
| 	const std::string &EventText() const; | ||||
|  | ||||
| 	bool isBig () const; | ||||
| 	void setName (std::string desc); | ||||
| 	void setDescription (std::string desc); | ||||
| 	void setEventText (std::string desc); | ||||
| 	void addConstituent (ArtifactID component); | ||||
|  | ||||
| 	int getArtClassSerial() const; //0 - treasure, 1 - minor, 2 - major, 3 - relic, 4 - spell scroll, 5 - other | ||||
| 	std::string nodeName() const OVERRIDE; | ||||
| 	void addNewBonus(Bonus *b) OVERRIDE; | ||||
| 	std::string nodeName() const override; | ||||
| 	void addNewBonus(Bonus *b) override; | ||||
|  | ||||
| 	virtual void levelUpArtifact (CArtifactInstance * art){}; | ||||
|  | ||||
| 	ui32 price; | ||||
| 	bmap<ArtBearer::ArtBearer, std::vector<ArtifactPosition> > possibleSlots; //Bearer Type => ids of slots where artifact can be placed | ||||
| 	std::vector<ArtifactID> * constituents; // Artifacts IDs a combined artifact consists of, or NULL. | ||||
| 	std::vector<ArtifactID> * constituentOf; // Reverse map of constituents. | ||||
| 	std::unique_ptr<std::vector<ArtifactID> > constituents; // Artifacts IDs a combined artifact consists of, or NULL. | ||||
| 	std::vector<ArtifactID> constituentOf; // Reverse map of constituents - combined arts that include this art | ||||
| 	EartClass aClass; | ||||
| 	ArtifactID id; | ||||
|  | ||||
| @@ -82,8 +82,7 @@ public: | ||||
| 	CArtifact(); | ||||
| 	~CArtifact(); | ||||
|  | ||||
| 	//override | ||||
| 	//void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const; | ||||
| 	friend class CArtHandler; | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CGrowingArtifact : public CArtifact //for example commander artifacts getting bonuses after battle | ||||
| @@ -201,20 +200,15 @@ public: | ||||
| 	std::set<ArtifactID> growingArtifacts; | ||||
|  | ||||
| 	void loadArtifacts(bool onlyTxt); | ||||
| 	/// load all artifacts from json structure | ||||
| 	void load(const JsonNode & node); | ||||
| 	/// load artifact from json structure | ||||
| 	void load(std::string objectID, const JsonNode & node); | ||||
| 	/// load one artifact from json config | ||||
| 	CArtifact * loadArtifact(const JsonNode & node); | ||||
| 	///read (optional) components of combined artifact | ||||
| 	void readComponents (const JsonNode & node, CArtifact * art); | ||||
| 	void reverseMapArtifactConstituents (); | ||||
|  | ||||
| 	void sortArts(); | ||||
| 	void addBonuses(); | ||||
| 	void clear(); | ||||
| 	void clearHlpLists(); | ||||
| 	void loadArtifactJson(CArtifact * art, const JsonNode & node); | ||||
|  | ||||
| 	void addBonuses(CArtifact *art, const JsonNode &bonusList); | ||||
|  | ||||
| 	//void restockArtifactList()'' | ||||
| 	void fillList(std::vector<CArtifact*> &listToBeFilled, CArtifact::EartClass artifactClass); //fills given empty list with allowed artifacts of gibven class. No side effects | ||||
|  | ||||
| 	boost::optional<std::vector<CArtifact*>&> listFromClass(CArtifact::EartClass artifactClass); | ||||
|   | ||||
| @@ -208,6 +208,50 @@ static void RemoveAbility(CCreature *cre, const JsonNode &ability) | ||||
| 	cre->removeBonus(b); | ||||
| } | ||||
|  | ||||
| void CCreatureHandler::loadBonuses(CCreature & ncre, std::string bonuses) | ||||
| { | ||||
| 	static const std::map<std::string,Bonus::BonusType> 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) | ||||
| 		("IMMUNE_TO_FIRE_SPELLS",Bonus::FIRE_IMMUNITY) | ||||
| 		("HAS_EXTENDED_ATTACK",Bonus::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); | ||||
| 	} | ||||
| 	if(hasAbility("DOUBLE_WIDE")) | ||||
| 		ncre.doubleWide = true; | ||||
| 	if(hasAbility("const_raises_morale")) | ||||
| 	{ | ||||
| 		ncre.addBonus(+1, Bonus::MORALE);; | ||||
| 		ncre.getBonusList().back()->addPropagator(make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO)); | ||||
| 	} | ||||
| 	if(hasAbility("const_lowers_morale")) | ||||
| 	{ | ||||
| 		ncre.addBonus(-1, Bonus::MORALE);; | ||||
| 		ncre.getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CCreatureHandler::loadCreatures() | ||||
| { | ||||
| 	tlog5 << "\t\tReading ZCRTRAIT.TXT" << std::endl; | ||||
| @@ -255,8 +299,8 @@ void CCreatureHandler::loadCreatures() | ||||
| 		ncre.ammMin = parser.readNumber(); | ||||
| 		ncre.ammMax = parser.readNumber(); | ||||
|  | ||||
| 		ncre.abilityText = parser.readString(); | ||||
| 		ncre.abilityRefs = parser.readString(); | ||||
| 		std::string abilities = parser.readString(); | ||||
| 		loadBonuses(ncre, parser.readString()); | ||||
|  | ||||
| 		{ //adding abilities from ZCRTRAIT.TXT | ||||
| 			static const std::map < std::string,Bonus::BonusType> abilityMap = boost::assign::map_list_of | ||||
| @@ -277,11 +321,11 @@ void CCreatureHandler::loadCreatures() | ||||
| 				("IMMUNE_TO_FIRE_SPELLS",Bonus::FIRE_IMMUNITY) | ||||
| 				("IMMUNE_TO_FIRE_SPELLS",Bonus::FIRE_IMMUNITY) | ||||
| 				("HAS_EXTENDED_ATTACK",Bonus::TWO_HEX_ATTACK_BREATH); | ||||
| 				 | ||||
| 			auto hasAbility = [&ncre](const std::string name) -> bool | ||||
|  | ||||
| 			auto hasAbility = [&](const std::string name) -> bool | ||||
| 			{ | ||||
| 				return boost::algorithm::find_first(ncre.abilityRefs,name); | ||||
| 			};			 | ||||
| 				return boost::algorithm::find_first(abilities, name); | ||||
| 			}; | ||||
| 			BOOST_FOREACH(auto a, abilityMap) | ||||
| 			{ | ||||
| 				if(hasAbility(a.first)) | ||||
| @@ -315,18 +359,6 @@ void CCreatureHandler::loadCreatures() | ||||
| 		int creatureID = node.second["id"].Float(); | ||||
| 		CCreature *c = creatures[creatureID]; | ||||
|  | ||||
| 		BOOST_FOREACH(const JsonNode &ability, node.second["ability_remove"].Vector()) | ||||
| 		{ | ||||
| 			RemoveAbility(c, ability); | ||||
| 		} | ||||
| 		BOOST_FOREACH(const JsonNode &ability, node.second["abilities"].Vector()) | ||||
| 		{ | ||||
| 			if (ability.getType() == JsonNode::DATA_VECTOR) | ||||
| 				AddAbility(c, ability.Vector()); | ||||
| 			else | ||||
| 				c->addNewBonus(JsonUtils::parseBonus(ability)); | ||||
| 		} | ||||
|  | ||||
| 		loadCreatureJson(c, node.second); | ||||
|  | ||||
| 		// Main reference name, e.g. royalGriffin | ||||
| @@ -508,47 +540,41 @@ void CCreatureHandler::loadAnimationInfo() | ||||
|  | ||||
| void CCreatureHandler::loadUnitAnimInfo(CCreature & unit, CLegacyConfigParser & parser) | ||||
| { | ||||
| 	unit.timeBetweenFidgets = parser.readNumber(); | ||||
| 	unit.walkAnimationTime = parser.readNumber(); | ||||
| 	unit.attackAnimationTime = parser.readNumber(); | ||||
| 	unit.flightAnimationDistance = parser.readNumber(); | ||||
| 	unit.animation.timeBetweenFidgets = parser.readNumber(); | ||||
| 	unit.animation.walkAnimationTime = parser.readNumber(); | ||||
| 	unit.animation.attackAnimationTime = parser.readNumber(); | ||||
| 	unit.animation.flightAnimationDistance = parser.readNumber(); | ||||
| 	/////////////////////// | ||||
|  | ||||
| 	unit.upperRightMissleOffsetX = parser.readNumber(); | ||||
| 	unit.upperRightMissleOffsetY = parser.readNumber(); | ||||
| 	unit.rightMissleOffsetX = parser.readNumber(); | ||||
| 	unit.rightMissleOffsetY = parser.readNumber(); | ||||
| 	unit.lowerRightMissleOffsetX = parser.readNumber(); | ||||
| 	unit.lowerRightMissleOffsetY = 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(); | ||||
|  | ||||
| 	/////////////////////// | ||||
|  | ||||
| 	for(int jjj=0; jjj<12; ++jjj) | ||||
| 	{ | ||||
| 		unit.missleFrameAngles[jjj] = parser.readNumber(); | ||||
| 		unit.animation.missleFrameAngles[jjj] = parser.readNumber(); | ||||
| 	} | ||||
|  | ||||
| 	unit.troopCountLocationOffset= parser.readNumber(); | ||||
| 	unit.attackClimaxFrame = parser.readNumber(); | ||||
| 	unit.animation.troopCountLocationOffset= parser.readNumber(); | ||||
| 	unit.animation.attackClimaxFrame = parser.readNumber(); | ||||
|  | ||||
| 	parser.endLine(); | ||||
| } | ||||
|  | ||||
| void CCreatureHandler::load(const JsonNode & node) | ||||
| void CCreatureHandler::load(std::string creatureID, const JsonNode & node) | ||||
| { | ||||
| 	BOOST_FOREACH(auto & entry, node.Struct()) | ||||
| 	{ | ||||
| 		if (!entry.second.isNull()) // may happens if mod removed creature by setting json entry to null | ||||
| 		{ | ||||
| 			CCreature * creature = loadCreature(entry.second); | ||||
| 			creature->nameRef = entry.first; | ||||
| 			creature->idNumber = CreatureID(creatures.size()); | ||||
| 	CCreature * creature = loadCreature(node); | ||||
| 	creature->nameRef = creatureID; | ||||
| 	creature->idNumber = CreatureID(creatures.size()); | ||||
|  | ||||
| 			creatures.push_back(creature); | ||||
| 			tlog5 << "Added creature: " << entry.first << "\n"; | ||||
| 			registerCreature(creature->nameRef,creature->idNumber); | ||||
| 		} | ||||
| 	} | ||||
| 	creatures.push_back(creature); | ||||
| 	tlog5 << "Added creature: " << creatureID << "\n"; | ||||
| 	registerCreature(creature->nameRef, creature->idNumber); | ||||
| } | ||||
|  | ||||
| CCreature * CCreatureHandler::loadCreature(const JsonNode & node) | ||||
| @@ -586,74 +612,31 @@ CCreature * CCreatureHandler::loadCreature(const JsonNode & node) | ||||
|  | ||||
| 	cre->doubleWide = node["doubleWide"].Bool(); | ||||
|  | ||||
| 	BOOST_FOREACH (const JsonNode &bonus, node["abilities"].Vector()) | ||||
| 	{ | ||||
| 		auto b = JsonUtils::parseBonus(bonus); | ||||
| 		b->source = Bonus::CREATURE_ABILITY; | ||||
| 		b->duration = Bonus::PERMANENT; | ||||
| 		cre->addNewBonus(b); | ||||
| 	} | ||||
|  | ||||
| 	BOOST_FOREACH (const JsonNode &exp, node["stackExperience"].Vector()) | ||||
| 	{ | ||||
| 		auto bonus = JsonUtils::parseBonus (exp["bonus"]); | ||||
| 		bonus->source = Bonus::STACK_EXPERIENCE; | ||||
| 		bonus->duration = Bonus::PERMANENT; | ||||
| 		const JsonVector &values = exp["values"].Vector(); | ||||
| 		int lowerLimit = 1;//, upperLimit = 255; | ||||
| 		if (values[0].getType() == JsonNode::JsonType::DATA_BOOL) | ||||
| 		{ | ||||
| 			BOOST_FOREACH (const JsonNode &val, values) | ||||
| 			{ | ||||
| 				if (val.Bool() == true) | ||||
| 				{ | ||||
| 					bonus->limiter = make_shared<RankRangeLimiter>(RankRangeLimiter(lowerLimit)); | ||||
| 					cre->addNewBonus (new Bonus(*bonus)); //bonuses must be unique objects | ||||
| 					break; //TODO: allow bonuses to turn off? | ||||
| 				} | ||||
| 				++lowerLimit; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			int lastVal = 0; | ||||
| 			BOOST_FOREACH (const JsonNode &val, values) | ||||
| 			{ | ||||
| 				if (val.Float() != lastVal) | ||||
| 				{ | ||||
| 					bonus->val = val.Float() - lastVal; | ||||
| 					bonus->limiter.reset (new RankRangeLimiter(lowerLimit)); | ||||
| 					cre->addNewBonus (new Bonus(*bonus)); | ||||
| 				} | ||||
| 				lastVal = val.Float(); | ||||
| 				++lowerLimit; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	//graphics | ||||
| 	loadStackExperience(cre, node["stackExperience"]); | ||||
|  | ||||
| 	const JsonNode & graphics = node["graphics"]; | ||||
| 	cre->timeBetweenFidgets = graphics["timeBetweenFidgets"].Float(); | ||||
| 	cre->troopCountLocationOffset = graphics["troopCountLocationOffset"].Float(); | ||||
| 	cre->attackClimaxFrame = graphics["attackClimaxFrame"].Float(); | ||||
| 	cre->animation.timeBetweenFidgets = graphics["timeBetweenFidgets"].Float(); | ||||
| 	cre->animation.troopCountLocationOffset = graphics["troopCountLocationOffset"].Float(); | ||||
| 	cre->animation.attackClimaxFrame = graphics["attackClimaxFrame"].Float(); | ||||
|  | ||||
| 	const JsonNode & animationTime = graphics["animationTime"]; | ||||
| 	cre->walkAnimationTime = animationTime["walk"].Float(); | ||||
| 	cre->attackAnimationTime = animationTime["attack"].Float(); | ||||
| 	cre->flightAnimationDistance = animationTime["flight"].Float(); //? | ||||
| 	cre->animation.walkAnimationTime = animationTime["walk"].Float(); | ||||
| 	cre->animation.attackAnimationTime = animationTime["attack"].Float(); | ||||
| 	cre->animation.flightAnimationDistance = animationTime["flight"].Float(); //? | ||||
|  | ||||
| 	const JsonNode & missile = graphics["missile"]; | ||||
| 	const JsonNode & offsets = missile["offset"]; | ||||
| 	cre->upperRightMissleOffsetX = offsets["upperX"].Float(); | ||||
| 	cre->upperRightMissleOffsetY = offsets["upperY"].Float(); | ||||
| 	cre->rightMissleOffsetX = offsets["middleX"].Float(); | ||||
| 	cre->rightMissleOffsetY = offsets["middleY"].Float(); | ||||
| 	cre->lowerRightMissleOffsetX = offsets["lowerX"].Float(); | ||||
| 	cre->lowerRightMissleOffsetY = offsets["lowerY"].Float(); | ||||
| 	cre->animation.upperRightMissleOffsetX = offsets["upperX"].Float(); | ||||
| 	cre->animation.upperRightMissleOffsetY = offsets["upperY"].Float(); | ||||
| 	cre->animation.rightMissleOffsetX = offsets["middleX"].Float(); | ||||
| 	cre->animation.rightMissleOffsetY = offsets["middleY"].Float(); | ||||
| 	cre->animation.lowerRightMissleOffsetX = offsets["lowerX"].Float(); | ||||
| 	cre->animation.lowerRightMissleOffsetY = offsets["lowerY"].Float(); | ||||
| 	int i = 0; | ||||
| 	BOOST_FOREACH (auto & angle, missile["frameAngles"].Vector()) | ||||
| 	{ | ||||
| 		cre->missleFrameAngles[i++] = angle.Float(); | ||||
| 		cre->animation.missleFrameAngles[i++] = angle.Float(); | ||||
| 	} | ||||
| 	cre->advMapDef = graphics["map"].String(); | ||||
| 	cre->iconIndex = graphics["iconIndex"].Float(); | ||||
| @@ -667,6 +650,24 @@ 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()) | ||||
| 	{ | ||||
| 		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 | ||||
| 		{ | ||||
| 			auto b = JsonUtils::parseBonus(ability); | ||||
| 			b->source = Bonus::CREATURE_ABILITY; | ||||
| 			b->duration = Bonus::PERMANENT; | ||||
| 			creature->addNewBonus(b); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	VLC->modh->identifiers.requestIdentifier(std::string("faction.") + config["faction"].String(), [=](si32 faction) | ||||
| 	{ | ||||
| 		creature->faction = faction; | ||||
| @@ -683,12 +684,10 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c | ||||
| 	if(config["hasDoubleWeek"].Bool()) | ||||
| 		doubledCreatures.insert(creature->idNumber); | ||||
|  | ||||
| 	creature->projectile = config["graphics"]["missile"]["projectile"].String(); | ||||
| 	creature->projectileSpin = config["graphics"]["missile"]["spinning"].Bool(); | ||||
| 	creature->animation.projectileImageName = config["graphics"]["missile"]["projectile"].String(); | ||||
| 	creature->animation.projectileSpin = config["graphics"]["missile"]["spinning"].Bool(); | ||||
|  | ||||
| 	creature->special = config["special"].Bool(); | ||||
| 	if ( creature->special ) | ||||
| 		notUsedMonsters.insert(creature->idNumber); | ||||
|  | ||||
| 	const JsonNode & sounds = config["sound"]; | ||||
|  | ||||
| @@ -706,6 +705,46 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c | ||||
| #undef GET_SOUND_VALUE | ||||
| } | ||||
|  | ||||
| void CCreatureHandler::loadStackExperience(CCreature * creature, const JsonNode & input) | ||||
| { | ||||
| 	BOOST_FOREACH (const JsonNode &exp, input.Vector()) | ||||
| 	{ | ||||
| 		auto bonus = JsonUtils::parseBonus (exp["bonus"]); | ||||
| 		bonus->source = Bonus::STACK_EXPERIENCE; | ||||
| 		bonus->duration = Bonus::PERMANENT; | ||||
| 		const JsonVector &values = exp["values"].Vector(); | ||||
| 		int lowerLimit = 1;//, upperLimit = 255; | ||||
| 		if (values[0].getType() == JsonNode::JsonType::DATA_BOOL) | ||||
| 		{ | ||||
| 			BOOST_FOREACH (const JsonNode &val, values) | ||||
| 			{ | ||||
| 				if (val.Bool() == true) | ||||
| 				{ | ||||
| 					bonus->limiter = make_shared<RankRangeLimiter>(RankRangeLimiter(lowerLimit)); | ||||
| 					creature->addNewBonus (new Bonus(*bonus)); //bonuses must be unique objects | ||||
| 					break; //TODO: allow bonuses to turn off? | ||||
| 				} | ||||
| 				++lowerLimit; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			int lastVal = 0; | ||||
| 			BOOST_FOREACH (const JsonNode &val, values) | ||||
| 			{ | ||||
| 				if (val.Float() != lastVal) | ||||
| 				{ | ||||
| 					bonus->val = val.Float() - lastVal; | ||||
| 					bonus->limiter.reset (new RankRangeLimiter(lowerLimit)); | ||||
| 					creature->addNewBonus (new Bonus(*bonus)); | ||||
| 				} | ||||
| 				lastVal = val.Float(); | ||||
| 				++lowerLimit; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser & parser) //help function for parsing CREXPBON.txt | ||||
| { | ||||
| 	bool enable = false; //some bonuses are activated with values 2 or 1 | ||||
| @@ -1022,7 +1061,7 @@ CreatureID CCreatureHandler::pickRandomMonster(const boost::function<int()> &ran | ||||
| 		do | ||||
| 		{ | ||||
| 			r = vstd::pickRandomElementOf(creatures, randGen)->idNumber; | ||||
| 		} while (vstd::contains(VLC->creh->notUsedMonsters,r)); | ||||
| 		} while (VLC->creh->creatures[r] && VLC->creh->creatures[r]->special); // find first "not special" creature | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -1031,9 +1070,9 @@ CreatureID CCreatureHandler::pickRandomMonster(const boost::function<int()> &ran | ||||
| 		BOOST_FOREACH(const CBonusSystemNode *b, creaturesOfLevel[tier].getChildrenNodes()) | ||||
| 		{ | ||||
| 			assert(b->getNodeType() == CBonusSystemNode::CREATURE); | ||||
| 			CreatureID creid = static_cast<const CCreature*>(b)->idNumber; | ||||
| 			if(!vstd::contains(notUsedMonsters, creid)) | ||||
| 				allowed.push_back(creid); | ||||
| 			const CCreature * crea = dynamic_cast<const CCreature*>(b); | ||||
| 			if(crea && !crea->special) | ||||
| 				allowed.push_back(crea->idNumber); | ||||
| 		} | ||||
|  | ||||
| 		if(!allowed.size()) | ||||
|   | ||||
| @@ -20,40 +20,58 @@ | ||||
| class CLegacyConfigParser; | ||||
| class CCreatureHandler; | ||||
| class CCreature; | ||||
| struct CreaturesBattleSounds; | ||||
|  | ||||
| class DLL_LINKAGE CCreature : public CBonusSystemNode | ||||
| { | ||||
| public: | ||||
| 	std::string namePl, nameSing, nameRef; //name in singular and plural form; and reference name | ||||
| 	TResources cost; //cost[res_id] - amount of that resource | ||||
| 	std::set<std::string> upgradeNames; //for reference, they are later transformed info ui32 upgrades | ||||
| 	std::set<CreatureID> upgrades; // IDs of creatures to which this creature can be upgraded | ||||
| 	//damage, hp. etc are handled by Bonuses | ||||
| 	ui32 fightValue, AIValue, growth, hordeGrowth; | ||||
| 	ui32 ammMin, ammMax; | ||||
| 	std::string abilityText; //description of abilities | ||||
| 	std::string abilityRefs; //references to abilities, in text format | ||||
| 	std::string animDefName; | ||||
| 	std::string advMapDef; //for new creatures only | ||||
| 	CreatureID idNumber; | ||||
| 	si32 iconIndex; // index of icon in files like twcrport | ||||
| 	TFaction faction; //-1 = neutral | ||||
| 	ui8 level; // 0 - unknown | ||||
| 	bool doubleWide; | ||||
| 	bool special; // Creature is not available normally (war machines, commanders, etc | ||||
| 	std::string nameRef; // reference name, stringID | ||||
| 	std::string nameSing;// singular name, e.g. Centaur | ||||
| 	std::string namePl;  // plural name, e.g. Centaurs | ||||
|  | ||||
| 	///animation info | ||||
| 	double timeBetweenFidgets, walkAnimationTime, attackAnimationTime, flightAnimationDistance; | ||||
| 	int upperRightMissleOffsetX, rightMissleOffsetX, lowerRightMissleOffsetX, upperRightMissleOffsetY, rightMissleOffsetY, lowerRightMissleOffsetY; | ||||
| 	double missleFrameAngles[12]; | ||||
| 	int troopCountLocationOffset, attackClimaxFrame; | ||||
| 	std::string projectile; | ||||
| 	bool projectileSpin; //if true, appropriate projectile is spinning during flight | ||||
| 	///end of anim info | ||||
| 	std::string abilityText; //description of abilities | ||||
|  | ||||
| 	CreatureID idNumber; | ||||
| 	TFaction faction; | ||||
| 	ui8 level; // 0 - unknown | ||||
|  | ||||
| 	//stats that are not handled by bonus system | ||||
| 	ui32 fightValue, AIValue, growth, hordeGrowth; | ||||
| 	ui32 ammMin, ammMax; // initial size of stack of these creatures on adventure map (if not set in editor) | ||||
|  | ||||
| 	bool doubleWide; | ||||
| 	bool special; // Creature is not available normally (war machines, commanders, several unused creatures, etc | ||||
|  | ||||
| 	TResources cost; //cost[res_id] - amount of that resource required to buy creature from dwelling | ||||
| 	std::set<CreatureID> upgrades; // IDs of creatures to which this creature can be upgraded | ||||
|  | ||||
| 	std::string animDefName; // creature animation used during battles | ||||
| 	std::string advMapDef; //for new creatures only, image for adventure map | ||||
| 	si32 iconIndex; // index of icon in files like twcrport | ||||
|  | ||||
| 	struct CreatureAnimation | ||||
| 	{ | ||||
| 		double timeBetweenFidgets, walkAnimationTime, attackAnimationTime, flightAnimationDistance; | ||||
| 		int upperRightMissleOffsetX, rightMissleOffsetX, lowerRightMissleOffsetX, | ||||
| 		    upperRightMissleOffsetY, rightMissleOffsetY, lowerRightMissleOffsetY; | ||||
|  | ||||
| 		double missleFrameAngles[12]; | ||||
| 		int troopCountLocationOffset, attackClimaxFrame; | ||||
|  | ||||
| 		std::string projectileImageName; | ||||
| 		bool projectileSpin; //if true, appropriate projectile is spinning during flight | ||||
|  | ||||
| 		template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 		{ | ||||
| 			h & timeBetweenFidgets & walkAnimationTime & attackAnimationTime & flightAnimationDistance; | ||||
| 			h & upperRightMissleOffsetX & rightMissleOffsetX & lowerRightMissleOffsetX; | ||||
| 			h & upperRightMissleOffsetY & rightMissleOffsetY & lowerRightMissleOffsetY; | ||||
| 			h & missleFrameAngles & troopCountLocationOffset & attackClimaxFrame; | ||||
| 			h & projectileImageName & projectileSpin; | ||||
| 		} | ||||
| 	} animation; | ||||
|  | ||||
| 	//sound info | ||||
| 	struct CreaturesBattleSounds | ||||
| 	struct CreatureBattleSounds | ||||
| 	{ | ||||
| 		std::string attack; | ||||
| 		std::string defend; | ||||
| @@ -106,21 +124,15 @@ public: | ||||
| 			& cost & upgrades | ||||
| 			& fightValue & AIValue & growth & hordeGrowth | ||||
| 			& ammMin & ammMax & level | ||||
| 			& abilityText & abilityRefs & animDefName & advMapDef; | ||||
| 			& abilityText & animDefName & advMapDef; | ||||
| 		h & iconIndex; | ||||
|  | ||||
| 		h & idNumber & faction | ||||
| 			& timeBetweenFidgets & walkAnimationTime & attackAnimationTime & flightAnimationDistance | ||||
| 			& upperRightMissleOffsetX & rightMissleOffsetX & lowerRightMissleOffsetX & upperRightMissleOffsetY & rightMissleOffsetY & lowerRightMissleOffsetY | ||||
| 			& missleFrameAngles & troopCountLocationOffset & attackClimaxFrame; | ||||
| 		h & sounds & projectile & projectileSpin; | ||||
| 		h & idNumber & faction & sounds & animation; | ||||
|  | ||||
| 		h & doubleWide; | ||||
| 		h & doubleWide & special; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	CCreature(); | ||||
| 	friend class CCreatureHandler; | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CCreatureHandler | ||||
| @@ -129,11 +141,11 @@ 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 loadStackExperience(CCreature * creature, const JsonNode &input); | ||||
| 	void loadCreatureJson(CCreature * creature, const JsonNode & config); | ||||
| public: | ||||
| 	std::set<CreatureID> notUsedMonsters; | ||||
| 	std::set<CreatureID> doubledCreatures; //they get double week | ||||
| 	std::vector<ConstTransitivePtr<CCreature> > creatures; //creature ID -> creature info | ||||
| 	std::vector<ConstTransitivePtr<CCreature> > creatures; //creature ID -> creature info. | ||||
|  | ||||
| 	//stack exp | ||||
| 	std::map<Bonus::BonusType, std::pair<std::string, std::string> > stackBonuses; // bonus => name, description | ||||
| @@ -148,10 +160,12 @@ public: | ||||
|  | ||||
| 	/// loading functions | ||||
|  | ||||
| 	/// adding abilities from ZCRTRAIT.TXT | ||||
| 	void loadBonuses(CCreature & creature, std::string bonuses); | ||||
| 	/// load all creatures from H3 files | ||||
| 	void loadCreatures(); | ||||
| 	/// load all creatures from json structure | ||||
| 	void load(const JsonNode & node); | ||||
| 	/// load creature from json structure | ||||
| 	void load(std::string creatureID, const JsonNode & node); | ||||
| 	/// load one creature from json config | ||||
| 	CCreature * loadCreature(const JsonNode & node); | ||||
| 	/// generates tier-specific bonus tree entries | ||||
| @@ -176,7 +190,7 @@ public: | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		//TODO: should be optimized, not all these informations needs to be serialized (same for ccreature) | ||||
| 		h & notUsedMonsters & doubledCreatures & creatures; | ||||
| 		h & doubledCreatures & creatures; | ||||
| 		h & stackBonuses & expRanks & maxExpPerBattle & expAfterUpgrade; | ||||
| 		h & skillLevels & skillRequirements & commanderLevelPremy; | ||||
| 		h & allCreatures; | ||||
|   | ||||
| @@ -2478,7 +2478,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level) | ||||
| 	} | ||||
| 	if(level >= 4) //obelisks found | ||||
| 	{ | ||||
| 		//TODO: obtainPlayersStats - obelisks found | ||||
| 		FILL_FIELD(obelisks, CGObelisk::visited[gs->getPlayerTeam(g->second.color)->id]) | ||||
| 	} | ||||
| 	if(level >= 5) //artifacts | ||||
| 	{ | ||||
|   | ||||
| @@ -131,21 +131,15 @@ void CHeroClassHandler::load() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CHeroClassHandler::load(const JsonNode & classes) | ||||
| void CHeroClassHandler::load(std::string objectID, const JsonNode & input) | ||||
| { | ||||
| 	BOOST_FOREACH(auto & entry, classes.Struct()) | ||||
| 	{ | ||||
| 		if (!entry.second.isNull()) // may happens if mod removed creature by setting json entry to null | ||||
| 		{ | ||||
| 			CHeroClass * heroClass = loadClass(entry.second); | ||||
| 			heroClass->identifier = entry.first; | ||||
| 			heroClass->id = heroClasses.size(); | ||||
| 	CHeroClass * heroClass = loadClass(input); | ||||
| 	heroClass->identifier = objectID; | ||||
| 	heroClass->id = heroClasses.size(); | ||||
|  | ||||
| 			heroClasses.push_back(heroClass); | ||||
| 			tlog5 << "Added hero class: " << entry.first << "\n"; | ||||
| 			VLC->modh->identifiers.registerObject("heroClass." + heroClass->identifier, heroClass->id); | ||||
| 		} | ||||
| 	} | ||||
| 	heroClasses.push_back(heroClass); | ||||
| 	tlog5 << "Added hero class: " << objectID << "\n"; | ||||
| 	VLC->modh->identifiers.registerObject("heroClass." + heroClass->identifier, heroClass->id); | ||||
| } | ||||
|  | ||||
| CHeroClass *CHeroClassHandler::loadClass(const JsonNode & node) | ||||
| @@ -209,20 +203,14 @@ CHeroHandler::CHeroHandler() | ||||
| { | ||||
| } | ||||
|  | ||||
| void CHeroHandler::load(const JsonNode & input) | ||||
| void CHeroHandler::load(std::string objectID, const JsonNode & input) | ||||
| { | ||||
| 	BOOST_FOREACH(auto & entry, input.Struct()) | ||||
| 	{ | ||||
| 		if (!entry.second.isNull()) // may happens if mod removed creature by setting json entry to null | ||||
| 		{ | ||||
| 			CHero * hero = loadHero(entry.second); | ||||
| 			hero->ID = heroes.size(); | ||||
| 	CHero * hero = loadHero(input); | ||||
| 	hero->ID = heroes.size(); | ||||
|  | ||||
| 			heroes.push_back(hero); | ||||
| 			tlog5 << "Added hero: " << entry.first << "\n"; | ||||
| 			VLC->modh->identifiers.registerObject("hero." + entry.first, hero->ID); | ||||
| 		} | ||||
| 	} | ||||
| 	heroes.push_back(hero); | ||||
| 	tlog5 << "Added hero: " << objectID << "\n"; | ||||
| 	VLC->modh->identifiers.registerObject("hero." + objectID, hero->ID); | ||||
| } | ||||
|  | ||||
| CHero * CHeroHandler::loadHero(const JsonNode & node) | ||||
| @@ -278,9 +266,23 @@ void CHeroHandler::loadHeroJson(CHero * hero, const JsonNode & node) | ||||
| 		hero->secSkillsInit.push_back(std::make_pair(skillID, skillLevel)); | ||||
| 	} | ||||
|  | ||||
| 	// spellbook is considered present if hero have "spellbook" entry even when this is an empty set (0 spells) | ||||
| 	hero->haveSpellBook = node["spellbook"].isNull(); | ||||
|  | ||||
| 	BOOST_FOREACH(const JsonNode & spell, node["spellbook"].Vector()) | ||||
| 	{ | ||||
| 		hero->spells.insert(SpellID(spell.Float())); | ||||
| 		if (spell.getType() == JsonNode::DATA_FLOAT) // for compatibility | ||||
| 		{ | ||||
| 			hero->spells.insert(SpellID(spell.Float())); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			VLC->modh->identifiers.requestIdentifier("spell." + spell.String(), | ||||
| 			[=](si32 spellID) | ||||
| 			{ | ||||
| 				hero->spells.insert(SpellID(spellID)); | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//deprecated, used only for original spciealties | ||||
| @@ -317,13 +319,14 @@ void CHeroHandler::loadHeroJson(CHero * hero, const JsonNode & node) | ||||
|  | ||||
| void CHeroHandler::load() | ||||
| { | ||||
| 	VLC->heroh = this; | ||||
|  | ||||
| 	for (int i = 0; i < GameConstants::SKILL_QUANTITY; ++i) | ||||
| 	{ | ||||
| 		VLC->modh->identifiers.registerObject("skill." + NSecondarySkill::names[i], i); | ||||
| 	} | ||||
| 	classes.load(); | ||||
| 	loadHeroes(); | ||||
| 	loadHeroTexts(); | ||||
| 	loadObstacles(); | ||||
| 	loadTerrains(); | ||||
| 	loadBallistics(); | ||||
| @@ -382,17 +385,26 @@ void CHeroHandler::loadObstacles() | ||||
|  | ||||
| void CHeroHandler::loadHeroes() | ||||
| { | ||||
| 	VLC->heroh = this; | ||||
| 	CLegacyConfigParser specParser("DATA/HEROSPEC.TXT"); | ||||
| 	CLegacyConfigParser bioParser("DATA/HEROBIOS.TXT"); | ||||
| 	CLegacyConfigParser parser("DATA/HOTRAITS.TXT"); | ||||
|  | ||||
| 	parser.endLine(); //ignore header | ||||
| 	parser.endLine(); | ||||
|  | ||||
| 	specParser.endLine(); //ignore header | ||||
| 	specParser.endLine(); | ||||
|  | ||||
| 	for (int i=0; i<GameConstants::HEROES_QUANTITY; i++) | ||||
| 	{ | ||||
| 		CHero * hero = new CHero; | ||||
| 		hero->name = parser.readString(); | ||||
|  | ||||
| 		hero->specName    = specParser.readString(); | ||||
| 		hero->specTooltip = specParser.readString(); | ||||
| 		hero->specDescr   = specParser.readString(); | ||||
| 		hero->biography   = bioParser.readString(); | ||||
|  | ||||
| 		hero->initialArmy.resize(3); | ||||
| 		for(int x=0;x<3;x++) | ||||
| 		{ | ||||
| @@ -408,6 +420,8 @@ void CHeroHandler::loadHeroes() | ||||
| 			}); | ||||
| 		} | ||||
| 		parser.endLine(); | ||||
| 		specParser.endLine(); | ||||
| 		bioParser.endLine(); | ||||
|  | ||||
| 		hero->ID = heroes.size(); | ||||
| 		hero->imageIndex = hero->ID; | ||||
| @@ -422,27 +436,6 @@ void CHeroHandler::loadHeroes() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CHeroHandler::loadHeroTexts() | ||||
| { | ||||
| 	CLegacyConfigParser parser("DATA/HEROSPEC.TXT"); | ||||
| 	CLegacyConfigParser bioParser("DATA/HEROBIOS.TXT"); | ||||
|  | ||||
| 	//skip header | ||||
| 	parser.endLine(); | ||||
| 	parser.endLine(); | ||||
|  | ||||
| 	int i=0; | ||||
| 	do | ||||
| 	{ | ||||
| 		CHero * hero = heroes[i++]; | ||||
| 		hero->specName    = parser.readString(); | ||||
| 		hero->specTooltip = parser.readString(); | ||||
| 		hero->specDescr   = parser.readString(); | ||||
| 		hero->biography   = bioParser.readString(); | ||||
| 	} | ||||
| 	while (parser.endLine() && bioParser.endLine() && heroes.size() > i); | ||||
| } | ||||
|  | ||||
| void CHeroHandler::loadBallistics() | ||||
| { | ||||
| 	CLegacyConfigParser ballParser("DATA/BALLIST.TXT"); | ||||
|   | ||||
| @@ -68,8 +68,9 @@ public: | ||||
| 	std::vector<SSpecialtyInfo> spec; | ||||
| 	std::vector<SSpecialtyBonus> specialty; | ||||
| 	std::set<SpellID> spells; | ||||
| 	bool haveSpellBook; | ||||
| 	bool special; // hero is special and won't be placed in game (unless preset on map), e.g. campaign heroes | ||||
| 	ui8 sex; // default sex: 0=male, 1=female | ||||
| 	ui8 special; // hero is special and won't be placed in game (unless preset on map), e.g. campaign heroes | ||||
|  | ||||
| 	/// Localized texts | ||||
| 	std::string name; //name of hero | ||||
| @@ -86,7 +87,7 @@ public: | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & ID & imageIndex & initialArmy & heroClass & secSkillsInit & spec & specialty & spells & sex; | ||||
| 		h & ID & imageIndex & initialArmy & heroClass & secSkillsInit & spec & specialty & spells & haveSpellBook & sex & special; | ||||
| 		h & name & biography & specName & specDescr & specTooltip; | ||||
| 		h & iconSpecSmall & iconSpecLarge & portraitSmall & portraitLarge; | ||||
| 	} | ||||
| @@ -157,7 +158,7 @@ public: | ||||
| 	void load(); | ||||
|  | ||||
| 	/// load any number of classes from json | ||||
| 	void load(const JsonNode & classes); | ||||
| 	void load(std::string objectID, const JsonNode & classes); | ||||
|  | ||||
| 	/// load one class from json | ||||
| 	CHeroClass * loadClass(const JsonNode & node); | ||||
| @@ -206,7 +207,7 @@ public: | ||||
| 	ui64 reqExp(ui32 level) const; //calculates experience required for given level | ||||
|  | ||||
| 	/// Load multiple heroes from json | ||||
| 	void load(const JsonNode & heroes); | ||||
| 	void load(std::string objectID, const JsonNode & heroes); | ||||
|  | ||||
| 	/// Load single hero from json | ||||
| 	CHero * loadHero(const JsonNode & node); | ||||
| @@ -215,7 +216,6 @@ public: | ||||
| 	void load(); | ||||
|  | ||||
| 	void loadHeroes(); | ||||
| 	void loadHeroTexts(); | ||||
| 	void loadExperience(); | ||||
| 	void loadBallistics(); | ||||
| 	void loadTerrains(); | ||||
|   | ||||
| @@ -281,9 +281,17 @@ std::vector<std::string> CModHandler::getActiveMods() | ||||
| } | ||||
|  | ||||
| template<typename Handler> | ||||
| void handleData(Handler handler, const JsonNode & config) | ||||
| void handleData(Handler handler, const JsonNode & sourceList) | ||||
| { | ||||
| 	handler->load(JsonUtils::assembleFromFiles(config.convertTo<std::vector<std::string> >())); | ||||
| 	JsonNode config = JsonUtils::assembleFromFiles(sourceList.convertTo<std::vector<std::string> >()); | ||||
|  | ||||
| 	BOOST_FOREACH(auto & entry, config.Struct()) | ||||
| 	{ | ||||
| 		if (!entry.second.isNull()) // may happens if mod removed object by setting json entry to null | ||||
| 		{ | ||||
| 			handler->load(entry.first, entry.second); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CModHandler::loadActiveMods() | ||||
| @@ -346,8 +354,6 @@ void CModHandler::reload() | ||||
| 				VLC->dobjinfo->gobjs[Obj::ARTIFACT][art->id] = info; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		VLC->arth->reverseMapArtifactConstituents(); | ||||
| 	} | ||||
|  | ||||
| 	{ | ||||
|   | ||||
| @@ -740,7 +740,7 @@ void CGHeroInstance::initHero() | ||||
| 	else //remove placeholder | ||||
| 		spells -= SpellID::PRESET; | ||||
|  | ||||
| 	if(!getArt(ArtifactPosition::MACH4) && !getArt(ArtifactPosition::SPELLBOOK) && !type->spells.empty()) //no catapult means we haven't read pre-existent set -> use default rules for spellbook | ||||
| 	if(!getArt(ArtifactPosition::MACH4) && !getArt(ArtifactPosition::SPELLBOOK) && type->haveSpellBook) //no catapult means we haven't read pre-existent set -> use default rules for spellbook | ||||
| 		putArtifact(ArtifactPosition::SPELLBOOK, CArtifactInstance::createNewArtifactInstance(0)); | ||||
|  | ||||
| 	if(!getArt(ArtifactPosition::MACH4)) | ||||
|   | ||||
| @@ -21,6 +21,8 @@ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| const int NAMES_PER_TOWN=16; // number of town names per faction in H3 files. Json can define any number | ||||
|  | ||||
| const std::string & CBuilding::Name() const | ||||
| { | ||||
| 	return name; | ||||
| @@ -218,7 +220,7 @@ void CTownHandler::loadLegacyData(JsonNode & dest) | ||||
| 			town["name"].String() = typeParser.readString(); | ||||
|  | ||||
|  | ||||
| 			for (int i=0; i<GameConstants::NAMES_PER_TOWN; i++) | ||||
| 			for (int i=0; i<NAMES_PER_TOWN; i++) | ||||
| 			{ | ||||
| 				JsonNode name; | ||||
| 				name.String() = nameParser.readString(); | ||||
| @@ -502,50 +504,47 @@ void CTownHandler::loadPuzzle(CFaction &faction, const JsonNode &source) | ||||
| 	assert(faction.puzzleMap.size() == GameConstants::PUZZLE_MAP_PIECES); | ||||
| } | ||||
|  | ||||
| void CTownHandler::load(const JsonNode &source) | ||||
| void CTownHandler::load(std::string townID, const JsonNode &source) | ||||
| { | ||||
| 	BOOST_FOREACH(auto & node, source.Struct()) | ||||
| 	{ | ||||
| 		int id; | ||||
| 	int id; | ||||
|  | ||||
| 		if (node.second["index"].isNull()) | ||||
| 			id = factions.rbegin()->first + 1; | ||||
| 		else | ||||
| 			id = node.second["index"].Float(); | ||||
| 	if (source["index"].isNull()) | ||||
| 		id = factions.rbegin()->first + 1; | ||||
| 	else | ||||
| 		id = source["index"].Float(); | ||||
|  | ||||
| 		CFaction & faction = factions[id]; | ||||
| 	CFaction & faction = factions[id]; | ||||
|  | ||||
| 		faction.factionID = id; | ||||
| 		faction.name = node.second["name"].String(); | ||||
| 	faction.factionID = id; | ||||
| 	faction.name = source["name"].String(); | ||||
|  | ||||
| 		VLC->modh->identifiers.requestIdentifier ("creature." + node.second["commander"].String(), | ||||
| 			[=](si32 commanderID) | ||||
| 			{ | ||||
| 				factions[id].commander = CreatureID(commanderID); | ||||
| 			}); | ||||
|  | ||||
| 		faction.creatureBg120 = node.second["creatureBackground"]["120px"].String(); | ||||
| 		faction.creatureBg130 = node.second["creatureBackground"]["130px"].String(); | ||||
|  | ||||
| 		faction.nativeTerrain = ETerrainType(vstd::find_pos(GameConstants::TERRAIN_NAMES, | ||||
| 			node.second["nativeTerrain"].String())); | ||||
| 		int alignment = vstd::find_pos(EAlignment::names, node.second["alignment"].String()); | ||||
| 		if (alignment == -1) | ||||
| 			faction.alignment = EAlignment::NEUTRAL; | ||||
| 		else | ||||
| 			faction.alignment = static_cast<EAlignment::EAlignment>(alignment); | ||||
|  | ||||
| 		if (!node.second["town"].isNull()) | ||||
| 	VLC->modh->identifiers.requestIdentifier ("creature." + source["commander"].String(), | ||||
| 		[=](si32 commanderID) | ||||
| 		{ | ||||
| 			towns[id].typeID = id; | ||||
| 			loadTown(towns[id], node.second["town"]); | ||||
| 		} | ||||
| 		if (!node.second["puzzleMap"].isNull()) | ||||
| 			loadPuzzle(faction, node.second["puzzleMap"]); | ||||
| 			factions[id].commander = CreatureID(commanderID); | ||||
| 		}); | ||||
|  | ||||
| 		tlog5 << "Added faction: " << node.first << "\n"; | ||||
| 		VLC->modh->identifiers.registerObject(std::string("faction.") + node.first, faction.factionID); | ||||
| 	faction.creatureBg120 = source["creatureBackground"]["120px"].String(); | ||||
| 	faction.creatureBg130 = source["creatureBackground"]["130px"].String(); | ||||
|  | ||||
| 	faction.nativeTerrain = ETerrainType(vstd::find_pos(GameConstants::TERRAIN_NAMES, | ||||
| 		source["nativeTerrain"].String())); | ||||
| 	int alignment = vstd::find_pos(EAlignment::names, source["alignment"].String()); | ||||
| 	if (alignment == -1) | ||||
| 		faction.alignment = EAlignment::NEUTRAL; | ||||
| 	else | ||||
| 		faction.alignment = static_cast<EAlignment::EAlignment>(alignment); | ||||
|  | ||||
| 	if (!source["town"].isNull()) | ||||
| 	{ | ||||
| 		towns[id].typeID = id; | ||||
| 		loadTown(towns[id], source["town"]); | ||||
| 	} | ||||
| 	if (!source["puzzleMap"].isNull()) | ||||
| 		loadPuzzle(faction, source["puzzleMap"]); | ||||
|  | ||||
| 	tlog5 << "Added faction: " << townID << "\n"; | ||||
| 	VLC->modh->identifiers.registerObject(std::string("faction.") + townID, faction.factionID); | ||||
| } | ||||
|  | ||||
| void CTownHandler::load() | ||||
| @@ -587,7 +586,10 @@ void CTownHandler::load() | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	load(buildingsConf); | ||||
| 	BOOST_FOREACH(auto & entry, buildingsConf.Struct()) | ||||
| 	{ | ||||
| 		load(entry.first, entry.second); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::set<TFaction> CTownHandler::getDefaultAllowedFactions() const | ||||
|   | ||||
| @@ -221,7 +221,7 @@ public: | ||||
|  | ||||
| 	/// main loading function for mods, accepts merged JSON source and add all entries from it into game | ||||
| 	/// all entries in JSON should be checked for validness before using this function | ||||
| 	void load(const JsonNode & source); | ||||
| 	void load(std::string townID, const JsonNode & source); | ||||
|  | ||||
| 	/// "entry point" for loading of OH3 town. | ||||
| 	/// reads legacy txt's from H3 + vcmi json, merges them | ||||
|   | ||||
| @@ -60,36 +60,38 @@ namespace GameConstants | ||||
| 	const int BFIELD_HEIGHT = 11; | ||||
| 	const int BFIELD_SIZE = BFIELD_WIDTH * BFIELD_HEIGHT; | ||||
|  | ||||
| 	const int ARMY_SIZE = 7; | ||||
| 	const int PUZZLE_MAP_PIECES = 48; | ||||
|  | ||||
| 	const int CREATURES_COUNT = 197; | ||||
| 	const int CRE_LEVELS = 10; | ||||
| 	const int F_NUMBER = 9; //factions (town types) quantity | ||||
| 	const int PLAYER_LIMIT = 8; //player limit per map | ||||
| 	const int MAX_HEROES_PER_PLAYER = 8; | ||||
| 	const int AVAILABLE_HEROES_PER_PLAYER = 2; | ||||
|  | ||||
| 	const int UNFLAGGABLE_PLAYER = 254; //254 - neutral objects (pandora, banks) | ||||
| 	const int NEUTRAL_PLAYER=255; | ||||
| 	const int ALL_PLAYERS = 255; //bitfield | ||||
| 	const int HEROES_PER_TYPE=8; //amount of heroes of each type | ||||
| 	const int SKILL_QUANTITY=28; | ||||
|  | ||||
| 	const ui16 BACKPACK_START = 19; | ||||
| 	const int CREATURES_PER_TOWN = 7; //without upgrades | ||||
| 	const int SPELL_LEVELS = 5; | ||||
|  | ||||
| 	const int SPELLBOOK_GOLD_COST = 500; | ||||
| 	const int BATTLE_PENALTY_DISTANCE = 10; //if the distance is > than this, then shooting stack has distance penalty | ||||
| 	const int ARMY_SIZE = 7; | ||||
| 	const int SKILL_PER_HERO=8; | ||||
|  | ||||
| 	const int CRE_LEVELS = 10; | ||||
| 	const int SKILL_QUANTITY=28; | ||||
| 	const int PRIMARY_SKILLS=4; | ||||
| 	const int TERRAIN_TYPES=10; | ||||
| 	const int RESOURCE_QUANTITY=8; | ||||
| 	const int HEROES_PER_TYPE=8; //amount of heroes of each type | ||||
|  | ||||
| 	// amounts of OH3 objects. Can be changed by mods, should be used only during H3 loading phase | ||||
| 	const int F_NUMBER = 9; | ||||
| 	const int ARTIFACTS_QUANTITY=171; | ||||
| 	const int HEROES_QUANTITY=156; | ||||
| 	const int SPELLS_QUANTITY=70; | ||||
| 	const int PRIMARY_SKILLS=4; | ||||
| 	const int UNFLAGGABLE_PLAYER = 254; //254 - neutral objects (pandora, banks) | ||||
| 	const int NEUTRAL_PLAYER=255; | ||||
| 	const int NAMES_PER_TOWN=16; | ||||
| 	const int CREATURES_PER_TOWN = 7; //without upgrades | ||||
| 	const int SPELL_LEVELS = 5; | ||||
| 	const int AVAILABLE_HEROES_PER_PLAYER = 2; | ||||
| 	const int SPELLBOOK_GOLD_COST = 500; | ||||
| 	const int PUZZLE_MAP_PIECES = 48; | ||||
|  | ||||
| 	const int BATTLE_PENALTY_DISTANCE = 10; //if the distance is > than this, then shooting stack has distance penalty | ||||
|  | ||||
| 	const ui16 BACKPACK_START = 19; | ||||
|  | ||||
| 	const int TERRAIN_TYPES=10; | ||||
| 	const int RESOURCE_QUANTITY=8; | ||||
| 	const int CREATURES_COUNT = 197; | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -740,9 +742,9 @@ public: | ||||
| 		BALLISTA = 4, | ||||
| 		AMMO_CART = 5, | ||||
| 		FIRST_AID_TENT = 6, | ||||
| 		CENTAUR_AXE = 7, | ||||
| 		BLACKSHARD_OF_THE_DEAD_KNIGHT = 8, | ||||
| 		CORNUCOPIA = 140, | ||||
| 		//CENTAUR_AXE = 7, | ||||
| 		//BLACKSHARD_OF_THE_DEAD_KNIGHT = 8, | ||||
| 		//CORNUCOPIA = 140, | ||||
| 		ART_SELECTION = 144, | ||||
| 		ART_LOCK = 145, | ||||
| 		AXE_OF_SMASHING = 146, | ||||
| @@ -753,8 +755,8 @@ public: | ||||
| 		BOOTS_OF_HASTE = 151, | ||||
| 		BOW_OF_SEEKING = 152, | ||||
| 		DRAGON_EYE_RING = 153, | ||||
| 		HARDENED_SHIELD = 154, | ||||
| 		SLAVAS_RING_OF_POWER = 155 | ||||
| 		//HARDENED_SHIELD = 154, | ||||
| 		//SLAVAS_RING_OF_POWER = 155 | ||||
| 	}; | ||||
|  | ||||
| 	ArtifactID(EArtifactID _num = NONE) : num(_num) | ||||
| @@ -853,7 +855,7 @@ public: | ||||
| ID_LIKE_OPERATORS_DECLS(SpellID, SpellID::ESpellID) | ||||
|  | ||||
| // Typedef declarations | ||||
| typedef si8 TFaction; | ||||
| typedef ui8 TFaction; | ||||
| typedef si64 TExpType; | ||||
| typedef std::pair<ui32, ui32> TDmgRange; | ||||
| typedef si32 TBonusSubtype; | ||||
|   | ||||
| @@ -89,6 +89,12 @@ public: | ||||
| 	template<typename Type> | ||||
| 	Type convertTo() const; | ||||
|  | ||||
| 	/// Similar to convertTo but will assign data only if node is not null | ||||
| 	/// Othervice original data will be preserved | ||||
| 	/// Returns true if data was assigned | ||||
| 	template<typename Type> | ||||
| 	bool loadTo(Type & data) const; | ||||
|  | ||||
| 	//operator [], for structs only - get child node by name | ||||
| 	JsonNode & operator[](std::string child); | ||||
| 	const JsonNode & operator[](std::string child) const; | ||||
| @@ -367,4 +373,12 @@ template<typename Type> | ||||
| Type JsonNode::convertTo() const | ||||
| { | ||||
| 	return JsonDetail::JsonConverter<Type>::convert(*this); | ||||
| } | ||||
| } | ||||
|  | ||||
| template<typename Type> | ||||
| bool JsonNode::loadTo(Type & data) const | ||||
| { | ||||
| 	if (!isNull()) | ||||
| 		data = convertTo<Type>(); | ||||
| 	return !isNull(); | ||||
| } | ||||
|   | ||||
| @@ -683,7 +683,7 @@ CArtifactInstance * CMapLoaderH3M::createArtifact(int aid, int spellID /*= -1*/) | ||||
| 	map->addNewArtifactInstance(a); | ||||
|  | ||||
| 	//TODO make it nicer | ||||
| 	if(a->artType && a->artType->constituents) | ||||
| 	if(a->artType && a->artType->constituents != nullptr) | ||||
| 	{ | ||||
| 		CCombinedArtifactInstance * comb = dynamic_cast<CCombinedArtifactInstance *>(a); | ||||
| 		BOOST_FOREACH(CCombinedArtifactInstance::ConstituentInfo & ci, comb->constituentsInfo) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user