mirror of
https://github.com/vcmi/vcmi.git
synced 2025-04-04 22:14:25 +02:00
vcmi: setup moats using MoatAbility
Setup moats using moat ability, need playtest for now. -3 to defence not added for now.
This commit is contained in:
parent
6c5f5dba75
commit
aab5b47038
@ -147,8 +147,7 @@
|
|||||||
"horde" : [ 2, -1 ],
|
"horde" : [ 2, -1 ],
|
||||||
"mageGuild" : 4,
|
"mageGuild" : 4,
|
||||||
"warMachine" : "ballista",
|
"warMachine" : "ballista",
|
||||||
"moatDamage" : 70,
|
"moatAbility" : "core:spell.castleMoat",
|
||||||
"moatHexes" : [ 11, 28, 44, 61, 77, 111, 129, 146, 164, 181 ],
|
|
||||||
// primaryResource not specified so town get both Wood and Ore for resource bonus
|
// primaryResource not specified so town get both Wood and Ore for resource bonus
|
||||||
|
|
||||||
"buildings" :
|
"buildings" :
|
||||||
|
@ -152,8 +152,7 @@
|
|||||||
"mageGuild" : 5,
|
"mageGuild" : 5,
|
||||||
"primaryResource" : "mercury",
|
"primaryResource" : "mercury",
|
||||||
"warMachine" : "ballista",
|
"warMachine" : "ballista",
|
||||||
"moatDamage" : 70,
|
"moatAbility" : "core:spell.castleMoat",
|
||||||
"moatHexes" : [ 11, 28, 44, 61, 77, 111, 129, 146, 164, 181 ],
|
|
||||||
|
|
||||||
"buildings" :
|
"buildings" :
|
||||||
{
|
{
|
||||||
|
@ -148,8 +148,8 @@
|
|||||||
"mageGuild" : 5,
|
"mageGuild" : 5,
|
||||||
"primaryResource" : "sulfur",
|
"primaryResource" : "sulfur",
|
||||||
"warMachine" : "ballista",
|
"warMachine" : "ballista",
|
||||||
"moatDamage" : 90,
|
"moatAbility" : "core:spell.dungeonMoat",
|
||||||
"moatHexes" : [ 11, 28, 44, 61, 77, 111, 129, 146, 164, 181 ],
|
|
||||||
|
|
||||||
"buildings" :
|
"buildings" :
|
||||||
{
|
{
|
||||||
|
@ -147,8 +147,7 @@
|
|||||||
"horde" : [ 0, -1 ],
|
"horde" : [ 0, -1 ],
|
||||||
"mageGuild" : 3,
|
"mageGuild" : 3,
|
||||||
"warMachine" : "firstAidTent",
|
"warMachine" : "firstAidTent",
|
||||||
"moatDamage" : 90,
|
"moatAbility" : "core:spell.fortressMoat",
|
||||||
"moatHexes" : [ 10, 11, 27, 28, 43, 44, 60, 61, 76, 77, 94, 110, 111, 128, 129, 145, 146, 163, 164, 180, 181 ],
|
|
||||||
// primaryResource not specified so town get both Wood and Ore for resource bonus
|
// primaryResource not specified so town get both Wood and Ore for resource bonus
|
||||||
|
|
||||||
"buildings" :
|
"buildings" :
|
||||||
|
@ -149,8 +149,7 @@
|
|||||||
"mageGuild" : 5,
|
"mageGuild" : 5,
|
||||||
"primaryResource" : "mercury",
|
"primaryResource" : "mercury",
|
||||||
"warMachine" : "ammoCart",
|
"warMachine" : "ammoCart",
|
||||||
"moatDamage" : 90,
|
"moatAbility" : "core:spell.infernoMoat",
|
||||||
"moatHexes" : [ 11, 28, 44, 61, 77, 111, 129, 146, 164, 181 ],
|
|
||||||
|
|
||||||
"buildings" :
|
"buildings" :
|
||||||
{
|
{
|
||||||
|
@ -152,8 +152,7 @@
|
|||||||
"horde" : [ 0, -1 ],
|
"horde" : [ 0, -1 ],
|
||||||
"mageGuild" : 5,
|
"mageGuild" : 5,
|
||||||
"warMachine" : "firstAidTent",
|
"warMachine" : "firstAidTent",
|
||||||
"moatDamage" : 70,
|
"moatAbility" : "core:spell.necropolisMoat",
|
||||||
"moatHexes" : [ 11, 28, 44, 61, 77, 111, 129, 146, 164, 181 ],
|
|
||||||
// primaryResource not specified so town get both Wood and Ore for resource bonus
|
// primaryResource not specified so town get both Wood and Ore for resource bonus
|
||||||
|
|
||||||
"buildings" :
|
"buildings" :
|
||||||
|
@ -152,8 +152,7 @@
|
|||||||
"mageGuild" : 5,
|
"mageGuild" : 5,
|
||||||
"primaryResource" : "crystal",
|
"primaryResource" : "crystal",
|
||||||
"warMachine" : "firstAidTent",
|
"warMachine" : "firstAidTent",
|
||||||
"moatDamage" : 70,
|
"moatAbility" : "core:spell.rampartMoat",
|
||||||
"moatHexes" : [ 11, 28, 44, 61, 77, 111, 129, 146, 164, 181 ],
|
|
||||||
|
|
||||||
"buildings" :
|
"buildings" :
|
||||||
{
|
{
|
||||||
|
@ -145,8 +145,7 @@
|
|||||||
"horde" : [ 0, -1 ],
|
"horde" : [ 0, -1 ],
|
||||||
"mageGuild" : 3,
|
"mageGuild" : 3,
|
||||||
"warMachine" : "ammoCart",
|
"warMachine" : "ammoCart",
|
||||||
"moatDamage" : 70,
|
"moatAbility" : "core:spell.strongholdMoat",
|
||||||
"moatHexes" : [ 11, 28, 44, 61, 77, 111, 129, 146, 164, 181 ],
|
|
||||||
// primaryResource not specified so town get both Wood and Ore for resource bonus
|
// primaryResource not specified so town get both Wood and Ore for resource bonus
|
||||||
|
|
||||||
"buildings" :
|
"buildings" :
|
||||||
|
@ -147,8 +147,7 @@
|
|||||||
"primaryResource" : "gems",
|
"primaryResource" : "gems",
|
||||||
"mageGuild" : 5,
|
"mageGuild" : 5,
|
||||||
"warMachine" : "ammoCart",
|
"warMachine" : "ammoCart",
|
||||||
"moatDamage" : 0, //TODO: minefield
|
"moatAbility" : "core:spell.towerMoat",
|
||||||
"moatHexes" : [ 11, 28, 44, 61, 77, 111, 129, 146, 164, 181 ],
|
|
||||||
|
|
||||||
"buildings" :
|
"buildings" :
|
||||||
{
|
{
|
||||||
|
@ -80,6 +80,7 @@
|
|||||||
"config/spells/timed.json",
|
"config/spells/timed.json",
|
||||||
"config/spells/ability.json",
|
"config/spells/ability.json",
|
||||||
"config/spells/vcmiAbility.json"
|
"config/spells/vcmiAbility.json"
|
||||||
|
"config/spells/moats.json"
|
||||||
],
|
],
|
||||||
"skills" :
|
"skills" :
|
||||||
[
|
[
|
||||||
|
@ -109,7 +109,7 @@
|
|||||||
"additionalProperties" : false,
|
"additionalProperties" : false,
|
||||||
"required" : [
|
"required" : [
|
||||||
"mapObject", "buildingsIcons", "buildings", "creatures", "guildWindow", "names",
|
"mapObject", "buildingsIcons", "buildings", "creatures", "guildWindow", "names",
|
||||||
"hallBackground", "hallSlots", "horde", "mageGuild", "moatDamage", "defaultTavern", "tavernVideo", "guildBackground", "musicTheme", "siege", "structures", "townBackground", "warMachine"
|
"hallBackground", "hallSlots", "horde", "mageGuild", "moatAbility", "defaultTavern", "tavernVideo", "guildBackground", "musicTheme", "siege", "structures", "townBackground", "warMachine"
|
||||||
],
|
],
|
||||||
"description": "town",
|
"description": "town",
|
||||||
"properties":{
|
"properties":{
|
||||||
@ -230,14 +230,9 @@
|
|||||||
"type":"number",
|
"type":"number",
|
||||||
"description": "Maximal level of mage guild"
|
"description": "Maximal level of mage guild"
|
||||||
},
|
},
|
||||||
"moatDamage": {
|
"moatAbility": {
|
||||||
"type":"number",
|
"type":"string",
|
||||||
"description": "Damage dealt to creature that entered town moat during siege"
|
"description": "Identifier of ability to use as town moat during siege"
|
||||||
},
|
|
||||||
"moatHexes": {
|
|
||||||
"type" : "array",
|
|
||||||
"description" : "Numbers of battlefield hexes affected by moat during siege",
|
|
||||||
"items" : { "type" : "number" }
|
|
||||||
},
|
},
|
||||||
"musicTheme": {
|
"musicTheme": {
|
||||||
"type":"string",
|
"type":"string",
|
||||||
|
677
config/spells/moats.json
Normal file
677
config/spells/moats.json
Normal file
@ -0,0 +1,677 @@
|
|||||||
|
{
|
||||||
|
"castleMoatTrigger" :
|
||||||
|
{
|
||||||
|
"targetType" : "CREATURE",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Moat",
|
||||||
|
"school": {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base": {
|
||||||
|
"power" : 0,
|
||||||
|
"range" : "0",
|
||||||
|
"description" : "", //For validation
|
||||||
|
"cost" : 0, //For validation
|
||||||
|
"aiValue" : 0, //For validation
|
||||||
|
"battleEffects" : {
|
||||||
|
"directDamage" : {
|
||||||
|
"type":"core:damage"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targetModifier":{"smart":false}
|
||||||
|
},
|
||||||
|
"none" : {
|
||||||
|
},
|
||||||
|
"basic" : {
|
||||||
|
},
|
||||||
|
"advanced" : {
|
||||||
|
},
|
||||||
|
"expert" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"damage": true,
|
||||||
|
"negative": true,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"castleMoat": {
|
||||||
|
"targetType" : "NO_TARGET",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Moat",
|
||||||
|
"school" : {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"defaultGainChance": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base":{
|
||||||
|
"description" : "",
|
||||||
|
"aiValue" : 0,
|
||||||
|
"power" : 0,
|
||||||
|
"cost" : 0,
|
||||||
|
"targetModifier":{"smart":false},
|
||||||
|
"battleEffects":{
|
||||||
|
"moat":{
|
||||||
|
"type":"core:moat",
|
||||||
|
"hidden" : false,
|
||||||
|
"trap" : true,
|
||||||
|
"trigger" : true,
|
||||||
|
"triggerAbility" : "core:castleMoatTrigger",
|
||||||
|
"dispellable" : false,
|
||||||
|
"removeOnTrigger" : false,
|
||||||
|
"moatDamage" : 70,
|
||||||
|
"moatHexes" : [[11, 28, 44, 61, 77, 111, 129, 146, 164, 181]],
|
||||||
|
"defender" :{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"range" : "X"
|
||||||
|
},
|
||||||
|
"none" :{
|
||||||
|
},
|
||||||
|
"basic" :{
|
||||||
|
},
|
||||||
|
"advanced" :{
|
||||||
|
},
|
||||||
|
"expert" :{
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"indifferent": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
"nonMagical" : true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rampartMoatTrigger" :
|
||||||
|
{
|
||||||
|
"targetType" : "CREATURE",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Brambles",
|
||||||
|
"school": {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base": {
|
||||||
|
"power" : 0,
|
||||||
|
"range" : "0",
|
||||||
|
"description" : "", //For validation
|
||||||
|
"cost" : 0, //For validation
|
||||||
|
"aiValue" : 0, //For validation
|
||||||
|
"battleEffects" : {
|
||||||
|
"directDamage" : {
|
||||||
|
"type":"core:damage"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targetModifier":{"smart":false}
|
||||||
|
},
|
||||||
|
"none" : {
|
||||||
|
},
|
||||||
|
"basic" : {
|
||||||
|
},
|
||||||
|
"advanced" : {
|
||||||
|
},
|
||||||
|
"expert" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"damage": true,
|
||||||
|
"negative": true,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rampartMoat": {
|
||||||
|
"targetType" : "NO_TARGET",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Brambles",
|
||||||
|
"school" : {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"defaultGainChance": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base":{
|
||||||
|
"description" : "",
|
||||||
|
"aiValue" : 0,
|
||||||
|
"power" : 0,
|
||||||
|
"cost" : 0,
|
||||||
|
"targetModifier":{"smart":false},
|
||||||
|
"battleEffects":{
|
||||||
|
"moat":{
|
||||||
|
"type":"core:moat",
|
||||||
|
"hidden" : false,
|
||||||
|
"trap" : true,
|
||||||
|
"trigger" : true,
|
||||||
|
"triggerAbility" : "core:rampartMoatTrigger",
|
||||||
|
"dispellable" : false,
|
||||||
|
"removeOnTrigger" : false,
|
||||||
|
"moatDamage" : 70,
|
||||||
|
"moatHexes" : [[11, 28, 44, 61, 77, 111, 129, 146, 164, 181]],
|
||||||
|
"defender" :{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"range" : "X"
|
||||||
|
},
|
||||||
|
"none" :{
|
||||||
|
},
|
||||||
|
"basic" :{
|
||||||
|
},
|
||||||
|
"advanced" :{
|
||||||
|
},
|
||||||
|
"expert" :{
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"indifferent": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
"nonMagical" : true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"towerMoat": {
|
||||||
|
"targetType" : "NO_TARGET",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Land Mine",
|
||||||
|
"school" : {},
|
||||||
|
"level": 3,
|
||||||
|
"power": 0,
|
||||||
|
"defaultGainChance": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base":{
|
||||||
|
"description" : "",
|
||||||
|
"aiValue" : 0,
|
||||||
|
"power" : 0,
|
||||||
|
"cost" : 0,
|
||||||
|
"targetModifier":{"smart":false},
|
||||||
|
"battleEffects":{
|
||||||
|
"moat":{
|
||||||
|
"type":"core:moat",
|
||||||
|
"hidden" : true,
|
||||||
|
"trap" : false,
|
||||||
|
"trigger" : true,
|
||||||
|
"triggerAbility" : "core:landMineTrigger",
|
||||||
|
"dispellable" : true,
|
||||||
|
"removeOnTrigger" : true,
|
||||||
|
"moatDamage" : 150,
|
||||||
|
"moatHexes" : [[11], [28], [44], [61], [77], [111], [129], [146], [164], [181]],
|
||||||
|
"defender" :{
|
||||||
|
"animation" : "C09SPF1",
|
||||||
|
"appearAnimation" : "C09SPF0",
|
||||||
|
"appearSound" : "LANDMINE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"range" : "X"
|
||||||
|
},
|
||||||
|
"none" :{
|
||||||
|
},
|
||||||
|
"basic" :{
|
||||||
|
},
|
||||||
|
"advanced" :{
|
||||||
|
},
|
||||||
|
"expert" :{
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"indifferent": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
"nonMagical" : true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"infernoMoatTrigger" :
|
||||||
|
{
|
||||||
|
"targetType" : "CREATURE",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Lava",
|
||||||
|
"school": {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base": {
|
||||||
|
"power" : 0,
|
||||||
|
"range" : "0",
|
||||||
|
"description" : "", //For validation
|
||||||
|
"cost" : 0, //For validation
|
||||||
|
"aiValue" : 0, //For validation
|
||||||
|
"battleEffects" : {
|
||||||
|
"directDamage" : {
|
||||||
|
"type":"core:damage"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targetModifier":{"smart":false}
|
||||||
|
},
|
||||||
|
"none" : {
|
||||||
|
},
|
||||||
|
"basic" : {
|
||||||
|
},
|
||||||
|
"advanced" : {
|
||||||
|
},
|
||||||
|
"expert" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"damage": true,
|
||||||
|
"negative": true,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"infernoMoat": {
|
||||||
|
"targetType" : "NO_TARGET",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Lava",
|
||||||
|
"school" : {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"defaultGainChance": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base":{
|
||||||
|
"description" : "",
|
||||||
|
"aiValue" : 0,
|
||||||
|
"power" : 0,
|
||||||
|
"cost" : 0,
|
||||||
|
"targetModifier":{"smart":false},
|
||||||
|
"battleEffects":{
|
||||||
|
"moat":{
|
||||||
|
"type":"core:moat",
|
||||||
|
"hidden" : false,
|
||||||
|
"trap" : true,
|
||||||
|
"trigger" : true,
|
||||||
|
"triggerAbility" : "core:infernoMoatTrigger",
|
||||||
|
"dispellable" : false,
|
||||||
|
"removeOnTrigger" : false,
|
||||||
|
"moatDamage" : 90,
|
||||||
|
"moatHexes" : [[11, 28, 44, 61, 77, 111, 129, 146, 164, 181]],
|
||||||
|
"defender" :{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"range" : "X"
|
||||||
|
},
|
||||||
|
"none" :{
|
||||||
|
},
|
||||||
|
"basic" :{
|
||||||
|
},
|
||||||
|
"advanced" :{
|
||||||
|
},
|
||||||
|
"expert" :{
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"indifferent": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
"nonMagical" : true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"necropolisMoatTrigger" :
|
||||||
|
{
|
||||||
|
"targetType" : "CREATURE",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Boneyard",
|
||||||
|
"school": {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base": {
|
||||||
|
"power" : 0,
|
||||||
|
"range" : "0",
|
||||||
|
"description" : "", //For validation
|
||||||
|
"cost" : 0, //For validation
|
||||||
|
"aiValue" : 0, //For validation
|
||||||
|
"battleEffects" : {
|
||||||
|
"directDamage" : {
|
||||||
|
"type":"core:damage"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targetModifier":{"smart":false}
|
||||||
|
},
|
||||||
|
"none" : {
|
||||||
|
},
|
||||||
|
"basic" : {
|
||||||
|
},
|
||||||
|
"advanced" : {
|
||||||
|
},
|
||||||
|
"expert" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"damage": true,
|
||||||
|
"negative": true,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"necropolisMoat": {
|
||||||
|
"targetType" : "NO_TARGET",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Boneyard",
|
||||||
|
"school" : {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"defaultGainChance": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base":{
|
||||||
|
"description" : "",
|
||||||
|
"aiValue" : 0,
|
||||||
|
"power" : 0,
|
||||||
|
"cost" : 0,
|
||||||
|
"targetModifier":{"smart":false},
|
||||||
|
"battleEffects":{
|
||||||
|
"moat":{
|
||||||
|
"type":"core:moat",
|
||||||
|
"hidden" : true,
|
||||||
|
"trap" : false,
|
||||||
|
"trigger" : true,
|
||||||
|
"triggerAbility" : "core:necropolisMoatTrigger",
|
||||||
|
"dispellable" : false,
|
||||||
|
"removeOnTrigger" : false,
|
||||||
|
"moatDamage" : 70,
|
||||||
|
"moatHexes" : [[11, 28, 44, 61, 77, 111, 129, 146, 164, 181]],
|
||||||
|
"defender" :{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"range" : "X"
|
||||||
|
},
|
||||||
|
"none" :{
|
||||||
|
},
|
||||||
|
"basic" :{
|
||||||
|
},
|
||||||
|
"advanced" :{
|
||||||
|
},
|
||||||
|
"expert" :{
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"indifferent": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
"nonMagical" : true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dungeonMoatTrigger" :
|
||||||
|
{
|
||||||
|
"targetType" : "CREATURE",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Boiling Oil",
|
||||||
|
"school": {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base": {
|
||||||
|
"power" : 0,
|
||||||
|
"range" : "0",
|
||||||
|
"description" : "", //For validation
|
||||||
|
"cost" : 0, //For validation
|
||||||
|
"aiValue" : 0, //For validation
|
||||||
|
"battleEffects" : {
|
||||||
|
"directDamage" : {
|
||||||
|
"type":"core:damage"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targetModifier":{"smart":false}
|
||||||
|
},
|
||||||
|
"none" : {
|
||||||
|
},
|
||||||
|
"basic" : {
|
||||||
|
},
|
||||||
|
"advanced" : {
|
||||||
|
},
|
||||||
|
"expert" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"damage": true,
|
||||||
|
"negative": true,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dungeonMoat": {
|
||||||
|
"targetType" : "NO_TARGET",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Boiling Oil",
|
||||||
|
"school" : {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"defaultGainChance": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base":{
|
||||||
|
"description" : "",
|
||||||
|
"aiValue" : 0,
|
||||||
|
"power" : 0,
|
||||||
|
"cost" : 0,
|
||||||
|
"targetModifier":{"smart":false},
|
||||||
|
"battleEffects":{
|
||||||
|
"moat":{
|
||||||
|
"type":"core:moat",
|
||||||
|
"hidden" : false,
|
||||||
|
"trap" : true,
|
||||||
|
"trigger" : true,
|
||||||
|
"triggerAbility" : "core:dungeonMoatTrigger",
|
||||||
|
"dispellable" : false,
|
||||||
|
"removeOnTrigger" : false,
|
||||||
|
"moatDamage" : 90,
|
||||||
|
"moatHexes" : [[11, 28, 44, 61, 77, 111, 129, 146, 164, 181]],
|
||||||
|
"defender" :{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"range" : "X"
|
||||||
|
},
|
||||||
|
"none" :{
|
||||||
|
},
|
||||||
|
"basic" :{
|
||||||
|
},
|
||||||
|
"advanced" :{
|
||||||
|
},
|
||||||
|
"expert" :{
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"indifferent": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
"nonMagical" : true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strongholdMoatTrigger" :
|
||||||
|
{
|
||||||
|
"targetType" : "CREATURE",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Wooden Spikes",
|
||||||
|
"school": {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base": {
|
||||||
|
"power" : 0,
|
||||||
|
"range" : "0",
|
||||||
|
"description" : "", //For validation
|
||||||
|
"cost" : 0, //For validation
|
||||||
|
"aiValue" : 0, //For validation
|
||||||
|
"battleEffects" : {
|
||||||
|
"directDamage" : {
|
||||||
|
"type":"core:damage"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targetModifier":{"smart":false}
|
||||||
|
},
|
||||||
|
"none" : {
|
||||||
|
},
|
||||||
|
"basic" : {
|
||||||
|
},
|
||||||
|
"advanced" : {
|
||||||
|
},
|
||||||
|
"expert" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"damage": true,
|
||||||
|
"negative": true,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strongholdMoat": {
|
||||||
|
"targetType" : "NO_TARGET",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Wooden Spikes",
|
||||||
|
"school" : {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"defaultGainChance": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base":{
|
||||||
|
"description" : "",
|
||||||
|
"aiValue" : 0,
|
||||||
|
"power" : 0,
|
||||||
|
"cost" : 0,
|
||||||
|
"targetModifier":{"smart":false},
|
||||||
|
"battleEffects":{
|
||||||
|
"moat":{
|
||||||
|
"type":"core:moat",
|
||||||
|
"hidden" : false,
|
||||||
|
"trap" : true,
|
||||||
|
"trigger" : true,
|
||||||
|
"triggerAbility" : "core:strongholdMoatTrigger",
|
||||||
|
"dispellable" : false,
|
||||||
|
"removeOnTrigger" : false,
|
||||||
|
"moatDamage" : 70,
|
||||||
|
"moatHexes" : [[11, 28, 44, 61, 77, 111, 129, 146, 164, 181]],
|
||||||
|
"defender" :{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"range" : "X"
|
||||||
|
},
|
||||||
|
"none" :{
|
||||||
|
},
|
||||||
|
"basic" :{
|
||||||
|
},
|
||||||
|
"advanced" :{
|
||||||
|
},
|
||||||
|
"expert" :{
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"indifferent": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
"nonMagical" : true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fortressMoatTrigger" :
|
||||||
|
{
|
||||||
|
"targetType" : "CREATURE",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Boiling Tar",
|
||||||
|
"school": {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base": {
|
||||||
|
"power" : 0,
|
||||||
|
"range" : "0",
|
||||||
|
"description" : "", //For validation
|
||||||
|
"cost" : 0, //For validation
|
||||||
|
"aiValue" : 0, //For validation
|
||||||
|
"battleEffects" : {
|
||||||
|
"directDamage" : {
|
||||||
|
"type":"core:damage"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targetModifier":{"smart":false}
|
||||||
|
},
|
||||||
|
"none" : {
|
||||||
|
},
|
||||||
|
"basic" : {
|
||||||
|
},
|
||||||
|
"advanced" : {
|
||||||
|
},
|
||||||
|
"expert" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"damage": true,
|
||||||
|
"negative": true,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fortressMoat": {
|
||||||
|
"targetType" : "NO_TARGET",
|
||||||
|
"type": "ability",
|
||||||
|
"name": "Boiling Tar",
|
||||||
|
"school" : {},
|
||||||
|
"level": 0,
|
||||||
|
"power": 0,
|
||||||
|
"defaultGainChance": 0,
|
||||||
|
"gainChance": {},
|
||||||
|
"levels" : {
|
||||||
|
"base":{
|
||||||
|
"description" : "",
|
||||||
|
"aiValue" : 0,
|
||||||
|
"power" : 0,
|
||||||
|
"cost" : 0,
|
||||||
|
"targetModifier":{"smart":false},
|
||||||
|
"battleEffects":{
|
||||||
|
"moat":{
|
||||||
|
"type":"core:moat",
|
||||||
|
"hidden" : false,
|
||||||
|
"trap" : true,
|
||||||
|
"trigger" : true,
|
||||||
|
"triggerAbility" : "core:fortressMoatTrigger",
|
||||||
|
"dispellable" : false,
|
||||||
|
"removeOnTrigger" : false,
|
||||||
|
"moatDamage" : 90,
|
||||||
|
"moatHexes" : [[10, 11, 27, 28, 43, 44, 60, 61, 76, 77, 94, 110, 111, 128, 129, 145, 146, 163, 164, 180, 181]],
|
||||||
|
"defender" :{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"range" : "X"
|
||||||
|
},
|
||||||
|
"none" :{
|
||||||
|
},
|
||||||
|
"basic" :{
|
||||||
|
},
|
||||||
|
"advanced" :{
|
||||||
|
},
|
||||||
|
"expert" :{
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flags" : {
|
||||||
|
"indifferent": true
|
||||||
|
},
|
||||||
|
"targetCondition" : {
|
||||||
|
"nonMagical" : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -173,7 +173,7 @@ void CFaction::serializeJson(JsonSerializeFormat & handler)
|
|||||||
|
|
||||||
|
|
||||||
CTown::CTown()
|
CTown::CTown()
|
||||||
: faction(nullptr), mageLevel(0), primaryRes(0), moatDamage(0), defaultTavernChance(0)
|
: faction(nullptr), mageLevel(0), primaryRes(0), moatAbility(SpellID::NONE), defaultTavernChance(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -882,9 +882,6 @@ void CTownHandler::loadTown(CTown * town, const JsonNode & source)
|
|||||||
|
|
||||||
warMachinesToLoad[town] = source["warMachine"];
|
warMachinesToLoad[town] = source["warMachine"];
|
||||||
|
|
||||||
town->moatDamage = static_cast<si32>(source["moatDamage"].Float());
|
|
||||||
town->moatHexes = source["moatHexes"].convertTo<std::vector<BattleHex> >();
|
|
||||||
|
|
||||||
town->mageLevel = static_cast<ui32>(source["mageGuild"].Float());
|
town->mageLevel = static_cast<ui32>(source["mageGuild"].Float());
|
||||||
|
|
||||||
town->namesCount = 0;
|
town->namesCount = 0;
|
||||||
@ -894,6 +891,11 @@ void CTownHandler::loadTown(CTown * town, const JsonNode & source)
|
|||||||
town->namesCount += 1;
|
town->namesCount += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VLC->modh->identifiers.requestIdentifier(source["moatAbility"], [=](si32 ability)
|
||||||
|
{
|
||||||
|
town->moatAbility = SpellID(ability);
|
||||||
|
});
|
||||||
|
|
||||||
// Horde building creature level
|
// Horde building creature level
|
||||||
for(const JsonNode &node : source["horde"].Vector())
|
for(const JsonNode &node : source["horde"].Vector())
|
||||||
town->hordeLvl[static_cast<int>(town->hordeLvl.size())] = static_cast<int>(node.Float());
|
town->hordeLvl[static_cast<int>(town->hordeLvl.size())] = static_cast<int>(node.Float());
|
||||||
|
@ -271,8 +271,7 @@ public:
|
|||||||
ui32 mageLevel; //max available mage guild level
|
ui32 mageLevel; //max available mage guild level
|
||||||
ui16 primaryRes;
|
ui16 primaryRes;
|
||||||
ArtifactID warMachine;
|
ArtifactID warMachine;
|
||||||
si32 moatDamage;
|
SpellID moatAbility;
|
||||||
std::vector<BattleHex> moatHexes;
|
|
||||||
// default chance for hero of specific class to appear in tavern, if field "tavern" was not set
|
// default chance for hero of specific class to appear in tavern, if field "tavern" was not set
|
||||||
// resulting chance = sqrt(town.chance * heroClass.chance)
|
// resulting chance = sqrt(town.chance * heroClass.chance)
|
||||||
ui32 defaultTavernChance;
|
ui32 defaultTavernChance;
|
||||||
@ -339,8 +338,7 @@ public:
|
|||||||
h & primaryRes;
|
h & primaryRes;
|
||||||
h & warMachine;
|
h & warMachine;
|
||||||
h & clientInfo;
|
h & clientInfo;
|
||||||
h & moatDamage;
|
h & moatAbility;
|
||||||
h & moatHexes;
|
|
||||||
h & defaultTavernChance;
|
h & defaultTavernChance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,12 +451,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
|||||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), 1, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_BOTTOM_TOWER);
|
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), 1, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_BOTTOM_TOWER);
|
||||||
}
|
}
|
||||||
|
|
||||||
//moat
|
//Moat generating is done on server
|
||||||
auto moat = std::make_shared<MoatObstacle>();
|
|
||||||
moat->ID = curB->town->subID;
|
|
||||||
moat->obstacleType = CObstacleInstance::MOAT;
|
|
||||||
moat->uniqueID = static_cast<si32>(curB->obstacles.size());
|
|
||||||
curB->obstacles.push_back(moat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stable_sort(stacks.begin(),stacks.end(),cmpst);
|
std::stable_sort(stacks.begin(),stacks.end(),cmpst);
|
||||||
|
@ -162,6 +162,7 @@ void SpellCreatedObstacle::serializeJson(JsonSerializeFormat & handler)
|
|||||||
handler.serializeInt("spellLevel", spellLevel);
|
handler.serializeInt("spellLevel", spellLevel);
|
||||||
handler.serializeInt("casterSide", casterSide);
|
handler.serializeInt("casterSide", casterSide);
|
||||||
handler.serializeInt("minimalDamage", minimalDamage);
|
handler.serializeInt("minimalDamage", minimalDamage);
|
||||||
|
handler.serializeInt("type", obstacleType);
|
||||||
|
|
||||||
handler.serializeBool("hidden", hidden);
|
handler.serializeBool("hidden", hidden);
|
||||||
handler.serializeBool("revealed", revealed);
|
handler.serializeBool("revealed", revealed);
|
||||||
@ -201,7 +202,7 @@ int SpellCreatedObstacle::getAnimationYOffset(int imageHeight) const
|
|||||||
{
|
{
|
||||||
int offset = imageHeight % 42;
|
int offset = imageHeight % 42;
|
||||||
|
|
||||||
if(obstacleType == CObstacleInstance::SPELL_CREATED)
|
if(obstacleType == CObstacleInstance::SPELL_CREATED || obstacleType == CObstacleInstance::MOAT)
|
||||||
{
|
{
|
||||||
offset += animationYOffset;
|
offset += animationYOffset;
|
||||||
}
|
}
|
||||||
|
@ -58,11 +58,6 @@ struct DLL_LINKAGE CObstacleInstance
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DLL_LINKAGE MoatObstacle : CObstacleInstance
|
|
||||||
{
|
|
||||||
std::vector<BattleHex> getAffectedTiles() const override; //for special effects (not blocking)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DLL_LINKAGE SpellCreatedObstacle : CObstacleInstance
|
struct DLL_LINKAGE SpellCreatedObstacle : CObstacleInstance
|
||||||
{
|
{
|
||||||
int32_t turnsRemaining;
|
int32_t turnsRemaining;
|
||||||
|
@ -203,7 +203,6 @@ void registerTypesMapObjects2(Serializer &s)
|
|||||||
s.template registerType<CArtifactInstance, CCombinedArtifactInstance>();
|
s.template registerType<CArtifactInstance, CCombinedArtifactInstance>();
|
||||||
|
|
||||||
//s.template registerType<CObstacleInstance>();
|
//s.template registerType<CObstacleInstance>();
|
||||||
s.template registerType<CObstacleInstance, MoatObstacle>();
|
|
||||||
s.template registerType<CObstacleInstance, SpellCreatedObstacle>();
|
s.template registerType<CObstacleInstance, SpellCreatedObstacle>();
|
||||||
}
|
}
|
||||||
template<typename Serializer>
|
template<typename Serializer>
|
||||||
|
@ -15,21 +15,12 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|||||||
namespace spells
|
namespace spells
|
||||||
{
|
{
|
||||||
|
|
||||||
ObstacleCasterProxy::ObstacleCasterProxy(PlayerColor owner_, const Caster * hero_, const SpellCreatedObstacle * obs_):
|
ObstacleCasterProxy::ObstacleCasterProxy(PlayerColor owner_, const Caster * hero_, const SpellCreatedObstacle & obs_):
|
||||||
ProxyCaster(hero_),
|
SilentCaster(owner_, hero_),
|
||||||
owner(std::move(owner_)),
|
obs(obs_)
|
||||||
obs(*obs_)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ObstacleCasterProxy::getCasterUnitId() const
|
|
||||||
{
|
|
||||||
if(actualCaster)
|
|
||||||
return actualCaster->getCasterUnitId();
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t ObstacleCasterProxy::getSpellSchoolLevel(const Spell * spell, int32_t * outSelectedSchool) const
|
int32_t ObstacleCasterProxy::getSpellSchoolLevel(const Spell * spell, int32_t * outSelectedSchool) const
|
||||||
{
|
{
|
||||||
return obs.spellLevel;
|
return obs.spellLevel;
|
||||||
@ -44,16 +35,8 @@ int64_t ObstacleCasterProxy::getSpellBonus(const Spell * spell, int64_t base, co
|
|||||||
{
|
{
|
||||||
if(actualCaster)
|
if(actualCaster)
|
||||||
return std::max<int64_t>(actualCaster->getSpellBonus(spell, base, affectedStack), obs.minimalDamage);
|
return std::max<int64_t>(actualCaster->getSpellBonus(spell, base, affectedStack), obs.minimalDamage);
|
||||||
else
|
|
||||||
return std::max<int64_t>(base, obs.minimalDamage);
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t ObstacleCasterProxy::getSpecificSpellBonus(const Spell * spell, int64_t base) const
|
return std::max<int64_t>(base, obs.minimalDamage);
|
||||||
{
|
|
||||||
if(actualCaster)
|
|
||||||
return actualCaster->getSpecificSpellBonus(spell, base);
|
|
||||||
else
|
|
||||||
return base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ObstacleCasterProxy::getEffectPower(const Spell * spell) const
|
int32_t ObstacleCasterProxy::getEffectPower(const Spell * spell) const
|
||||||
@ -74,25 +57,35 @@ int64_t ObstacleCasterProxy::getEffectValue(const Spell * spell) const
|
|||||||
return obs.minimalDamage;
|
return obs.minimalDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerColor ObstacleCasterProxy::getCasterOwner() const
|
SilentCaster::SilentCaster(PlayerColor owner_, const Caster * hero_):
|
||||||
|
ProxyCaster(hero_),
|
||||||
|
owner(std::move(owner_))
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SilentCaster::getCasterName(MetaString & text) const
|
||||||
|
{
|
||||||
|
logGlobal->error("Unexpected call to SilentCaster::getCasterName");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SilentCaster::getCastDescription(const Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const
|
||||||
|
{
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void SilentCaster::spendMana(ServerCallback * server, const int spellCost) const
|
||||||
|
{
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerColor SilentCaster::getCasterOwner() const
|
||||||
|
{
|
||||||
|
if(actualCaster)
|
||||||
|
return actualCaster->getCasterOwner();
|
||||||
|
|
||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObstacleCasterProxy::getCasterName(MetaString & text) const
|
|
||||||
{
|
|
||||||
logGlobal->error("Unexpected call to ObstacleCasterProxy::getCasterName");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObstacleCasterProxy::getCastDescription(const Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const
|
|
||||||
{
|
|
||||||
//do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObstacleCasterProxy::spendMana(ServerCallback * server, const int spellCost) const
|
|
||||||
{
|
|
||||||
//do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
@ -17,26 +17,32 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|||||||
namespace spells
|
namespace spells
|
||||||
{
|
{
|
||||||
|
|
||||||
class DLL_LINKAGE ObstacleCasterProxy : public ProxyCaster
|
class DLL_LINKAGE SilentCaster : public ProxyCaster
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
const PlayerColor owner;
|
||||||
public:
|
public:
|
||||||
ObstacleCasterProxy(PlayerColor owner_, const Caster * hero_, const SpellCreatedObstacle * obs_);
|
SilentCaster(PlayerColor owner_, const Caster * caster);
|
||||||
|
|
||||||
int32_t getCasterUnitId() const override;
|
|
||||||
int32_t getSpellSchoolLevel(const Spell * spell, int32_t * outSelectedSchool = nullptr) const override;
|
|
||||||
int32_t getEffectLevel(const Spell * spell) const override;
|
|
||||||
int64_t getSpellBonus(const Spell * spell, int64_t base, const battle::Unit * affectedStack) const override;
|
|
||||||
int64_t getSpecificSpellBonus(const Spell * spell, int64_t base) const override;
|
|
||||||
int32_t getEffectPower(const Spell * spell) const override;
|
|
||||||
int32_t getEnchantPower(const Spell * spell) const override;
|
|
||||||
int64_t getEffectValue(const Spell * spell) const override;
|
|
||||||
PlayerColor getCasterOwner() const override;
|
|
||||||
void getCasterName(MetaString & text) const override;
|
void getCasterName(MetaString & text) const override;
|
||||||
void getCastDescription(const Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const override;
|
void getCastDescription(const Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const override;
|
||||||
void spendMana(ServerCallback * server, const int spellCost) const override;
|
void spendMana(ServerCallback * server, const int spellCost) const override;
|
||||||
|
PlayerColor getCasterOwner() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DLL_LINKAGE ObstacleCasterProxy : public SilentCaster
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ObstacleCasterProxy(PlayerColor owner_, const Caster * hero_, const SpellCreatedObstacle & obs_);
|
||||||
|
|
||||||
|
int32_t getSpellSchoolLevel(const Spell * spell, int32_t * outSelectedSchool = nullptr) const override;
|
||||||
|
int32_t getEffectLevel(const Spell * spell) const override;
|
||||||
|
int64_t getSpellBonus(const Spell * spell, int64_t base, const battle::Unit * affectedStack) const override;
|
||||||
|
int32_t getEffectPower(const Spell * spell) const override;
|
||||||
|
int32_t getEnchantPower(const Spell * spell) const override;
|
||||||
|
int64_t getEffectValue(const Spell * spell) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const PlayerColor owner;
|
|
||||||
const SpellCreatedObstacle & obs;
|
const SpellCreatedObstacle & obs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,6 +31,23 @@ namespace effects
|
|||||||
|
|
||||||
VCMI_REGISTER_SPELL_EFFECT(Moat, EFFECT_NAME);
|
VCMI_REGISTER_SPELL_EFFECT(Moat, EFFECT_NAME);
|
||||||
|
|
||||||
|
static void serializeMoatHexes(JsonSerializeFormat & handler, const std::string & fieldName, std::vector<std::vector<BattleHex>> & moatHexes)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
JsonArraySerializer outer = handler.enterArray(fieldName);
|
||||||
|
outer.syncSize(moatHexes, JsonNode::JsonType::DATA_VECTOR);
|
||||||
|
|
||||||
|
for(size_t outerIndex = 0; outerIndex < outer.size(); outerIndex++)
|
||||||
|
{
|
||||||
|
JsonArraySerializer inner = outer.enterArray(outerIndex);
|
||||||
|
inner.syncSize(moatHexes.at(outerIndex), JsonNode::JsonType::DATA_INTEGER);
|
||||||
|
|
||||||
|
for(size_t innerIndex = 0; innerIndex < inner.size(); innerIndex++)
|
||||||
|
inner.serializeInt(innerIndex, moatHexes.at(outerIndex).at(innerIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Moat::serializeJsonEffect(JsonSerializeFormat & handler)
|
void Moat::serializeJsonEffect(JsonSerializeFormat & handler)
|
||||||
{
|
{
|
||||||
handler.serializeBool("hidden", hidden);
|
handler.serializeBool("hidden", hidden);
|
||||||
@ -39,14 +56,8 @@ void Moat::serializeJsonEffect(JsonSerializeFormat & handler)
|
|||||||
handler.serializeBool("removeOnTrigger", removeOnTrigger);
|
handler.serializeBool("removeOnTrigger", removeOnTrigger);
|
||||||
handler.serializeBool("dispellable", dispellable);
|
handler.serializeBool("dispellable", dispellable);
|
||||||
handler.serializeInt("moatDamage", moatDamage);
|
handler.serializeInt("moatDamage", moatDamage);
|
||||||
|
serializeMoatHexes(handler, "moatHexes", moatHexes);
|
||||||
handler.serializeId("triggerAbility", triggerAbility, SpellID::NONE);
|
handler.serializeId("triggerAbility", triggerAbility, SpellID::NONE);
|
||||||
{
|
|
||||||
JsonArraySerializer customSizeJson = handler.enterArray("moatHexes");
|
|
||||||
customSizeJson.syncSize(moatHexes, JsonNode::JsonType::DATA_INTEGER);
|
|
||||||
|
|
||||||
for(size_t index = 0; index < customSizeJson.size(); index++)
|
|
||||||
customSizeJson.serializeInt(index, moatHexes.at(index));
|
|
||||||
}
|
|
||||||
handler.serializeStruct("defender", sideOptions); //Moats are defender only
|
handler.serializeStruct("defender", sideOptions); //Moats are defender only
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,10 +68,6 @@ void Moat::apply(ServerCallback * server, const Mechanics * m, const EffectTarge
|
|||||||
if(m->isMassive() && m->battle()->battleGetSiegeLevel() >= CGTownInstance::CITADEL)
|
if(m->isMassive() && m->battle()->battleGetSiegeLevel() >= CGTownInstance::CITADEL)
|
||||||
{
|
{
|
||||||
EffectTarget moat;
|
EffectTarget moat;
|
||||||
moat.reserve(moatHexes.size());
|
|
||||||
for(const auto & tile : moatHexes)
|
|
||||||
moat.emplace_back(tile);
|
|
||||||
|
|
||||||
placeObstacles(server, m, moat);
|
placeObstacles(server, m, moat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,11 +87,11 @@ void Moat::placeObstacles(ServerCallback * server, const Mechanics * m, const Ef
|
|||||||
if(one->uniqueID >= obstacleIdToGive)
|
if(one->uniqueID >= obstacleIdToGive)
|
||||||
obstacleIdToGive = one->uniqueID + 1;
|
obstacleIdToGive = one->uniqueID + 1;
|
||||||
|
|
||||||
for(const Destination & destination : target)
|
for(const auto & destination : moatHexes) //Moat hexes can be different obstacles
|
||||||
{
|
{
|
||||||
SpellCreatedObstacle obstacle;
|
SpellCreatedObstacle obstacle;
|
||||||
obstacle.uniqueID = obstacleIdToGive++;
|
obstacle.uniqueID = obstacleIdToGive++;
|
||||||
obstacle.pos = destination.hexValue;
|
obstacle.pos = destination.at(0);
|
||||||
obstacle.obstacleType = dispellable ? CObstacleInstance::SPELL_CREATED : CObstacleInstance::MOAT;
|
obstacle.obstacleType = dispellable ? CObstacleInstance::SPELL_CREATED : CObstacleInstance::MOAT;
|
||||||
obstacle.ID = triggerAbility;
|
obstacle.ID = triggerAbility;
|
||||||
|
|
||||||
@ -102,7 +109,7 @@ void Moat::placeObstacles(ServerCallback * server, const Mechanics * m, const Ef
|
|||||||
obstacle.appearSound = sideOptions.appearSound; //For dispellable moats
|
obstacle.appearSound = sideOptions.appearSound; //For dispellable moats
|
||||||
obstacle.appearAnimation = sideOptions.appearAnimation; //For dispellable moats
|
obstacle.appearAnimation = sideOptions.appearAnimation; //For dispellable moats
|
||||||
obstacle.animation = sideOptions.animation;
|
obstacle.animation = sideOptions.animation;
|
||||||
obstacle.customSize.emplace_back(obstacle.pos); //All moat hexes are different obstacles
|
obstacle.customSize.insert(obstacle.customSize.end(),destination.cbegin(), destination.cend());
|
||||||
obstacle.animationYOffset = sideOptions.offsetY;
|
obstacle.animationYOffset = sideOptions.offsetY;
|
||||||
pack.changes.emplace_back();
|
pack.changes.emplace_back();
|
||||||
obstacle.toInfo(pack.changes.back());
|
obstacle.toInfo(pack.changes.back());
|
||||||
|
@ -23,7 +23,7 @@ class Moat : public Obstacle
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ObstacleSideOptions sideOptions; //Defender only
|
ObstacleSideOptions sideOptions; //Defender only
|
||||||
std::vector<BattleHex> moatHexes;
|
std::vector<std::vector<BattleHex>> moatHexes;
|
||||||
bool dispellable; //For Tower landmines
|
bool dispellable; //For Tower landmines
|
||||||
int moatDamage; // Minimal moat damage
|
int moatDamage; // Minimal moat damage
|
||||||
public:
|
public:
|
||||||
|
@ -5222,12 +5222,9 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
|
|||||||
{
|
{
|
||||||
if(!curStack->alive())
|
if(!curStack->alive())
|
||||||
return false;
|
return false;
|
||||||
bool containDamageFromMoat = false;
|
|
||||||
bool movementStopped = false;
|
bool movementStopped = false;
|
||||||
for(auto & obstacle : getAllAffectedObstaclesByStack(curStack, passed))
|
for(auto & obstacle : getAllAffectedObstaclesByStack(curStack, passed))
|
||||||
{
|
{
|
||||||
if(obstacle->obstacleType == CObstacleInstance::SPELL_CREATED)
|
|
||||||
{
|
|
||||||
//helper info
|
//helper info
|
||||||
const SpellCreatedObstacle * spellObstacle = dynamic_cast<const SpellCreatedObstacle *>(obstacle.get());
|
const SpellCreatedObstacle * spellObstacle = dynamic_cast<const SpellCreatedObstacle *>(obstacle.get());
|
||||||
const ui8 side = curStack->side;
|
const ui8 side = curStack->side;
|
||||||
@ -5262,7 +5259,7 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
|
|||||||
};
|
};
|
||||||
auto shouldReveal = !spellObstacle->hidden || !gs->curB->battleIsObstacleVisibleForSide(*obstacle, (BattlePerspective::BattlePerspective)side);
|
auto shouldReveal = !spellObstacle->hidden || !gs->curB->battleIsObstacleVisibleForSide(*obstacle, (BattlePerspective::BattlePerspective)side);
|
||||||
const auto * hero = gs->curB->battleGetFightingHero(spellObstacle->casterSide);
|
const auto * hero = gs->curB->battleGetFightingHero(spellObstacle->casterSide);
|
||||||
auto caster = spells::ObstacleCasterProxy(gs->curB->sides.at(spellObstacle->casterSide).color, hero, spellObstacle);
|
auto caster = spells::ObstacleCasterProxy(gs->curB->sides.at(spellObstacle->casterSide).color, hero, *spellObstacle);
|
||||||
const auto * sp = SpellID(spellObstacle->ID).toSpell();
|
const auto * sp = SpellID(spellObstacle->ID).toSpell();
|
||||||
if(sp)
|
if(sp)
|
||||||
{
|
{
|
||||||
@ -5279,27 +5276,6 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
|
|||||||
}
|
}
|
||||||
else if(shouldReveal)
|
else if(shouldReveal)
|
||||||
revealObstacles(*spellObstacle);
|
revealObstacles(*spellObstacle);
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(obstacle->obstacleType == CObstacleInstance::MOAT)
|
|
||||||
{
|
|
||||||
auto town = gs->curB->town;
|
|
||||||
int damage = (town == nullptr) ? 0 : town->town->moatDamage;
|
|
||||||
if(!containDamageFromMoat)
|
|
||||||
{
|
|
||||||
containDamageFromMoat = true;
|
|
||||||
|
|
||||||
BattleStackAttacked bsa;
|
|
||||||
bsa.damageAmount = damage;
|
|
||||||
bsa.stackAttacked = curStack->ID;
|
|
||||||
bsa.attackerID = -1;
|
|
||||||
curStack->prepareAttacked(bsa, getRandomGenerator());
|
|
||||||
|
|
||||||
StacksInjured si;
|
|
||||||
si.stacks.push_back(bsa);
|
|
||||||
sendAndApply(&si);
|
|
||||||
sendGenericKilledLog(curStack, bsa.killedAmount, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!curStack->alive())
|
if(!curStack->alive())
|
||||||
@ -6347,6 +6323,17 @@ void CGameHandler::runBattle()
|
|||||||
assert(gs->curB);
|
assert(gs->curB);
|
||||||
//TODO: pre-tactic stuff, call scripts etc.
|
//TODO: pre-tactic stuff, call scripts etc.
|
||||||
|
|
||||||
|
//Moat should be initialized here, because only here we can use spellcasting
|
||||||
|
if (gs->curB->town && gs->curB->town->fortLevel() >= CGTownInstance::CITADEL)
|
||||||
|
{
|
||||||
|
const auto * h = gs->curB->battleGetFightingHero(BattleSide::DEFENDER);
|
||||||
|
const auto * actualCaster = h ? static_cast<const spells::Caster*>(h) : nullptr;
|
||||||
|
auto moatCaster = spells::SilentCaster(gs->curB->getSidePlayer(BattleSide::DEFENDER), actualCaster);
|
||||||
|
auto cast = spells::BattleCast(gs->curB, &moatCaster, spells::Mode::PASSIVE, gs->curB->town->town->moatAbility.toSpell());
|
||||||
|
auto target = spells::Target();
|
||||||
|
cast.cast(spellEnv, target);
|
||||||
|
}
|
||||||
|
|
||||||
//tactic round
|
//tactic round
|
||||||
{
|
{
|
||||||
while (gs->curB->tacticDistance && !battleResult.get())
|
while (gs->curB->tacticDistance && !battleResult.get())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user