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

[refactor]

* spells are now more configurable (unused yet, WiP)
* a few more cleanups
This commit is contained in:
alexvins 2013-01-15 14:20:48 +00:00
parent 264ce77ec9
commit 68e91ada1c
13 changed files with 1202 additions and 329 deletions

View File

@ -7,88 +7,914 @@
// anim: main effect animation (AC format), -1 - none // anim: main effect animation (AC format), -1 - none
// ranges: spell range description in SRSL ([no magic] [basic] [advanced] [expert]) // ranges: spell range description in SRSL ([no magic] [basic] [advanced] [expert])
// flags: string array of
// damage
// directDamage //todo
// rising
// mind
//effects: array of bonus for permanent effects
"spells": "spells":
{ {
"summonBoat" : { "id": 0, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "summonBoat" :
"scuttleBoat" : { "id": 1, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, {
"visions" : { "id": 2, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "id": 0,
"viewEarth" : { "id": 3, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "effect": 0,
"disguise" : { "id": 4, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "anim": -1,
"viewAir" : { "id": 5, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "ranges": [ "X", "X", "X", "X" ]
"fly" : { "id": 6, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, },
"waterWalk" : { "id": 7, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "scuttleBoat" :
"dimensionDoor" : { "id": 8, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, {
"townPortal" : { "id": 9, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "id": 1,
"quicksand" : { "id": 10, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "effect": 0,
"landMine" : { "id": 11, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "anim": -1,
"forceField" : { "id": 12, "effect": 0, "anim": -1, "ranges": [ "0", "0", "0", "0" ] }, "ranges": [ "X", "X", "X", "X" ]
"fireWall" : { "id": 13, "effect": 0, "anim": -1, "ranges": [ "0", "0", "0", "0" ] }, },
"earthquake" : { "id": 14, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "visions" :
"magicArrow" : { "id": 15, "effect": -1, "anim": 64, "ranges": [ "0", "0", "0", "0" ] }, {
"iceBolt" : { "id": 16, "effect": -1, "anim": 46, "ranges": [ "0", "0", "0", "0" ] }, "id": 2,
"lightningBolt" : { "id": 17, "effect": -1, "anim": 38, "ranges": [ "0", "0", "0", "0" ] }, "effect": 0,
"implosion" : { "id": 18, "effect": -1, "anim": 10, "ranges": [ "0", "0", "0", "0" ] }, "anim": -1,
"chainLightning" : { "id": 19, "effect": -1, "anim": 38, "ranges": [ "0", "0", "0", "0" ] }, "ranges": [ "X", "X", "X", "X" ]
"frostRing" : { "id": 20, "effect": -1, "anim": 45, "ranges": [ "1", "1", "1", "1" ] }, },
"fireball" : { "id": 21, "effect": -1, "anim": 53, "ranges": [ "0,1", "0,1", "0,1", "0,1" ] }, "viewEarth" :
"inferno" : { "id": 22, "effect": -1, "anim": 9, "ranges": [ "0-2", "0-2", "0-2", "0-2" ] }, {
"meteorShower" : { "id": 23, "effect": -1, "anim": 16, "ranges": [ "0,1", "0,1", "0,1", "0,1" ] }, "id": 3,
"deathRipple" : { "id": 24, "effect": -1, "anim": 8, "ranges": [ "X", "X", "X", "X" ] }, "effect": 0,
"destroyUndead" : { "id": 25, "effect": -1, "anim": 29, "ranges": [ "X", "X", "X", "X" ] }, "anim": -1,
"armageddon" : { "id": 26, "effect": -1, "anim": 12, "ranges": [ "X", "X", "X", "X" ] }, "ranges": [ "X", "X", "X", "X" ]
"shield" : { "id": 27, "effect": 1, "anim": 27, "ranges": [ "0", "0", "0", "X" ] }, },
"airShield" : { "id": 28, "effect": 1, "anim": 2, "ranges": [ "0", "0", "0", "X" ] }, "disguise" :
"fireShield" : { "id": 29, "effect": 1, "anim": 11, "ranges": [ "0", "0", "0", "X" ] }, {
"protectAir" : { "id": 30, "effect": 1, "anim": 22, "ranges": [ "0", "0", "0", "X" ] }, "id": 4,
"protectFire" : { "id": 31, "effect": 1, "anim": 24, "ranges": [ "0", "0", "0", "X" ] }, "effect": 0,
"protectWater" : { "id": 32, "effect": 1, "anim": 23, "ranges": [ "0", "0", "0", "X" ] }, "anim": -1,
"protectEarth" : { "id": 33, "effect": 1, "anim": 26, "ranges": [ "0", "0", "0", "X" ] }, "ranges": [ "X", "X", "X", "X" ]
"antiMagic" : { "id": 34, "effect": 1, "anim": 5, "ranges": [ "0", "0", "0", "X" ] }, },
"dispel" : { "id": 35, "effect": 0, "anim": 41, "ranges": [ "0", "0", "0", "X" ] }, "viewAir" :
"magicMirror" : { "id": 36, "effect": 1, "anim": 3, "ranges": [ "0", "0", "0", "0" ] }, {
"cure" : { "id": 37, "effect": 1, "anim": 39, "ranges": [ "0", "0", "0", "0" ] }, "id": 5,
"resurrection" : { "id": 38, "effect": 1, "anim": 79, "ranges": [ "0", "0", "0", "0" ] }, "effect": 0,
"animateDead" : { "id": 39, "effect": 1, "anim": 79, "ranges": [ "0", "0", "0", "0" ] }, "anim": -1,
"sacrifice" : { "id": 40, "effect": 1, "anim": 79, "ranges": [ "0", "0", "0", "0" ] }, "ranges": [ "X", "X", "X", "X" ]
"bless" : { "id": 41, "effect": 1, "anim": 36, "ranges": [ "0", "0", "0", "X" ], "counters" : [42] }, },
"curse" : { "id": 42, "effect": -1, "anim": 40, "ranges": [ "0", "0", "0", "X" ], "counters" : [41] }, "fly" :
"bloodlust" : { "id": 43, "effect": 1, "anim": 4, "ranges": [ "0", "0", "0", "X" ], "counters" : [45] }, {
"precision" : { "id": 44, "effect": 1, "anim": 25, "ranges": [ "0", "0", "0", "X" ] }, "id": 6,
"weakness" : { "id": 45, "effect": -1, "anim": 56, "ranges": [ "0", "0", "0", "X" ], "counters" : [43] }, "effect": 0,
"stoneSkin" : { "id": 46, "effect": 1, "anim": 54, "ranges": [ "0", "0", "0", "X" ] }, "anim": -1,
"disruptingRay" : { "id": 47, "effect": -1, "anim": 14, "ranges": [ "0", "0", "0", "0" ] }, "ranges": [ "X", "X", "X", "X" ]
"prayer" : { "id": 48, "effect": 1, "anim": 0, "ranges": [ "0", "0", "0", "X" ] }, },
"mirth" : { "id": 49, "effect": 1, "anim": 20, "ranges": [ "0", "0", "0", "X" ], "counters" : [50] }, "waterWalk" :
"sorrow" : { "id": 50, "effect": -1, "anim": 30, "ranges": [ "0", "0", "0", "X" ], "counters" : [49] }, {
"fortune" : { "id": 51, "effect": 1, "anim": 18, "ranges": [ "0", "0", "0", "X" ], "counters" : [52] }, "id": 7,
"misfortune" : { "id": 52, "effect": -1, "anim": 48, "ranges": [ "0", "0", "0", "X" ], "counters" : [51] }, "effect": 0,
"haste" : { "id": 53, "effect": 1, "anim": 31, "ranges": [ "0", "0", "0", "X" ], "counters" : [54] }, "anim": -1,
"slow" : { "id": 54, "effect": -1, "anim": 19, "ranges": [ "0", "0", "0", "X" ], "counters" : [53] }, "ranges": [ "X", "X", "X", "X" ]
"slayer" : { "id": 55, "effect": 1, "anim": 28, "ranges": [ "0", "0", "0", "0" ] }, },
"frenzy" : { "id": 56, "effect": 1, "anim": 17, "ranges": [ "0", "0", "0", "0" ] }, "dimensionDoor" :
"titanBolt" : { "id": 57, "effect": -1, "anim": 38, "ranges": [ "0", "0", "0", "0" ] }, {
"counterstrike" : { "id": 58, "effect": 1, "anim": 7, "ranges": [ "0", "0", "0", "X" ] }, "id": 8,
"berserk" : { "id": 59, "effect": -1, "anim": 35, "ranges": [ "0", "0", "0-1", "0-2" ] }, "effect": 0,
"hypnotize" : { "id": 60, "effect": -1, "anim": 21, "ranges": [ "0", "0", "0", "0" ] }, "anim": -1,
"forgetfulness" : { "id": 61, "effect": -1, "anim": 42, "ranges": [ "0", "0", "0", "X" ] }, "ranges": [ "X", "X", "X", "X" ]
"blind" : { "id": 62, "effect": -1, "anim": 6, "ranges": [ "0", "0", "0", "0" ] }, },
"teleport" : { "id": 63, "effect": 1, "anim": -1, "ranges": [ "0", "0", "0", "0" ] }, "townPortal" :
"removeObstacle" : { "id": 64, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, {
"clone" : { "id": 65, "effect": 1, "anim": -1, "ranges": [ "0", "0", "0", "0" ] }, "id": 9,
"fireElemental" : { "id": 66, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "effect": 0,
"earthElemental" : { "id": 67, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "anim": -1,
"waterElemental" : { "id": 68, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, "ranges": [ "X", "X", "X", "X" ]
"airElemental" : { "id": 69, "effect": 0, "anim": -1, "ranges": [ "X", "X", "X", "X" ] }, },
"stoneGaze" : { "id": 70, "effect": 0, "anim": 70, "ranges": [ "0", "0", "0", "0" ] }, "quicksand" :
"poison" : { "id": 71, "effect": -1, "anim": 67, "ranges": [ "0", "0", "0", "0" ] }, {
"bind" : { "id": 72, "effect": 0, "anim": 68, "ranges": [ "0", "0", "0", "0" ] }, "id": 10,
"disease" : { "id": 73, "effect": -1, "anim": 69, "ranges": [ "0", "0", "0", "0" ] }, "effect": 0,
"paralyze" : { "id": 74, "effect": -1, "anim": 70, "ranges": [ "0", "0", "0", "0" ] }, "anim": -1,
"age" : { "id": 75, "effect": -1, "anim": 71, "ranges": [ "0", "0", "0", "0" ] }, "ranges": [ "X", "X", "X", "X" ]
"deathCloud" : { "id": 76, "effect": 0, "anim": 72, "ranges": [ "0-1", "0-1", "0-1", "0-1" ] }, },
"thunderbolt" : { "id": 77, "effect": -1, "anim": 38, "ranges": [ "0", "0", "0", "0" ] }, "landMine" :
"dispelHelpful" : { "id": 78, "effect": -1, "anim": 41, "ranges": [ "0", "0", "0", "0" ] }, {
"deathStare" : { "id": 79, "effect": 0, "anim": 80, "ranges": [ "0", "0", "0", "0" ] }, "id": 11,
"acidBreath" : { "id": 80, "effect": 0, "anim": 81, "ranges": [ "0", "0", "0", "0" ] } "effect": 0,
"anim": -1,
"ranges": [ "X", "X", "X", "X" ],
"flags" : ["damage"]
},
"forceField" :
{
"id": 12,
"effect": 0,
"anim": -1,
"ranges": [ "0", "0", "0", "0" ]
},
"fireWall" :
{
"id": 13,
"effect": 0,
"anim": -1,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["damage"]
},
"earthquake" :
{
"id": 14,
"effect": 0,
"anim": -1,
"ranges": [ "X", "X", "X", "X" ]
},
"magicArrow" :
{
"id": 15,
"effect": -1,
"anim": 64,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["damage"]
},
"iceBolt" :
{
"id": 16,
"effect": -1,
"anim": 46,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["damage"]
},
"lightningBolt" :
{
"id": 17,
"effect": -1,
"anim": 38,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["damage"]
},
"implosion" :
{
"id": 18,
"effect": -1,
"anim": 10,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["damage"]
},
"chainLightning" :
{
"id": 19,
"effect": -1,
"anim": 38,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["damage"]
},
"frostRing" :
{
"id": 20,
"effect": -1,
"anim": 45,
"ranges": [ "1", "1", "1", "1" ],
"flags" : ["damage"]
},
"fireball" :
{
"id": 21,
"effect": -1,
"anim": 53,
"ranges": [ "0,1", "0,1", "0,1", "0,1" ],
"flags" : ["damage"]
},
"inferno" :
{
"id": 22,
"effect": -1,
"anim": 9,
"ranges": [ "0-2", "0-2", "0-2", "0-2" ],
"flags" : ["damage"]
},
"meteorShower" :
{
"id": 23,
"effect": -1,
"anim": 16,
"ranges": [ "0,1", "0,1", "0,1", "0,1" ],
"flags" : ["damage"]
},
"deathRipple" :
{
"id": 24,
"effect": -1,
"anim": 8,
"ranges": [ "X", "X", "X", "X" ],
"flags" : ["damage"]
},
"destroyUndead" :
{
"id": 25,
"effect": -1,
"anim": 29,
"ranges": [ "X", "X", "X", "X" ],
"flags" : ["damage"]
},
"armageddon" :
{
"id": 26,
"effect": -1,
"anim": 12,
"ranges": [ "X", "X", "X", "X" ],
"flags" : ["damage"]
},
"shield" :
{
"id": 27,
"effect": 1,
"anim": 27,
"ranges": [ "0", "0", "0", "X" ],
"effects":
[
{
"type": "GENERAL_DAMAGE_REDUCTION",
"subtype":0
}
]
},
"airShield" :
{
"id": 28,
"effect": 1,
"anim": 2,
"ranges": [ "0", "0", "0", "X" ],
"effects":
[
{
"type": "GENERAL_DAMAGE_REDUCTION",
"subtype":1
}
]
},
"fireShield" :
{
"id": 29,
"effect": 1,
"anim": 11,
"ranges": [ "0", "0", "0", "X" ],
"effects":
[
{
"type": "FIRE_SHIELD"
}
]
},
"protectAir" :
{
"id": 30,
"effect": 1,
"anim": 22,
"ranges": [ "0", "0", "0", "X" ],
"effects":
[
{
"type": "SPELL_DAMAGE_REDUCTION",
"subtype":0
}
]
},
"protectFire" :
{
"id": 31,
"effect": 1,
"anim": 24,
"ranges": [ "0", "0", "0", "X" ],
"effects":
[
{
"type": "SPELL_DAMAGE_REDUCTION",
"subtype":1
}
]
},
"protectWater" :
{
"id": 32,
"effect": 1,
"anim": 23,
"ranges": [ "0", "0", "0", "X" ],
"effects":
[
{
"type": "SPELL_DAMAGE_REDUCTION",
"subtype":2
}
]
},
"protectEarth" :
{
"id": 33,
"effect": 1,
"anim": 26,
"ranges": [ "0", "0", "0", "X" ],
"effects":
[
{
"type": "SPELL_DAMAGE_REDUCTION",
"subtype":3
}
]
},
"antiMagic" :
{
"id": 34,
"effect": 1,
"anim": 5,
"ranges": [ "0", "0", "0", "X" ],
"effects":
[
{
"type": "LEVEL_SPELL_IMMUNITY",
"subtype":5,
"valType":"INDEPENDENT_MAX"
}
]
},
"dispel" :
{
"id": 35,
"effect": 0,
"anim": 41,
"ranges": [ "0", "0", "0", "X" ]
},
"magicMirror" :
{
"id": 36,
"effect": 1,
"anim": 3,
"ranges": [ "0", "0", "0", "0" ],
"effects":
[
{
"type": "MAGIC_MIRROR",
"valType":"INDEPENDENT_MAX"
}
]
},
"cure" :
{
"id": 37,
"effect": 1,
"anim": 39,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["rising"]
},
"resurrection" :
{
"id": 38,
"effect": 1,
"anim": 79,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["rising"]
},
"animateDead" :
{
"id": 39,
"effect": 1,
"anim": 79,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["rising"]
},
"sacrifice" :
{
"id": 40,
"effect": 1,
"anim": 79,
"ranges": [ "0", "0", "0", "0" ]
},
"bless" :
{
"id": 41,
"effect": 1,
"anim": 36,
"ranges": [ "0", "0", "0", "X" ],
"counters" : [42],
"effects":
[
{
"type": "ALWAYS_MAXIMUM_DAMAGE",
"valType":"INDEPENDENT_MAX"
}
]
},
"curse" :
{
"id": 42,
"effect": -1,
"anim": 40,
"ranges": [ "0", "0", "0", "X" ], "counters" : [41],
"effects":
[
{
"type": "ALWAYS_MINIMUM_DAMAGE",
"valType":"INDEPENDENT_MAX"
}
]
},
"bloodlust" :
{
"id": 43,
"effect": 1,
"anim": 4,
"ranges": [ "0", "0", "0", "X" ], "counters" : [45],
"effects":
[
{
"type": "PRIMARY_SKILL",
"subtype": 0, //ATTACK
"effectRange" : "ONLY_MELEE_FIGHT"
}
]
},
"precision" :
{
"id": 44,
"effect": 1,
"anim": 25,
"ranges": [ "0", "0", "0", "X" ],
"effects":
[
{
"type": "PRIMARY_SKILL",
"subtype": 0, //ATTACK
"effectRange" : "ONLY_DISTANCE_FIGHT"
}
]
},
"weakness" :
{
"id": 45,
"effect": -1,
"anim": 56,
"ranges": [ "0", "0", "0", "X" ], "counters" : [43],
"effects":
[
{
"type": "PRIMARY_SKILL",
"subtype": 0 //ATTACK
}
]
},
"stoneSkin" :
{
"id": 46,
"effect": 1,
"anim": 54,
"ranges": [ "0", "0", "0", "X" ],
"effects":
[
{
"type": "PRIMARY_SKILL",
"subtype": 1 //DEFENSE
}
]
},
"disruptingRay" :
{
"id": 47,
"effect": -1,
"anim": 14,
"ranges": [ "0", "0", "0", "0" ],
"effects":
[
{
"type": "PRIMARY_SKILL",
"subtype": 1 //DEFENSE
}
]
},
"prayer" :
{
"id": 48,
"effect": 1,
"anim": 0,
"ranges": [ "0", "0", "0", "X" ],
"effects":
[
{
"type": "PRIMARY_SKILL",
"subtype": 0 //ATTACK
},
{
"type": "PRIMARY_SKILL",
"subtype": 1 //DEFENSE
},
{
"type": "STACKS_SPEED"
}
]
},
"mirth" :
{
"id": 49,
"effect": 1,
"anim": 20,
"ranges": [ "0", "0", "0", "X" ],
"counters" : [50],
"effects":
[
{
"type": "MORALE"
}
]
},
"sorrow" :
{
"id": 50,
"effect": -1,
"anim": 30,
"ranges": [ "0", "0", "0", "X" ], "counters" : [49],
"flags" : ["mind"],
"effects":
[
{
"type": "MORALE"
}
]
},
"fortune" :
{
"id": 51,
"effect": 1,
"anim": 18,
"ranges": [ "0", "0", "0", "X" ],
"counters" : [52],
"effects":
[
{
"type": "LUCK"
}
]
},
"misfortune" :
{
"id": 52,
"effect": -1,
"anim": 48,
"ranges": [ "0", "0", "0", "X" ],
"counters" : [51],
"effects":
[
{
"type": "LUCK"
}
]
},
"haste" :
{
"id": 53,
"effect": 1,
"anim": 31,
"ranges": [ "0", "0", "0", "X" ],
"counters" : [54],
"effects":
[
{
"type": "STACKS_SPEED"
}
]
},
"slow" :
{
"id": 54,
"effect": -1,
"anim": 19,
"ranges": [ "0", "0", "0", "X" ],
"counters" : [53],
"effects":
[
{
"type": "STACKS_SPEED"
}
]
},
"slayer" :
{
"id": 55,
"effect": 1,
"anim": 28,
"ranges": [ "0", "0", "0", "0" ],
"effects":
[
{
"type": "SLAYER"
}
]
},
"frenzy" :
{
"id": 56,
"effect": 1,
"anim": 17,
"ranges": [ "0", "0", "0", "0" ],
"effects":
[
{
"type": "IN_FRENZY"
}
]
},
"titanBolt" :
{
"id": 57,
"effect": -1,
"anim": 38,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["damage"]
},
"counterstrike" :
{
"id": 58,
"effect": 1,
"anim": 7,
"ranges": [ "0", "0", "0", "X" ],
"effects":
[
{
"type": "ADDITIONAL_RETALIATION"
}
]
},
"berserk" :
{
"id": 59,
"effect": -1,
"anim": 35,
"ranges": [ "0", "0", "0-1", "0-2" ],
"flags" : ["mind"],
"effects":
[
{
"type": "ATTACKS_NEAREST_CREATURE"
}
]
},
"hypnotize" :
{
"id": 60,
"effect": -1,
"anim": 21,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["mind"],
"effects":
[
{
"type": "HYPNOTIZED"
}
]
},
"forgetfulness" :
{
"id": 61,
"effect": -1,
"anim": 42,
"ranges": [ "0", "0", "0", "X" ],
"flags" : ["mind"],
"effects":
[
{
"type": "FORGETFULL"
}
]
},
"blind" :
{
"id": 62,
"effect": -1,
"anim": 6,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["mind"],
"effects":
[
{
"type": "NOT_ACTIVE",
"subtype": 62, //really ase spell id, is it right?
//TODO: duration
},
{
"type": "GENERAL_ATTACK_REDUCTION"
//TODO: duration
},
{
"type": "NO_RETALIATION",
"duration": "UNITL_BEING_ATTACKED"
}
]
},
"teleport" :
{
"id": 63,
"effect": 1,
"anim": -1,
"ranges": [ "0", "0", "0", "0" ]
},
"removeObstacle" :
{
"id": 64,
"effect": 0,
"anim": -1,
"ranges": [ "X", "X", "X", "X" ]
},
"clone" :
{
"id": 65,
"effect": 1,
"anim": -1,
"ranges": [ "0", "0", "0", "0" ]
},
"fireElemental" :
{
"id": 66,
"effect": 0,
"anim": -1,
"ranges": [ "X", "X", "X", "X" ]
},
"earthElemental" :
{
"id": 67,
"effect": 0,
"anim": -1,
"ranges": [ "X", "X", "X", "X" ]
},
"waterElemental" :
{
"id": 68,
"effect": 0,
"anim": -1,
"ranges": [ "X", "X", "X", "X" ]
},
"airElemental" :
{
"id": 69,
"effect": 0,
"anim": -1,
"ranges": [ "X", "X", "X", "X" ]
},
"stoneGaze" :
{
"id": 70,
"effect": 0,
"anim": 70,
"ranges": [ "0", "0", "0", "0" ],
"effects":
[
{
"type": "NOT_ACTIVE",
"subtype": 62
//TODO: duration
},
{
"type": "NO_RETALIATION",
"duration": "UNITL_BEING_ATTACKED"
}
]
},
"poison" :
{
"id": 71,
"effect": -1,
"anim": 67,
"ranges": [ "0", "0", "0", "0" ],
"effects":
[
{
"type": "POISON",
"val" : 30,
"valueType": "INDEPENDENT_MAX"
},
{
"type": "STACK_HEALTH",
"val" : -10,
"valueType": "PERCENT_TO_ALL"
}
]
},
"bind" :
{
"id": 72,
"effect": 0,
"anim": 68,
"ranges": [ "0", "0", "0", "0" ],
"effects":
[
{
"type": "BIND_EFFECT",
"val" : 30,
"turns" : 1,
"duration" : "PERMANENT"
}
]
},
"disease" :
{
"id": 73,
"effect": -1,
"anim": 69,
"ranges": [ "0", "0", "0", "0" ],
"effects":
[
{
"type": "PRIMARY_SKILL",
"subtype": 0,
"val" : -2,
},
{
"type": "PRIMARY_SKILL",
"subtype": 1,
"val" : -2,
}
]
},
"paralyze" :
{
"id": 74,
"effect": -1,
"anim": 70,
"ranges": [ "0", "0", "0", "0" ],
"effects":
[
{
"type": "NOT_ACTIVE",
"subtype": 74,
//TODO: duration
},
{
"type": "NO_RETALIATION",
"duration": "UNITL_BEING_ATTACKED"
}
]
},
"age" :
{
"id": 75,
"effect": -1,
"anim": 71,
"ranges": [ "0", "0", "0", "0" ],
"effects":
[
{
"type": "STACK_HEALTH",
"val" : -50,
"valueType": "PERCENT_TO_ALL"
}
]
},
"deathCloud" :
{
"id": 76,
"effect": 0,
"anim": 72,
"ranges": [ "0-1", "0-1", "0-1", "0-1" ]
},
"thunderbolt" :
{
"id": 77,
"effect": -1,
"anim": 38,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["damage"]
},
"dispelHelpful" :
{
"id": 78,
"effect": -1,
"anim": 41,
"ranges": [ "0", "0", "0", "0" ]
},
"deathStare" :
{
"id": 79,
"effect": 0,
"anim": 80,
"ranges": [ "0", "0", "0", "0" ]
},
"acidBreath" :
{
"id": 80,
"effect": 0,
"anim": 81,
"ranges": [ "0", "0", "0", "0" ],
"effects":
[
{
"type": "PRIMARY_SKILL",
"subtype": 1,
"val" : -3,
"duration" : "PERMANENT",
"valueType": "ADDITIVE_VALUE"
}
]
},
"acidBreathDamage" :
{
"id": 81,
"effect": 0,
"anim": 81,
"ranges": [ "0", "0", "0", "0" ],
"flags" : ["damage"]
}
} }
} }

View File

@ -186,7 +186,7 @@ ui32 BattleInfo::calculateHealedHP(const CSpell * spell, int usedSpellPower, int
} }
bool BattleInfo::resurrects(TSpell spellid) const bool BattleInfo::resurrects(TSpell spellid) const
{ {
return vstd::contains(VLC->spellh->risingSpells, spellid); return VLC->spellh->spells[spellid]->isRisingSpell();
} }
const CStack * BattleInfo::battleGetStack(BattleHex pos, bool onlyAlive) const CStack * BattleInfo::battleGetStack(BattleHex pos, bool onlyAlive)
@ -931,170 +931,146 @@ si32 CStack::magicResistance() const
void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse) void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse)
{ {
si32 power = VLC->spellh->spells[sse.sid]->powers[sse.val]; //TODO: get rid of this spaghetti code
const CSpell * sp = VLC->spellh->spells[sse.sid];
si32 power = sp->powers[sse.val];
auto add = [&](Bonus::BonusType type, si16 subtype, si32 value,si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
{
sf.push_back(featureGenerator(type, subtype, value, sse.turnsRemain,additionalInfo, limit));
sf.back().sid = sse.sid;
};
auto addVT = [&](Bonus::BonusType type, si16 subtype, si32 value, ui8 valType,si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
{
add(type, subtype, value, additionalInfo, limit);
sf.back().valType = valType;
};
auto addDur = [&](Bonus::BonusType type, si16 subtype, si32 value, ui8 duration ,si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
{
add(type, subtype, value, additionalInfo, limit);
sf.back().duration = duration;
};
switch(sse.sid) switch(sse.sid)
{ {
case 27: //shield case Spells::SHIELD:
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain)); add(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power);
sf.back().sid = sse.sid;
break; break;
case 28: //air shield case Spells::AIR_SHIELD:
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain)); add(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power);
sf.back().sid = sse.sid;
break; break;
case 29: //fire shield case Spells::FIRE_SHIELD:
sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain)); add(Bonus::FIRE_SHIELD, 0, power);
sf.back().sid = sse.sid;
break; break;
case 30: //protection from air case Spells::PROTECTION_FROM_AIR:
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain)); add(Bonus::SPELL_DAMAGE_REDUCTION, 0, power);
sf.back().sid = sse.sid;
break; break;
case 31: //protection from fire case Spells::PROTECTION_FROM_FIRE:
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain)); add(Bonus::SPELL_DAMAGE_REDUCTION, 1, power);
sf.back().sid = sse.sid;
break; break;
case 32: //protection from water case Spells::PROTECTION_FROM_WATER:
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain)); add(Bonus::SPELL_DAMAGE_REDUCTION, 2, power);
sf.back().sid = sse.sid;
break; break;
case 33: //protection from earth case Spells::PROTECTION_FROM_EARTH:
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain)); add(Bonus::SPELL_DAMAGE_REDUCTION, 3, power);
sf.back().sid = sse.sid;
break; break;
case 34: //anti-magic case Spells::ANTI_MAGIC:
sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, GameConstants::SPELL_LEVELS, power - 1, sse.turnsRemain)); addVT(Bonus::LEVEL_SPELL_IMMUNITY, GameConstants::SPELL_LEVELS, power - 1, Bonus::INDEPENDENT_MAX);break;
sf.back().valType = Bonus::INDEPENDENT_MAX; case Spells::MAGIC_MIRROR:
sf.back().sid = sse.sid; addVT(Bonus::MAGIC_MIRROR, -1, power,Bonus::INDEPENDENT_MAX);
break; break;
case 36: //magic mirror case Spells::BLESS:
sf.push_back(featureGenerator(Bonus::MAGIC_MIRROR, -1, power, sse.turnsRemain)); addVT(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power,Bonus::INDEPENDENT_MAX);
sf.back().valType = Bonus::INDEPENDENT_MAX;
sf.back().sid = sse.sid;
case 41: //bless
sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
sf.back().valType = Bonus::INDEPENDENT_MAX;
sf.back().sid = sse.sid;
break; break;
case 42: //curse case Spells::CURSE:
sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, power, sse.turnsRemain, sse.val >= 2 ? 20 : 0)); addVT(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, power, Bonus::INDEPENDENT_MAX, sse.val >= 2 ? 20 : 0);
sf.back().valType = Bonus::INDEPENDENT_MAX;
sf.back().sid = sse.sid;
break; break;
case 43: //bloodlust case Spells::BLOODLUST:
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT)); add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, 0, Bonus::ONLY_MELEE_FIGHT);
sf.back().sid = sse.sid;
break; break;
case 44: //precision case Spells::PRECISION:
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT)); add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, 0, Bonus::ONLY_DISTANCE_FIGHT);
sf.back().sid = sse.sid;
break; break;
case 45: //weakness case Spells::WEAKNESS:
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain)); add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power);
sf.back().sid = sse.sid;
break; break;
case 46: //stone skin case Spells::STONE_SKIN:
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain)); add(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power);
sf.back().sid = sse.sid;
break; break;
case 47: //disrupting ray case Spells::DISRUPTING_RAY:
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain)); addVT(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power,Bonus::ADDITIVE_VALUE);
sf.back().sid = sse.sid;
sf.back().valType = Bonus::ADDITIVE_VALUE;
break; break;
case 48: //prayer case Spells::PRAYER:
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain)); add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power);
sf.back().sid = sse.sid; add(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power);
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain)); add(Bonus::STACKS_SPEED, 0, power);
sf.back().sid = sse.sid;
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
sf.back().sid = sse.sid;
break; break;
case 49: //mirth case Spells::MIRTH:
sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain)); add(Bonus::MORALE, 0, power);
sf.back().sid = sse.sid;
break; break;
case 50: //sorrow case Spells::SORROW:
sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain)); add(Bonus::MORALE, 0, -1 * power);
sf.back().sid = sse.sid;
break; break;
case 51: //fortune case Spells::FORTUNE:
sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain)); add(Bonus::LUCK, 0, power);
sf.back().sid = sse.sid;
break; break;
case 52: //misfortune case Spells::MISFORTUNE:
sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain)); add(Bonus::LUCK, 0, -1 * power);
sf.back().sid = sse.sid;
break; break;
case 53: //haste case Spells::HASTE: //haste
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain)); add(Bonus::STACKS_SPEED, 0, power);
sf.back().sid = sse.sid;
break; break;
case 54: //slow case Spells::SLOW:
sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL)); addVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ),Bonus::PERCENT_TO_ALL);
sf.back().sid = sse.sid;
break; break;
case 55: //slayer case Spells::SLAYER:
sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.val, sse.turnsRemain)); add(Bonus::SLAYER, 0, sse.val);
sf.back().sid = sse.sid;
break; break;
case 56: //frenzy case Spells::FRENZY:
sf.push_back(featureGenerator(Bonus::IN_FRENZY, 0, VLC->spellh->spells[56]->powers[sse.val]/100.0, sse.turnsRemain)); add(Bonus::IN_FRENZY, 0, power/100.0);
sf.back().sid = sse.sid;
break; break;
case 58: //counterstrike case Spells::COUNTERSTRIKE:
sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain)); add(Bonus::ADDITIONAL_RETALIATION, 0, power);
sf.back().sid = sse.sid;
break; break;
case 59: //bersek case Spells::BERSERK:
sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val, sse.turnsRemain)); add(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val);
sf.back().sid = sse.sid;
break; break;
case 60: //hypnotize case Spells::HYPNOTIZE:
sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.val, sse.turnsRemain)); add(Bonus::HYPNOTIZED, 0, sse.val);
sf.back().sid = sse.sid;
break; break;
case 61: //forgetfulness case Spells::FORGETFULNESS:
sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.val, sse.turnsRemain)); add(Bonus::FORGETFULL, 0, sse.val);
sf.back().sid = sse.sid;
break; break;
case Spells::BLIND: //blind case Spells::BLIND:
sf.push_back(makeFeatureVal(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, sse.sid, 0, Bonus::SPELL_EFFECT, sse.turnsRemain)); addDur(Bonus::NOT_ACTIVE, sse.sid, 0, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS);
sf.back().sid = sse.sid; addDur(Bonus::GENERAL_ATTACK_REDUCTION, 0, power, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS);
sf.push_back(makeFeatureVal(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain)); addDur(Bonus::NO_RETALIATION,0,0, Bonus::UNITL_BEING_ATTACKED);
sf.back().sid = sse.sid;
sf.push_back(makeFeatureVal(Bonus::NO_RETALIATION, Bonus::UNITL_BEING_ATTACKED, 0, 0, Bonus::SPELL_EFFECT, 0)); // don't retaliate after basilisk / unicorn attack
sf.back().sid = sse.sid;
break; break;
case Spells::STONE_GAZE: //Stone Gaze case Spells::STONE_GAZE:
case Spells::PARALYZE: //Paralyze case Spells::PARALYZE:
sf.push_back(makeFeatureVal(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, sse.sid, 0, Bonus::SPELL_EFFECT, sse.turnsRemain)); addDur(Bonus::NOT_ACTIVE, sse.sid, 0, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS);
sf.back().sid = sse.sid; addDur(Bonus::NO_RETALIATION,0,0, Bonus::UNITL_BEING_ATTACKED);
sf.push_back(makeFeatureVal(Bonus::NO_RETALIATION, Bonus::UNITL_BEING_ATTACKED, 0, 0, Bonus::SPELL_EFFECT, 0)); // don't retaliate after basilisk / unicorn attack
sf.back().sid = sse.sid;
break; break;
case 71: //Poison case Spells::POISON: //Poison
sf.push_back(featureGeneratorVT(Bonus::POISON, 0, 30, sse.turnsRemain, Bonus::INDEPENDENT_MAX)); //max hp penalty from this source addVT(Bonus::POISON, 0, 30,Bonus::INDEPENDENT_MAX); //max hp penalty from this source
sf.back().sid = sse.sid; addVT(Bonus::STACK_HEALTH, 0, -10, Bonus::PERCENT_TO_ALL);
sf.push_back(featureGeneratorVT(Bonus::STACK_HEALTH, 0, -10, sse.turnsRemain, Bonus::PERCENT_TO_ALL));
sf.back().sid = sse.sid;
break; break;
case 72: //Bind case Spells::BIND:
sf.push_back(featureGenerator(Bonus::BIND_EFFECT, 0, 0, 1)); //marker sf.push_back(featureGenerator(Bonus::BIND_EFFECT, 0, 0, 1)); //marker
sf.back().duration = Bonus::PERMANENT; sf.back().duration = Bonus::PERMANENT;
sf.back().sid = sse.sid; sf.back().sid = sse.sid;
break; break;
case 73: //Disease case Spells::DISEASE:
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -2 , sse.turnsRemain)); add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -2);
sf.back().sid = sse.sid; add(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -2);
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -2 , sse.turnsRemain));
sf.back().sid = sse.sid;
break; break;
case 75: //Age case Spells::AGE:
sf.push_back(featureGeneratorVT(Bonus::STACK_HEALTH, 0, -50, sse.turnsRemain, Bonus::PERCENT_TO_ALL)); addVT(Bonus::STACK_HEALTH, 0, -50, Bonus::PERCENT_TO_ALL);
sf.back().sid = sse.sid;
break; break;
case 80: //Acid Breath case Spells::ACID_BREATH_DEFENSE:
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -sse.turnsRemain, 1)); sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -sse.turnsRemain, 1));
sf.back().sid = sse.sid; sf.back().sid = sse.sid;
sf.back().duration = Bonus::PERMANENT; sf.back().duration = Bonus::PERMANENT;

