1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +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:
Ivan Savenko 2013-03-02 16:55:51 +00:00
parent cc2391d641
commit f306d7bb70
17 changed files with 565 additions and 729 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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