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:
parent
cc2391d641
commit
f306d7bb70
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user