View File

@ -179,7 +179,6 @@ public:
{ {
Bonus hb = makeFeatureVal(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo); Bonus hb = makeFeatureVal(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo);
hb.effectRange = limit; hb.effectRange = limit;
hb.source = Bonus::SPELL_EFFECT;
return hb; return hb;
} }
@ -187,7 +186,6 @@ public:
{ {
Bonus ret = makeFeatureVal(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain); Bonus ret = makeFeatureVal(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain);
ret.valType = valType; ret.valType = valType;
ret.source = Bonus::SPELL_EFFECT;
return ret; return ret;
} }

View File

@ -1591,7 +1591,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleIsImmune(const C
if (battleTestElementalImmunity(Bonus::AIR_IMMUNITY)) if (battleTestElementalImmunity(Bonus::AIR_IMMUNITY))
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
} }
if (vstd::contains(VLC->spellh->mindSpells, spell->id)) if (spell->isMindSpell())
{ {
if (subject->hasBonusOfType(Bonus::MIND_IMMUNITY)) if (subject->hasBonusOfType(Bonus::MIND_IMMUNITY))
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
@ -1909,7 +1909,7 @@ ui32 CBattleInfoCallback::calculateSpellDmg( const CSpell * sp, const CGHeroInst
ui32 ret = 0; //value to return ui32 ret = 0; //value to return
//check if spell really does damage - if not, return 0 //check if spell really does damage - if not, return 0
if(VLC->spellh->damageSpells.find(sp->id) == VLC->spellh->damageSpells.end()) if(!sp->isDamageSpell())
return 0; return 0;
ret = usedSpellPower * sp->power; ret = usedSpellPower * sp->power;

View File

@ -1963,7 +1963,7 @@ std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const
{ {
if(obj->blockVisit) if(obj->blockVisit)
{ {
if (obj->ID == 54) // Monster if (obj->ID == Obj::MONSTER) // Monster
guards.push_back(obj); guards.push_back(obj);
} }
} }
@ -1976,11 +1976,11 @@ std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const
if (map->isInTheMap(pos)) if (map->isInTheMap(pos))
{ {
TerrainTile &tile = map->terrain[pos.x][pos.y][pos.z]; TerrainTile &tile = map->terrain[pos.x][pos.y][pos.z];
if (tile.visitable && (tile.terType == ETerrainType::WATER) == (posTile.terType == ETerrainType::WATER)) if (tile.visitable && (tile.isWater() == posTile.isWater()))
{ {
BOOST_FOREACH (CGObjectInstance* obj, tile.visitableObjects) BOOST_FOREACH (CGObjectInstance* obj, tile.visitableObjects)
{ {
if (obj->ID == 54 && checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile if (obj->ID == Obj::MONSTER && checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile
{ {
guards.push_back(obj); guards.push_back(obj);
} }
@ -2010,7 +2010,7 @@ int3 CGameState::guardingCreaturePosition (int3 pos) const
{ {
if(obj->blockVisit) if(obj->blockVisit)
{ {
if (obj->ID == 54) // Monster if (obj->ID == Obj::MONSTER) // Monster
return pos; return pos;
else else
return int3(-1, -1, -1); //blockvis objects are not guarded by neighbouring creatures return int3(-1, -1, -1); //blockvis objects are not guarded by neighbouring creatures
@ -2027,11 +2027,11 @@ int3 CGameState::guardingCreaturePosition (int3 pos) const
if (map->isInTheMap(pos)) if (map->isInTheMap(pos))
{ {
TerrainTile &tile = map->terrain[pos.x][pos.y][pos.z]; TerrainTile &tile = map->terrain[pos.x][pos.y][pos.z];
if (tile.visitable && (tile.terType == ETerrainType::WATER) == (posTile.terType == ETerrainType::WATER)) if (tile.visitable && (tile.isWater() == posTile.isWater()))
{ {
BOOST_FOREACH (CGObjectInstance* obj, tile.visitableObjects) BOOST_FOREACH (CGObjectInstance* obj, tile.visitableObjects)
{ {
if (obj->ID == 54 && checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile if (obj->ID == Obj::MONSTER && checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile
{ {
return pos; return pos;
} }
@ -2429,7 +2429,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
} }
if(level >= 4) //obelisks found if(level >= 4) //obelisks found
{ {
//TODO //TODO: obtainPlayersStats - obelisks found
} }
if(level >= 5) //artifacts if(level >= 5) //artifacts
{ {
@ -2441,7 +2441,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
} }
if(level >= 7) //income if(level >= 7) //income
{ {
//TODO //TODO:obtainPlayersStats - income
} }
if(level >= 8) //best hero's stats if(level >= 8) //best hero's stats
{ {
@ -2507,18 +2507,11 @@ int CGameState::lossCheck( ui8 player ) const
switch(map->lossCondition.typeOfLossCon) switch(map->lossCondition.typeOfLossCon)
{ {
case ELossConditionType::LOSSCASTLE: case ELossConditionType::LOSSCASTLE:
{
const CGTownInstance *t = dynamic_cast<const CGTownInstance *>(map->lossCondition.obj);
assert(t);
if(t->tempOwner != player)
return 1;
}
break;
case ELossConditionType::LOSSHERO: case ELossConditionType::LOSSHERO:
{ {
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(map->lossCondition.obj); const CGObjectInstance *obj = map->lossCondition.obj;
assert(h); assert(obj);
if(h->tempOwner != player) if(obj->tempOwner != player)
return 1; return 1;
} }
break; break;
@ -3177,13 +3170,6 @@ bool CPathfinder::canMoveBetween(const int3 &a, const int3 &b) const
return gs->checkForVisitableDir(a, b) && gs->checkForVisitableDir(b, a); return gs->checkForVisitableDir(a, b) && gs->checkForVisitableDir(b, a);
} }
bool CPathfinder::canStepOntoDst() const
{
//TODO remove
assert(0);
return false;
}
CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const TerrainTile *tinfo) const CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const TerrainTile *tinfo) const
{ {
CGPathNode::EAccessibility ret = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE); CGPathNode::EAccessibility ret = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE);
@ -3194,7 +3180,7 @@ CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const TerrainTile
if(tinfo->visitable) if(tinfo->visitable)
{ {
if(tinfo->visitableObjects.front()->ID == 80 && tinfo->visitableObjects.back()->ID == Obj::HERO && tinfo->visitableObjects.back()->tempOwner != hero->tempOwner) //non-owned hero stands on Sanctuary if(tinfo->visitableObjects.front()->ID == Obj::SANCTUARY && tinfo->visitableObjects.back()->ID == Obj::HERO && tinfo->visitableObjects.back()->tempOwner != hero->tempOwner) //non-owned hero stands on Sanctuary
{ {
return CGPathNode::BLOCKED; return CGPathNode::BLOCKED;
} }

View File

@ -368,7 +368,6 @@ private:
CGPathNode::EAccessibility evaluateAccessibility(const TerrainTile *tinfo) const; CGPathNode::EAccessibility evaluateAccessibility(const TerrainTile *tinfo) const;
bool canMoveBetween(const int3 &a, const int3 &b) const; //checks only for visitable objects that may make moving between tiles impossible, not other conditions (like tiles itself accessibility) bool canMoveBetween(const int3 &a, const int3 &b) const; //checks only for visitable objects that may make moving between tiles impossible, not other conditions (like tiles itself accessibility)
bool canStepOntoDst() const;
public: public:
CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance *_hero); CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance *_hero);

View File

@ -292,6 +292,7 @@ void CModHandler::loadActiveMods()
handleData(VLC->townh, config["factions"]); handleData(VLC->townh, config["factions"]);
handleData(VLC->creh, config["creatures"]); handleData(VLC->creh, config["creatures"]);
handleData(VLC->arth, config["artifacts"]); handleData(VLC->arth, config["artifacts"]);
//todo: spells
handleData(&VLC->heroh->classes, config["heroClasses"]); handleData(&VLC->heroh->classes, config["heroClasses"]);
handleData(VLC->heroh, config["heroes"]); handleData(VLC->heroh, config["heroes"]);

View File

@ -1384,13 +1384,12 @@ void CGHeroInstance::showNecromancyDialog(const CStackBasicDescriptor &raisedSta
{ {
iw.text.addTxt(MetaString::GENERAL_TXT, 145); iw.text.addTxt(MetaString::GENERAL_TXT, 145);
iw.text.addReplacement(raisedStack.count); iw.text.addReplacement(raisedStack.count);
iw.text.addReplacement(MetaString::CRE_PL_NAMES, raisedStack.type->idNumber);
} }
else // Practicing the dark arts of necromancy, ... (singular) else // Practicing the dark arts of necromancy, ... (singular)
{ {
iw.text.addTxt(MetaString::GENERAL_TXT, 146); iw.text.addTxt(MetaString::GENERAL_TXT, 146);
iw.text.addReplacement(MetaString::CRE_SING_NAMES, raisedStack.type->idNumber);
} }
iw.text.addReplacement(raisedStack);
cb->showInfoDialog(&iw); cb->showInfoDialog(&iw);
} }
@ -4772,7 +4771,7 @@ void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const
const std::string & CGWitchHut::getHoverText() const const std::string & CGWitchHut::getHoverText() const
{ {
hoverName = VLC->generaltexth->names[ID]; hoverName = VLC->generaltexth->names[ID];
if(wasVisited(cb->getCurrentPlayer())) //TODO: use local player, not current if(wasVisited(cb->getLocalPlayer()))
{ {
hoverName += "\n" + VLC->generaltexth->allTexts[356]; // + (learn %s) hoverName += "\n" + VLC->generaltexth->allTexts[356]; // + (learn %s)
boost::algorithm::replace_first(hoverName,"%s",VLC->generaltexth->skillName[ability]); boost::algorithm::replace_first(hoverName,"%s",VLC->generaltexth->skillName[ability]);
@ -6113,14 +6112,12 @@ void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) cons
//display loot //display loot
if (!iw.components.empty()) if (!iw.components.empty())
{ {
iw.text.addTxt (MetaString::ADVOB_TXT, textID);
if (textID == 34) if (textID == 34)
{ {
iw.text.addTxt(MetaString::ADVOB_TXT, 34);//Heaving defeated %s, you discover %s
iw.text.addReplacement(MetaString::CRE_PL_NAMES, result->casualties[1].begin()->first); iw.text.addReplacement(MetaString::CRE_PL_NAMES, result->casualties[1].begin()->first);
iw.text.addReplacement(loot.buildList()); iw.text.addReplacement(loot.buildList());
} }
else
iw.text.addTxt (MetaString::ADVOB_TXT, textID);
cb->showInfoDialog(&iw); cb->showInfoDialog(&iw);
} }
loot.clear(); loot.clear();

View File

@ -167,7 +167,7 @@ public:
mutable std::string hoverName; mutable std::string hoverName;
int3 pos; //h3m pos int3 pos; //h3m pos
si32 ID, subID; //normal ID (this one from OH3 maps ;]) - eg. town=98; hero=34 si32 ID, subID; //normal ID (this one from OH3 maps ;]) - eg. town=98; hero=34
si32 id;//number of object in CObjectHandler's vector si32 id;//number of object in map's vector
CGDefInfo * defInfo; CGDefInfo * defInfo;
ui8 animPhaseShift; ui8 animPhaseShift;

View File

@ -122,11 +122,19 @@ namespace SRSLPraserHelpers
return ret; return ret;
} }
} }
using namespace SRSLPraserHelpers; using namespace SRSLPraserHelpers;
CSpellHandler::CSpellHandler() CSpellHandler::CSpellHandler()
{ {
VLC->spellh = this;
} }
CSpell::CSpell()
{
_isDamage = false;
_isMind = false;
_isRising = false;
}
std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const
{ {
std::vector<BattleHex> ret; std::vector<BattleHex> ret;
@ -254,13 +262,30 @@ bool CSpell::isNegative() const
bool CSpell::isRisingSpell() const bool CSpell::isRisingSpell() const
{ {
return vstd::contains(VLC->spellh->risingSpells, id); return _isRising;
} }
bool CSpell::isDamageSpell() const bool CSpell::isDamageSpell() const
{ {
return vstd::contains(VLC->spellh->damageSpells, id); return _isDamage;
} }
bool CSpell::isMindSpell() const
{
return _isMind;
}
void CSpell::getEffects(std::vector<Bonus>& lst) const
{
lst.reserve(lst.size() + _effects.size());
BOOST_FOREACH (Bonus b, _effects)
{
lst.push_back(b);
}
}
bool DLL_LINKAGE isInScreenRange(const int3 &center, const int3 &pos) bool DLL_LINKAGE isInScreenRange(const int3 &center, const int3 &pos)
{ {
int3 diff = pos - center; int3 diff = pos - center;
@ -343,7 +368,10 @@ void CSpellHandler::loadSpells()
} }
while (parser.endLine() && !parser.isNextEntryEmpty()); while (parser.endLine() && !parser.isNextEntryEmpty());
boost::replace_first (spells[47]->attributes, "2", ""); // disrupting ray will now affect single creature boost::replace_first (spells[Spells::DISRUPTING_RAY]->attributes, "2", ""); // disrupting ray will now affect single creature
spells.push_back(spells[Spells::ACID_BREATH_DEFENSE]); //clone Acid Breath attributes for Acid Breath damage effect
//loading of additional spell traits //loading of additional spell traits
const JsonNode config(ResourceID("config/spell_info.json")); const JsonNode config(ResourceID("config/spell_info.json"));
@ -367,16 +395,50 @@ void CSpellHandler::loadSpells()
s->identifier = spell.first; s->identifier = spell.first;
VLC->modh->identifiers.registerObject("spell." + spell.first, spellID); VLC->modh->identifiers.registerObject("spell." + spell.first, spellID);
const JsonNode & flags_node = spell.second["flags"];
if (!flags_node.isNull())
{
auto flags = flags_node.convertTo<std::vector<std::string> >();
BOOST_FOREACH (const auto & flag, flags)
{
if (flag == "damage")
{
s->_isDamage = true;
} }
else if (flag == "rising")
{
s->_isRising = true;
}
else if (flag == "mind")
{
s->_isMind = true;
}
}
}
const JsonNode & effects_node = spell.second["effects"];
if (!effects_node.isNull())
{
BOOST_FOREACH (const JsonNode & bonus_node, effects_node.Vector())
{
Bonus * b = JsonUtils::parseBonus(bonus_node);
b->sid = s->id;
b->source = Bonus::SPELL_EFFECT;
b->duration = Bonus::N_TURNS; //default
//TODO: make duration configurable
s->_effects.push_back(*b);
}
}
}
//spell fixes //spell fixes
spells.push_back(spells[80]); //clone Acid Breath attributes for Acid Breath damage effect
//forgetfulness needs to get targets automatically on expert level //forgetfulness needs to get targets automatically on expert level
boost::replace_first(spells[61]->attributes, "CREATURE_TARGET", "CREATURE_TARGET_2"); //TODO: use flags instead? boost::replace_first(spells[Spells::FORGETFULNESS]->attributes, "CREATURE_TARGET", "CREATURE_TARGET_2"); //TODO: use flags instead?
damageSpells += 11, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 57, 77;
risingSpells += 38, 39, 40;
mindSpells += 50, 59, 60, 61, 62;
} }
std::vector<ui8> CSpellHandler::getDefaultAllowedSpells() const std::vector<ui8> CSpellHandler::getDefaultAllowedSpells() const

View File

@ -3,6 +3,7 @@
#include "../lib/ConstTransitivePtr.h" #include "../lib/ConstTransitivePtr.h"
#include "int3.h" #include "int3.h"
#include "GameConstants.h" #include "GameConstants.h"
#include "HeroBonus.h"
/* /*
* CSpellHandler.h, part of VCMI engine * CSpellHandler.h, part of VCMI engine
@ -44,20 +45,38 @@ public:
std::vector<std::string> range; //description of spell's range in SRSL by magic school level std::vector<std::string> range; //description of spell's range in SRSL by magic school level
std::vector<TSpell> counteredSpells; //spells that are removed when effect of this spell is placed on creature (for bless-curse, haste-slow, and similar pairs) std::vector<TSpell> counteredSpells; //spells that are removed when effect of this spell is placed on creature (for bless-curse, haste-slow, and similar pairs)
CSpell();
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = NULL ) const; //convert range to specific hexes; last optional out parameter is set to true, if spell would cover unavailable hexes (that are not included in ret) std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = NULL ) const; //convert range to specific hexes; last optional out parameter is set to true, if spell would cover unavailable hexes (that are not included in ret)
si16 mainEffectAnim; //main spell effect animation, in AC format (or -1 when none) si16 mainEffectAnim; //main spell effect animation, in AC format (or -1 when none)
ETargetType getTargetType() const; ETargetType getTargetType() const;
bool isPositive() const; bool isPositive() const;
bool isNegative() const; bool isNegative() const;
bool isRisingSpell() const; bool isRisingSpell() const;
bool isDamageSpell() const; bool isDamageSpell() const;
bool isMindSpell() const;
void getEffects(std::vector<Bonus> & lst) const;
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & identifier & id & name & abbName & descriptions & level & earth & water & fire & air & power & costs h & identifier & id & name & abbName & descriptions & level & earth & water & fire & air & power & costs
& powers & probabilities & AIVals & attributes & combatSpell & creatureAbility & positiveness & range & counteredSpells & mainEffectAnim; & powers & probabilities & AIVals & attributes & combatSpell & creatureAbility & positiveness & range & counteredSpells & mainEffectAnim;
h & _isRising & _isDamage & _isMind;
h & _effects;
} }
friend class CSpellHandler;
private:
bool _isRising;
bool _isDamage;
bool _isMind;
std::vector<Bonus> _effects;
}; };
namespace Spells namespace Spells
@ -96,9 +115,7 @@ class DLL_LINKAGE CSpellHandler
public: public:
CSpellHandler(); CSpellHandler();
std::vector< ConstTransitivePtr<CSpell> > spells; std::vector< ConstTransitivePtr<CSpell> > spells;
std::set<TSpell> damageSpells; //they inflict damage and require particular threatment
std::set<TSpell> risingSpells; //they affect dead stacks and need special target selection
std::set<TSpell> mindSpells;
void loadSpells(); void loadSpells();
/** /**
@ -110,6 +127,6 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & spells & damageSpells & risingSpells & mindSpells; h & spells ;
} }
}; };

View File

@ -955,7 +955,7 @@ void CMapLoaderH3M::readDefInfo()
defInfo->visitMap[zi] = reverse(bytes[6 + zi]); defInfo->visitMap[zi] = reverse(bytes[6 + zi]);
} }
pos += 16; pos += 16;
if(defInfo->id != Obj::HERO && defInfo->id != 70) if(defInfo->id != Obj::HERO && defInfo->id != Obj::RANDOM_HERO)
{ {
CGDefInfo * h = VLC->dobjinfo->gobjs[defInfo->id][defInfo->subid]; CGDefInfo * h = VLC->dobjinfo->gobjs[defInfo->id][defInfo->subid];
if(!h) if(!h)
@ -1160,11 +1160,22 @@ void CMapLoaderH3M::readObjects()
case Obj::FLOTSAM: case Obj::FLOTSAM:
case Obj::SEA_CHEST: case Obj::SEA_CHEST:
case Obj::SHIPWRECK_SURVIVOR: case Obj::SHIPWRECK_SURVIVOR:
case Obj::TREASURE_CHEST:
{ {
nobj = new CGPickable(); nobj = new CGPickable();
break; break;
} }
case Obj::TREASURE_CHEST:
if(defInfo->subid == 0)
{
nobj = new CGPickable();
}
else
{
//WoG pickable object
//TODO: possible special handling
nobj = new CGObjectInstance();
}
break;
case Obj::MONSTER: //Monster case Obj::MONSTER: //Monster
case Obj::RANDOM_MONSTER: case Obj::RANDOM_MONSTER:
case Obj::RANDOM_MONSTER_L1: case Obj::RANDOM_MONSTER_L1:

View File

@ -4376,7 +4376,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
{ {
BattleStackAttacked bsa; BattleStackAttacked bsa;
bsa.flags |= BattleStackAttacked::EFFECT; bsa.flags |= BattleStackAttacked::EFFECT;
bsa.effect = VLC->spellh->spells[80]->mainEffectAnim; //use acid breath bsa.effect = spell->mainEffectAnim;
bsa.damageAmount = usedSpellPower; //damage times the number of attackers bsa.damageAmount = usedSpellPower; //damage times the number of attackers
bsa.stackAttacked = (*it)->ID; bsa.stackAttacked = (*it)->ID;
bsa.attackerID = -1; bsa.attackerID = -1;