mirror of
https://github.com/vcmi/vcmi.git
synced 2025-05-13 22:06:58 +02:00
Merge pull request #4440 from IvanSavenko/building_fixes
Fixes for configurable buildings
This commit is contained in:
commit
6426d24feb
@ -174,7 +174,20 @@
|
|||||||
"horde1": { "id" : 18, "upgrades" : "dwellingLvl3" },
|
"horde1": { "id" : 18, "upgrades" : "dwellingLvl3" },
|
||||||
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl3", "requires" : [ "horde1" ], "mode" : "auto" },
|
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl3", "requires" : [ "horde1" ], "mode" : "auto" },
|
||||||
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
||||||
"special2": { "type" : "stables", "requires" : [ "dwellingLvl4" ] },
|
"special2": {
|
||||||
|
"type" : "configurable",
|
||||||
|
"requires" : [ "dwellingLvl4" ],
|
||||||
|
"configuration" : {
|
||||||
|
"visitMode" : "bonus",
|
||||||
|
"rewards" : [
|
||||||
|
{
|
||||||
|
"message" : "@core.genrltxt.580",
|
||||||
|
"movePoints" : 400,
|
||||||
|
"bonuses" : [ { "type" : "MOVEMENT", "subtype" : "heroMovementLand", "val" : 400, "valueType" : "ADDITIVE_VALUE", "duration" : "ONE_WEEK"} ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"special3": { "type" : "brotherhoodOfSword", "upgrades" : "tavern" },
|
"special3": { "type" : "brotherhoodOfSword", "upgrades" : "tavern" },
|
||||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }, "bonuses": [ { "type": "MORALE", "val": 2, "propagator": "PLAYER_PROPAGATOR" } ] },
|
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }, "bonuses": [ { "type": "MORALE", "val": 2, "propagator": "PLAYER_PROPAGATOR" } ] },
|
||||||
|
|
||||||
|
@ -174,9 +174,39 @@
|
|||||||
"special1": { "type" : "artifactMerchant", "requires" : [ "marketplace" ] },
|
"special1": { "type" : "artifactMerchant", "requires" : [ "marketplace" ] },
|
||||||
"horde1": { "id" : 18, "upgrades" : "dwellingLvl1" },
|
"horde1": { "id" : 18, "upgrades" : "dwellingLvl1" },
|
||||||
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
|
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
|
||||||
"special2": { "type" : "manaVortex", "requires" : [ "mageGuild1" ] },
|
"special2": {
|
||||||
|
"type" : "configurable",
|
||||||
|
"requires" : [ "mageGuild1" ],
|
||||||
|
"configuration" : {
|
||||||
|
"resetParameters" : {
|
||||||
|
"period" : 7,
|
||||||
|
"visitors" : true
|
||||||
|
},
|
||||||
|
"visitMode" : "hero", // Should be 'once' to match (somewhat buggy) H3 logic
|
||||||
|
"rewards" : [
|
||||||
|
{
|
||||||
|
"limiter" : {
|
||||||
|
"noneOf" : [ { "manaPercentage" : 200 } ]
|
||||||
|
},
|
||||||
|
"message" : "@core.genrltxt.579",
|
||||||
|
"manaPercentage" : 200
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"special3": { "type" : "portalOfSummoning" },
|
"special3": { "type" : "portalOfSummoning" },
|
||||||
"special4": { "type" : "experienceVisitingBonus" },
|
"special4": {
|
||||||
|
"type" : "configurable",
|
||||||
|
"configuration" : {
|
||||||
|
"visitMode" : "hero",
|
||||||
|
"rewards" : [
|
||||||
|
{
|
||||||
|
"message" : "@core.genrltxt.583",
|
||||||
|
"heroExperience" : 1000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 },
|
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 },
|
||||||
"bonuses": [ { "type": "PRIMARY_SKILL", "subtype": "primarySkill.spellpower", "val": 12 } ] },
|
"bonuses": [ { "type": "PRIMARY_SKILL", "subtype": "primarySkill.spellpower", "val": 12 } ] },
|
||||||
|
|
||||||
|
@ -169,7 +169,19 @@
|
|||||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "wood": 1, "ore": 1 } },
|
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "wood": 1, "ore": 1 } },
|
||||||
"blacksmith": { "id" : 16 },
|
"blacksmith": { "id" : 16 },
|
||||||
|
|
||||||
"special1": { "type" : "defenceVisitingBonus", "requires" : [ "allOf", [ "townHall" ], [ "special2" ] ] },
|
"special1": {
|
||||||
|
"type" : "configurable",
|
||||||
|
"requires" : [ "allOf", [ "townHall" ], [ "special2" ] ],
|
||||||
|
"configuration" : {
|
||||||
|
"visitMode" : "hero",
|
||||||
|
"rewards" : [
|
||||||
|
{
|
||||||
|
"message" : "@core.genrltxt.585",
|
||||||
|
"primary" : { "defence" : 1 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"horde1": { "id" : 18, "upgrades" : "dwellingLvl1" },
|
"horde1": { "id" : 18, "upgrades" : "dwellingLvl1" },
|
||||||
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
|
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
|
||||||
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
||||||
|
@ -175,7 +175,19 @@
|
|||||||
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
|
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
|
||||||
"special2": { "type" : "spellPowerGarrisonBonus", "requires" : [ "fort" ] },
|
"special2": { "type" : "spellPowerGarrisonBonus", "requires" : [ "fort" ] },
|
||||||
"special3": { "type" : "castleGate", "requires" : [ "citadel" ] },
|
"special3": { "type" : "castleGate", "requires" : [ "citadel" ] },
|
||||||
"special4": { "type" : "spellPowerVisitingBonus", "requires" : [ "mageGuild1" ] },
|
"special4": {
|
||||||
|
"type" : "configurable",
|
||||||
|
"requires" : [ "mageGuild1" ],
|
||||||
|
"configuration" : {
|
||||||
|
"visitMode" : "hero",
|
||||||
|
"rewards" : [
|
||||||
|
{
|
||||||
|
"message" : "@core.genrltxt.582",
|
||||||
|
"primary" : { "spellpower" : 1 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"horde2": { "id" : 24, "upgrades" : "dwellingLvl3" },
|
"horde2": { "id" : 24, "upgrades" : "dwellingLvl3" },
|
||||||
"horde2Upgr": { "id" : 25, "upgrades" : "dwellingUpLvl3", "requires" : [ "horde2" ], "mode" : "auto" },
|
"horde2Upgr": { "id" : 25, "upgrades" : "dwellingUpLvl3", "requires" : [ "horde2" ], "mode" : "auto" },
|
||||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
||||||
|
@ -171,7 +171,19 @@
|
|||||||
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
|
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
|
||||||
"special2": { "type" : "freelancersGuild", "requires" : [ "marketplace" ] },
|
"special2": { "type" : "freelancersGuild", "requires" : [ "marketplace" ] },
|
||||||
"special3": { "type" : "ballistaYard", "requires" : [ "blacksmith" ] },
|
"special3": { "type" : "ballistaYard", "requires" : [ "blacksmith" ] },
|
||||||
"special4": { "type" : "attackVisitingBonus", "requires" : [ "fort" ] },
|
"special4": {
|
||||||
|
"type" : "configurable",
|
||||||
|
"requires" : [ "fort" ],
|
||||||
|
"configuration" : {
|
||||||
|
"visitMode" : "hero",
|
||||||
|
"rewards" : [
|
||||||
|
{
|
||||||
|
"message" : "@core.genrltxt.584",
|
||||||
|
"primary" : { "attack" : 1 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 },
|
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 },
|
||||||
"bonuses": [ { "type": "PRIMARY_SKILL", "subtype": "primarySkill.attack", "val": 20 } ] },
|
"bonuses": [ { "type": "PRIMARY_SKILL", "subtype": "primarySkill.attack", "val": 20 } ] },
|
||||||
|
|
||||||
|
@ -174,7 +174,19 @@
|
|||||||
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl2", "requires" : [ "horde1" ], "mode" : "auto" },
|
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl2", "requires" : [ "horde1" ], "mode" : "auto" },
|
||||||
"special2": { "type" : "lookoutTower", "height" : "high", "requires" : [ "fort" ] },
|
"special2": { "type" : "lookoutTower", "height" : "high", "requires" : [ "fort" ] },
|
||||||
"special3": { "type" : "library", "requires" : [ "mageGuild1" ] },
|
"special3": { "type" : "library", "requires" : [ "mageGuild1" ] },
|
||||||
"special4": { "type" : "knowledgeVisitingBonus", "requires" : [ "mageGuild1" ] },
|
"special4": {
|
||||||
|
"type" : "configurable",
|
||||||
|
"requires" : [ "mageGuild1" ],
|
||||||
|
"configuration" : {
|
||||||
|
"visitMode" : "hero",
|
||||||
|
"rewards" : [
|
||||||
|
{
|
||||||
|
"message" : "@core.genrltxt.581",
|
||||||
|
"primary" : { "knowledge" : 1 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"grail": { "height" : "skyship", "produce" : { "gold": 5000 }, "bonuses": [ { "type": "PRIMARY_SKILL", "subtype": "primarySkill.knowledge", "val": 15 } ] },
|
"grail": { "height" : "skyship", "produce" : { "gold": 5000 }, "bonuses": [ { "type": "PRIMARY_SKILL", "subtype": "primarySkill.knowledge", "val": 15 } ] },
|
||||||
|
|
||||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||||
|
@ -179,7 +179,10 @@
|
|||||||
"description" : "stacking"
|
"description" : "stacking"
|
||||||
},
|
},
|
||||||
"description" : {
|
"description" : {
|
||||||
"type" : "string",
|
"anyOf" : [
|
||||||
|
{ "type" : "string" },
|
||||||
|
{ "type" : "number" }
|
||||||
|
],
|
||||||
"description" : "description"
|
"description" : "description"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
326
config/schemas/rewardable.json
Normal file
326
config/schemas/rewardable.json
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
{
|
||||||
|
"type" : "object",
|
||||||
|
"$schema" : "http://json-schema.org/draft-04/schema",
|
||||||
|
"title" : "VCMI map object format",
|
||||||
|
"description" : "Description of map object class",
|
||||||
|
"required" : [ "rewards" ],
|
||||||
|
"additionalProperties" : false,
|
||||||
|
|
||||||
|
"definitions" : {
|
||||||
|
"value" : {
|
||||||
|
"anyOf" : [
|
||||||
|
{
|
||||||
|
"type" : "number"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "string" // variable name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "array",
|
||||||
|
"items" : {
|
||||||
|
"$ref" : "#/definitions/value"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : true,
|
||||||
|
"properties" : {
|
||||||
|
"amount" : { "$ref" : "#/definitions/value" },
|
||||||
|
"min" : { "$ref" : "#/definitions/value" },
|
||||||
|
"max" : { "$ref" : "#/definitions/value" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"identifier" : {
|
||||||
|
"anyOf" : [
|
||||||
|
{
|
||||||
|
"type" : "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : true,
|
||||||
|
"properties" : {
|
||||||
|
"type" : {
|
||||||
|
"$ref" : "#/definitions/identifier"
|
||||||
|
},
|
||||||
|
"anyOf" : {
|
||||||
|
"type" : "array",
|
||||||
|
"items" : {
|
||||||
|
"$ref" : "#/definitions/identifier"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"noneOf" : {
|
||||||
|
"type" : "array",
|
||||||
|
"items" : {
|
||||||
|
"$ref" : "#/definitions/identifier"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"identifierList" : {
|
||||||
|
"type" : "array",
|
||||||
|
"items" : {
|
||||||
|
"$ref" : "#/definitions/identifier"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"identifierWithValueList" : {
|
||||||
|
"anyOf" : [
|
||||||
|
{
|
||||||
|
"type" : "array",
|
||||||
|
"items" : {
|
||||||
|
"allOf" : [
|
||||||
|
{ "$ref" : "#/definitions/identifier" },
|
||||||
|
{ "$ref" : "#/definitions/value" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : {
|
||||||
|
"$ref" : "#/definitions/value"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"reward" : {
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : false,
|
||||||
|
"properties" : {
|
||||||
|
"appearChance" : {
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : false,
|
||||||
|
"properties" : {
|
||||||
|
"dice" : { "type" : "number" },
|
||||||
|
"min" : { "type" : "number", "minimum" : 0, "exclusiveMaximum" : 100 },
|
||||||
|
"max" : { "type" : "number", "exclusiveMinimum" : 0, "maximum" : 100 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"limiter" : { "$ref" : "#/definitions/limiter" },
|
||||||
|
"message" : { "$ref" : "#/definitions/message" },
|
||||||
|
"description" : { "$ref" : "#/definitions/message" },
|
||||||
|
|
||||||
|
"heroExperience" : { "$ref" : "#/definitions/value" },
|
||||||
|
"heroLevel" : { "$ref" : "#/definitions/value" },
|
||||||
|
"movePercentage" : { "$ref" : "#/definitions/value" },
|
||||||
|
"movePoints" : { "$ref" : "#/definitions/value" },
|
||||||
|
"manaPercentage" : { "$ref" : "#/definitions/value" },
|
||||||
|
"manaPoints" : { "$ref" : "#/definitions/value" },
|
||||||
|
"manaOverflowFactor" : { "$ref" : "#/definitions/value" },
|
||||||
|
|
||||||
|
"removeObject" : { "type" : "boolean" },
|
||||||
|
"bonuses" : {
|
||||||
|
"type":"array",
|
||||||
|
"description": "List of bonuses that will be granted to visiting hero",
|
||||||
|
"items": { "$ref" : "bonus.json" }
|
||||||
|
},
|
||||||
|
|
||||||
|
"resources" : { "$ref" : "#/definitions/identifierWithValueList" },
|
||||||
|
"secondary" : { "$ref" : "#/definitions/identifierWithValueList" },
|
||||||
|
"creatures" : { "$ref" : "#/definitions/identifierWithValueList" },
|
||||||
|
"primary" : { "$ref" : "#/definitions/identifierWithValueList" },
|
||||||
|
|
||||||
|
"artifacts" : { "$ref" : "#/definitions/identifierList" },
|
||||||
|
"spells" : { "$ref" : "#/definitions/identifierList" },
|
||||||
|
|
||||||
|
"spellCast" : {
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : false,
|
||||||
|
"properties" : {
|
||||||
|
"spell" : { "$ref" : "#/definitions/identifier" },
|
||||||
|
"schoolLevel" : { "type" : "number" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"revealTiles" : {
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : false,
|
||||||
|
"properties" : {
|
||||||
|
"hide" : { "type" : "boolean" },
|
||||||
|
"radius" : { "type" : "number" },
|
||||||
|
"surface" : { "type" : "number" },
|
||||||
|
"subterra" : { "type" : "number" },
|
||||||
|
"water" : { "type" : "number" },
|
||||||
|
"rock" : { "type" : "number" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"changeCreatures" : {
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : { "type" : "string" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"limiter" : {
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : false,
|
||||||
|
"properties" : {
|
||||||
|
"dayOfWeek" : { "$ref" : "#/definitions/value" },
|
||||||
|
"daysPassed" : { "$ref" : "#/definitions/value" },
|
||||||
|
"heroExperience" : { "$ref" : "#/definitions/value" },
|
||||||
|
"heroLevel" : { "$ref" : "#/definitions/value" },
|
||||||
|
"manaPercentage" : { "$ref" : "#/definitions/value" },
|
||||||
|
"manaPoints" : { "$ref" : "#/definitions/value" },
|
||||||
|
|
||||||
|
"canLearnSkills" : { "type" : "boolean" },
|
||||||
|
|
||||||
|
"resources" : { "$ref" : "#/definitions/identifierWithValueList" },
|
||||||
|
"secondary" : { "$ref" : "#/definitions/identifierWithValueList" },
|
||||||
|
"creatures" : { "$ref" : "#/definitions/identifierWithValueList" },
|
||||||
|
"primary" : { "$ref" : "#/definitions/identifierWithValueList" },
|
||||||
|
|
||||||
|
"canLearnSpells" : { "$ref" : "#/definitions/identifierList" },
|
||||||
|
"heroClasses" : { "$ref" : "#/definitions/identifierList" },
|
||||||
|
"artifacts" : { "$ref" : "#/definitions/identifierList" },
|
||||||
|
"spells" : { "$ref" : "#/definitions/identifierList" },
|
||||||
|
"colors" : { "$ref" : "#/definitions/identifierList" },
|
||||||
|
"heroes" : { "$ref" : "#/definitions/identifierList" },
|
||||||
|
|
||||||
|
"anyOf" : {
|
||||||
|
"type" : "array",
|
||||||
|
"items" : { "$ref" : "#/definitions/limiter" }
|
||||||
|
},
|
||||||
|
"allOf" : {
|
||||||
|
"type" : "array",
|
||||||
|
"items" : { "$ref" : "#/definitions/limiter" }
|
||||||
|
},
|
||||||
|
"noneOf" : {
|
||||||
|
"type" : "array",
|
||||||
|
"items" : { "$ref" : "#/definitions/limiter" }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"message" : {
|
||||||
|
"anyOf" : [
|
||||||
|
{
|
||||||
|
"type" : "array",
|
||||||
|
"items" : {
|
||||||
|
"anyOf" : [
|
||||||
|
{ "type" : "number" },
|
||||||
|
{ "type" : "string" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "number"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"variableList" : {
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : {
|
||||||
|
"$ref" : "#/definitions/identifier"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"properties" : {
|
||||||
|
"rewards" : {
|
||||||
|
"type" : "array",
|
||||||
|
"items" : { "$ref" : "#/definitions/reward" }
|
||||||
|
},
|
||||||
|
"onVisited" : {
|
||||||
|
"type" : "array",
|
||||||
|
"items" : { "$ref" : "#/definitions/reward" }
|
||||||
|
},
|
||||||
|
"onEmpty" : {
|
||||||
|
"type" : "array",
|
||||||
|
"items" : { "$ref" : "#/definitions/reward" }
|
||||||
|
},
|
||||||
|
|
||||||
|
"variables" : {
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : false,
|
||||||
|
"properties" : {
|
||||||
|
"number" : {
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : {
|
||||||
|
"$ref" : "#/definitions/value"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"artifact" : {
|
||||||
|
"$ref" : "#/definitions/variableList"
|
||||||
|
},
|
||||||
|
"spell" : {
|
||||||
|
"$ref" : "#/definitions/variableList"
|
||||||
|
},
|
||||||
|
"primarySkill" : {
|
||||||
|
"$ref" : "#/definitions/variableList"
|
||||||
|
},
|
||||||
|
"secondarySkill" : {
|
||||||
|
"$ref" : "#/definitions/variableList"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"onSelectMessage" : {
|
||||||
|
"$ref" : "#/definitions/message"
|
||||||
|
},
|
||||||
|
"description" : {
|
||||||
|
"$ref" : "#/definitions/message"
|
||||||
|
},
|
||||||
|
"notVisitedTooltip" : {
|
||||||
|
"$ref" : "#/definitions/message"
|
||||||
|
},
|
||||||
|
"visitedTooltip" : {
|
||||||
|
"$ref" : "#/definitions/message"
|
||||||
|
},
|
||||||
|
"onVisitedMessage" : {
|
||||||
|
"$ref" : "#/definitions/message"
|
||||||
|
},
|
||||||
|
"onEmptyMessage" : {
|
||||||
|
"$ref" : "#/definitions/message"
|
||||||
|
},
|
||||||
|
|
||||||
|
"canRefuse": {
|
||||||
|
"type" : "boolean"
|
||||||
|
},
|
||||||
|
|
||||||
|
"showScoutedPreview": {
|
||||||
|
"type" : "boolean"
|
||||||
|
},
|
||||||
|
|
||||||
|
"showInInfobox": {
|
||||||
|
"type" : "boolean"
|
||||||
|
},
|
||||||
|
|
||||||
|
"visitMode": {
|
||||||
|
"enum" : [ "unlimited", "once", "hero", "bonus", "limiter", "player" ],
|
||||||
|
"type" : "string"
|
||||||
|
},
|
||||||
|
|
||||||
|
"visitLimiter": {
|
||||||
|
"type" : "object"
|
||||||
|
},
|
||||||
|
|
||||||
|
"selectMode": {
|
||||||
|
"enum" : [ "selectFirst", "selectPlayer", "selectRandom", "selectAll" ],
|
||||||
|
"type" : "string"
|
||||||
|
},
|
||||||
|
|
||||||
|
"resetParameters" : {
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : false,
|
||||||
|
"properties" : {
|
||||||
|
"visitors" : { "type" : "boolean" },
|
||||||
|
"rewards" : { "type" : "boolean" },
|
||||||
|
"period" : { "type" : "number" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Properties that might appear since this node is shared with object config
|
||||||
|
"compatibilityIdentifiers" : { },
|
||||||
|
"blockedVisitable" : { },
|
||||||
|
"removable" : { },
|
||||||
|
"aiValue" : { },
|
||||||
|
"index" : { },
|
||||||
|
"base" : { },
|
||||||
|
"rmg" : { },
|
||||||
|
"templates" : { },
|
||||||
|
"battleground" : { },
|
||||||
|
"sounds" : { }
|
||||||
|
}
|
||||||
|
}
|
@ -31,11 +31,12 @@
|
|||||||
"type" : "string"
|
"type" : "string"
|
||||||
},
|
},
|
||||||
"description" : {
|
"description" : {
|
||||||
"description" : "Localizable decsription of this building",
|
"description" : "Localizable description of this building",
|
||||||
"type" : "string"
|
"type" : "string"
|
||||||
},
|
},
|
||||||
"type" : {
|
"type" : {
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
|
"enum" : [ "mysticPond", "artifactMerchant", "freelancersGuild", "magicUniversity", "castleGate", "creatureTransformer", "portalOfSummoning", "ballistaYard", "lookoutTower", "library", "brotherhoodOfSword", "fountainOfFortune", "spellPowerGarrisonBonus", "attackGarrisonBonus", "defenseGarrisonBonus", "escapeTunnel", "lighthouse", "treasury", "thievesGuild", "bank", "configurable" ],
|
||||||
"description" : "Subtype for some special buildings"
|
"description" : "Subtype for some special buildings"
|
||||||
},
|
},
|
||||||
"mode" : {
|
"mode" : {
|
||||||
@ -56,6 +57,10 @@
|
|||||||
"description" : "Optional, indicates that this building upgrades another base building",
|
"description" : "Optional, indicates that this building upgrades another base building",
|
||||||
"type" : "string"
|
"type" : "string"
|
||||||
},
|
},
|
||||||
|
"configuration" : {
|
||||||
|
"description" : "Configuration of building. Only used if 'type' is set to 'configurable'",
|
||||||
|
"$ref" : "rewardable.json"
|
||||||
|
},
|
||||||
"cost" : {
|
"cost" : {
|
||||||
"type" : "object",
|
"type" : "object",
|
||||||
"additionalProperties" : false,
|
"additionalProperties" : false,
|
||||||
|
@ -341,100 +341,7 @@ Each town requires a set of buildings (Around 30-45 buildings)
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Building node
|
## Building node
|
||||||
|
See [Town Building Format](Town_Building_Format.md)
|
||||||
```jsonc
|
|
||||||
{
|
|
||||||
// Numeric identifier of this building
|
|
||||||
"id" : 0,
|
|
||||||
|
|
||||||
// Localizable name of this building
|
|
||||||
"name" : "",
|
|
||||||
|
|
||||||
// Localizable decsription of this building
|
|
||||||
"description" : "",
|
|
||||||
|
|
||||||
// Optional, indicates that this building upgrades another base building
|
|
||||||
"upgrades" : "baseBuilding",
|
|
||||||
|
|
||||||
// List of town buildings that must be built before this one. See below for full format
|
|
||||||
"requires" : [ "allOf", [ "mageGuild1" ], [ "tavern" ] ],
|
|
||||||
|
|
||||||
// Resources needed to build building
|
|
||||||
"cost" : { ... },
|
|
||||||
|
|
||||||
// TODO: Document me: Subtype for some special buildings
|
|
||||||
"type" : "",
|
|
||||||
|
|
||||||
// TODO: Document me: Height for lookout towers and some grails
|
|
||||||
"height" : "average"
|
|
||||||
|
|
||||||
// Resources produced each day by this building
|
|
||||||
"produce" : { ... },
|
|
||||||
|
|
||||||
//determine how this building can be built. Possible values are:
|
|
||||||
// normal - default value. Fulfill requirements, use resources, spend one day
|
|
||||||
// auto - building appears when all requirements are built
|
|
||||||
// special - building can not be built manually
|
|
||||||
// grail - building requires grail to be built
|
|
||||||
"mode" : "auto",
|
|
||||||
|
|
||||||
// Buildings which bonuses should be overridden with bonuses of the current building
|
|
||||||
"overrides" : [ "anotherBuilding ]
|
|
||||||
|
|
||||||
// Bonuses, provided by this special building on build using bonus system
|
|
||||||
"bonuses" : BONUS_FORMAT
|
|
||||||
|
|
||||||
// Bonuses, provided by this special building on hero visit and applied to the visiting hero
|
|
||||||
"onVisitBonuses" : BONUS_FORMAT
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Building requirements can be described using logical expressions:
|
|
||||||
|
|
||||||
```jsonc
|
|
||||||
"requires" :
|
|
||||||
[
|
|
||||||
"allOf", // Normal H3 "build all" mode
|
|
||||||
[ "mageGuild1" ],
|
|
||||||
[
|
|
||||||
"noneOf", // available only when none of these building are built
|
|
||||||
[ "dwelling5A" ],
|
|
||||||
[ "dwelling5AUpgrade" ]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"anyOf", // any non-zero number of these buildings must be built
|
|
||||||
[ "tavern" ],
|
|
||||||
[ "blacksmith" ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Structure node
|
## Structure node
|
||||||
|
See [Town Building Format](Town_Building_Format.md)
|
||||||
```jsonc
|
|
||||||
{
|
|
||||||
// Main animation file for this building
|
|
||||||
"animation" : "",
|
|
||||||
|
|
||||||
// Horizontal position on town screen
|
|
||||||
"x" : 0,
|
|
||||||
|
|
||||||
// Vertical position on town screen
|
|
||||||
"y" : 0,
|
|
||||||
|
|
||||||
// used for blit order. Higher value places structure close to screen and drawn on top of buildings with lower values
|
|
||||||
"z" : 0,
|
|
||||||
|
|
||||||
// Path to image with golden border around building, displayed when building is selected
|
|
||||||
"border" : "",
|
|
||||||
|
|
||||||
// Path to image with area that indicate when building is selected
|
|
||||||
"area" : "",
|
|
||||||
|
|
||||||
//TODO: describe me
|
|
||||||
"builds": "",
|
|
||||||
|
|
||||||
// If upgrade, this building will replace parent animation but will not alter its behaviour
|
|
||||||
"hidden" : false
|
|
||||||
}
|
|
||||||
```
|
|
194
docs/modders/Entities_Format/Town_Building_Format.md
Normal file
194
docs/modders/Entities_Format/Town_Building_Format.md
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
# Town Building Format
|
||||||
|
|
||||||
|
# Required data
|
||||||
|
|
||||||
|
Each building requires following assets:
|
||||||
|
|
||||||
|
- Town animation file (1 animation file)
|
||||||
|
- Selection highlight (1 image)
|
||||||
|
- Selection area (1 image)
|
||||||
|
- Town hall icon (1 image)
|
||||||
|
|
||||||
|
## Town Building node
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
// Numeric identifier of this building
|
||||||
|
"id" : 0,
|
||||||
|
|
||||||
|
// Localizable name of this building
|
||||||
|
"name" : "",
|
||||||
|
|
||||||
|
// Localizable decsription of this building
|
||||||
|
"description" : "",
|
||||||
|
|
||||||
|
// Optional, indicates that this building upgrades another base building
|
||||||
|
"upgrades" : "baseBuilding",
|
||||||
|
|
||||||
|
// List of town buildings that must be built before this one. See below for full format
|
||||||
|
"requires" : [ "allOf", [ "mageGuild1" ], [ "tavern" ] ],
|
||||||
|
|
||||||
|
// Resources needed to build building
|
||||||
|
"cost" : {
|
||||||
|
"wood" : 20,
|
||||||
|
"ore" : 20,
|
||||||
|
"gold" : 10000
|
||||||
|
},
|
||||||
|
|
||||||
|
// Allows to define additional functionality of this building, usually using logic of one of original H3 town building
|
||||||
|
// Generally only needs to be specified for "special" buildings
|
||||||
|
// See 'List of unique town buildings' section below for detailed description of this field
|
||||||
|
"type" : "",
|
||||||
|
|
||||||
|
// If set, building will have Lookout Tower logic - extend sight radius of a town.
|
||||||
|
// Possible values:
|
||||||
|
// low - increases town sight radius by 5 tiles
|
||||||
|
// average - sight radius extended by 15 tiles
|
||||||
|
// high - sight radius extended by 20 tiles
|
||||||
|
// skyship - entire map will be revealed
|
||||||
|
// If not set, building will not affect sight radius of a town
|
||||||
|
"height" : "average"
|
||||||
|
|
||||||
|
// Resources produced each day by this building
|
||||||
|
"produce" : {
|
||||||
|
"sulfur" : 1,
|
||||||
|
"gold" : 2000
|
||||||
|
},
|
||||||
|
|
||||||
|
//determine how this building can be built. Possible values are:
|
||||||
|
// normal - default value. Fulfill requirements, use resources, spend one day
|
||||||
|
// auto - building appears when all requirements are built
|
||||||
|
// special - building can not be built manually
|
||||||
|
// grail - building requires grail to be built
|
||||||
|
"mode" : "auto",
|
||||||
|
|
||||||
|
// Buildings which bonuses should be overridden with bonuses of the current building
|
||||||
|
"overrides" : [ "anotherBuilding ]
|
||||||
|
|
||||||
|
// Bonuses, provided by this special building on build using bonus system
|
||||||
|
"bonuses" : BONUS_FORMAT
|
||||||
|
|
||||||
|
// Bonuses, provided by this special building on hero visit and applied to the visiting hero
|
||||||
|
"onVisitBonuses" : BONUS_FORMAT
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Building requirements can be described using logical expressions:
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
"requires" :
|
||||||
|
[
|
||||||
|
"allOf", // Normal H3 "build all" mode
|
||||||
|
[ "mageGuild1" ],
|
||||||
|
[
|
||||||
|
"noneOf", // available only when none of these building are built
|
||||||
|
[ "dwelling5A" ],
|
||||||
|
[ "dwelling5AUpgrade" ]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"anyOf", // any non-zero number of these buildings must be built
|
||||||
|
[ "tavern" ],
|
||||||
|
[ "blacksmith" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
### List of unique town buildings
|
||||||
|
|
||||||
|
Following Heroes III buildings can be used as unique buildings for a town. Their functionality should be identical to a corresponding H3 building:
|
||||||
|
- `mysticPond`
|
||||||
|
- `artifactMerchant`
|
||||||
|
- `freelancersGuild`
|
||||||
|
- `magicUniversity`
|
||||||
|
- `castleGate`
|
||||||
|
- `creatureTransformer`
|
||||||
|
- `portalOfSummoning`
|
||||||
|
- `ballistaYard`
|
||||||
|
- `stables`
|
||||||
|
- `manaVortex`
|
||||||
|
- `lookoutTower`
|
||||||
|
- `library`
|
||||||
|
- `brotherhoodOfSword`
|
||||||
|
- `fountainOfFortune`
|
||||||
|
- `escapeTunnel`
|
||||||
|
- `lighthouse`
|
||||||
|
- `treasury`
|
||||||
|
- `spellPowerGarrisonBonus`
|
||||||
|
- `attackGarrisonBonus`
|
||||||
|
- `defenseGarrisonBonus`
|
||||||
|
|
||||||
|
Following HotA buildings can be used as unique building for a town. Functionality should match corresponding HotA building:
|
||||||
|
- `thievesGuild`
|
||||||
|
- `bank`
|
||||||
|
|
||||||
|
In addition to above, it is possible to use same format as [Rewardable](../Map_Objects/Rewardable.md) map objects for town buildings. In order to do that, town building type must be set to `configurable` and configuration of a rewardable object must be placed into `configuration` node
|
||||||
|
|
||||||
|
Example 1 - Order of Fire from Inferno:
|
||||||
|
```jsonc
|
||||||
|
"special4": { //
|
||||||
|
"type" : "configurable",
|
||||||
|
"requires" : [ "mageGuild1" ],
|
||||||
|
"configuration" : {
|
||||||
|
"visitMode" : "hero",
|
||||||
|
"rewards" : [
|
||||||
|
{
|
||||||
|
"message" : "@core.genrltxt.582", // NOTE: this forces vcmi to load string from H3 text file. In order to define own string simply write your own message without '@' symbol
|
||||||
|
"primary" : { "spellpower" : 1 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example 2 - Mana Vortex from Dungeon
|
||||||
|
```jsonc
|
||||||
|
"special2": {
|
||||||
|
"type" : "configurable",
|
||||||
|
"requires" : [ "mageGuild1" ],
|
||||||
|
"configuration" : {
|
||||||
|
"resetParameters" : {
|
||||||
|
"period" : 7,
|
||||||
|
"visitors" : true
|
||||||
|
},
|
||||||
|
"visitMode" : "once",
|
||||||
|
"rewards" : [
|
||||||
|
{
|
||||||
|
"limiter" : {
|
||||||
|
"noneOf" : [ { "manaPercentage" : 200 } ]
|
||||||
|
},
|
||||||
|
"message" : "@core.genrltxt.579",
|
||||||
|
"manaPercentage" : 200
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Town Structure node
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
// Main animation file for this building
|
||||||
|
"animation" : "",
|
||||||
|
|
||||||
|
// Horizontal position on town screen
|
||||||
|
"x" : 0,
|
||||||
|
|
||||||
|
// Vertical position on town screen
|
||||||
|
"y" : 0,
|
||||||
|
|
||||||
|
// used for blit order. Higher value places structure close to screen and drawn on top of buildings with lower values
|
||||||
|
"z" : 0,
|
||||||
|
|
||||||
|
// Path to image with golden border around building, displayed when building is selected
|
||||||
|
"border" : "",
|
||||||
|
|
||||||
|
// Path to image with area that indicate when building is selected
|
||||||
|
"area" : "",
|
||||||
|
|
||||||
|
//TODO: describe me
|
||||||
|
"builds": "",
|
||||||
|
|
||||||
|
// If upgrade, this building will replace parent animation but will not alter its behaviour
|
||||||
|
"hidden" : false
|
||||||
|
}
|
||||||
|
```
|
@ -84,11 +84,9 @@ bool IBonusBearer::hasBonusOfType(BonusType type, BonusSubtypeID subtype) const
|
|||||||
|
|
||||||
bool IBonusBearer::hasBonusFrom(BonusSource source, BonusSourceID sourceID) const
|
bool IBonusBearer::hasBonusFrom(BonusSource source, BonusSourceID sourceID) const
|
||||||
{
|
{
|
||||||
boost::format fmt("source_%did_%s");
|
return hasBonus(Selector::source(source,sourceID));
|
||||||
fmt % static_cast<int>(source) % sourceID.toString();
|
|
||||||
|
|
||||||
return hasBonus(Selector::source(source,sourceID), fmt.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const Bonus> IBonusBearer::getBonus(const CSelector &selector) const
|
std::shared_ptr<const Bonus> IBonusBearer::getBonus(const CSelector &selector) const
|
||||||
{
|
{
|
||||||
auto bonuses = getAllBonuses(selector, Selector::all);
|
auto bonuses = getAllBonuses(selector, Selector::all);
|
||||||
|
@ -203,7 +203,8 @@ namespace MappedKeys
|
|||||||
{ "lighthouse", BuildingSubID::LIGHTHOUSE },
|
{ "lighthouse", BuildingSubID::LIGHTHOUSE },
|
||||||
{ "treasury", BuildingSubID::TREASURY },
|
{ "treasury", BuildingSubID::TREASURY },
|
||||||
{ "thievesGuild", BuildingSubID::THIEVES_GUILD },
|
{ "thievesGuild", BuildingSubID::THIEVES_GUILD },
|
||||||
{ "bank", BuildingSubID::BANK }
|
{ "bank", BuildingSubID::BANK },
|
||||||
|
{ "configurable", BuildingSubID::CUSTOM_VISITING_REWARD}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::map<std::string, EMarketMode> MARKET_NAMES_TO_TYPES =
|
static const std::map<std::string, EMarketMode> MARKET_NAMES_TO_TYPES =
|
||||||
|
@ -80,7 +80,7 @@ BuildingID CTown::getBuildingType(BuildingSubID::EBuildingSubID subID) const
|
|||||||
|
|
||||||
std::string CTown::getGreeting(BuildingSubID::EBuildingSubID subID) const
|
std::string CTown::getGreeting(BuildingSubID::EBuildingSubID subID) const
|
||||||
{
|
{
|
||||||
return CTownHandler::getMappedValue<const std::string, BuildingSubID::EBuildingSubID>(subID, std::string(), specialMessages, false);
|
return vstd::find_or(specialMessages, subID, std::string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTown::setGreeting(BuildingSubID::EBuildingSubID subID, const std::string & message) const
|
void CTown::setGreeting(BuildingSubID::EBuildingSubID subID, const std::string & message) const
|
||||||
|
@ -324,7 +324,7 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons
|
|||||||
assert(!source.getModScope().empty());
|
assert(!source.getModScope().empty());
|
||||||
|
|
||||||
auto * ret = new CBuilding();
|
auto * ret = new CBuilding();
|
||||||
ret->bid = getMappedValue<BuildingID, std::string>(stringID, BuildingID::NONE, MappedKeys::BUILDING_NAMES_TO_TYPES, false);
|
ret->bid = vstd::find_or(MappedKeys::BUILDING_NAMES_TO_TYPES, stringID, BuildingID::NONE);
|
||||||
ret->subId = BuildingSubID::NONE;
|
ret->subId = BuildingSubID::NONE;
|
||||||
|
|
||||||
if(ret->bid == BuildingID::NONE && !source["id"].isNull())
|
if(ret->bid == BuildingID::NONE && !source["id"].isNull())
|
||||||
@ -339,9 +339,9 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons
|
|||||||
|
|
||||||
ret->mode = ret->bid == BuildingID::GRAIL
|
ret->mode = ret->bid == BuildingID::GRAIL
|
||||||
? CBuilding::BUILD_GRAIL
|
? CBuilding::BUILD_GRAIL
|
||||||
: getMappedValue<CBuilding::EBuildMode>(source["mode"], CBuilding::BUILD_NORMAL, CBuilding::MODES);
|
: vstd::find_or(CBuilding::MODES, source["mode"].String(), CBuilding::BUILD_NORMAL);
|
||||||
|
|
||||||
ret->height = getMappedValue<CBuilding::ETowerHeight>(source["height"], CBuilding::HEIGHT_NO_TOWER, CBuilding::TOWER_TYPES);
|
ret->height = vstd::find_or(CBuilding::TOWER_TYPES, source["height"].String(), CBuilding::HEIGHT_NO_TOWER);
|
||||||
|
|
||||||
ret->identifier = stringID;
|
ret->identifier = stringID;
|
||||||
ret->modScope = source.getModScope();
|
ret->modScope = source.getModScope();
|
||||||
@ -361,7 +361,7 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons
|
|||||||
|
|
||||||
if(ret->buildingBonuses.empty())
|
if(ret->buildingBonuses.empty())
|
||||||
{
|
{
|
||||||
ret->subId = getMappedValue<BuildingSubID::EBuildingSubID>(source["type"], BuildingSubID::NONE, MappedKeys::SPECIAL_BUILDINGS);
|
ret->subId = vstd::find_or(MappedKeys::SPECIAL_BUILDINGS, source["type"].String(), BuildingSubID::NONE);
|
||||||
addBonusesForVanilaBuilding(ret);
|
addBonusesForVanilaBuilding(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,11 +376,8 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons
|
|||||||
bonus->sid = BonusSourceID(ret->getUniqueTypeID());
|
bonus->sid = BonusSourceID(ret->getUniqueTypeID());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(source["type"].String() == "configurable" && ret->subId == BuildingSubID::NONE)
|
if(ret->subId == BuildingSubID::CUSTOM_VISITING_REWARD)
|
||||||
{
|
ret->rewardableObjectInfo.init(source["configuration"], ret->getBaseTextID());
|
||||||
ret->subId = BuildingSubID::CUSTOM_VISITING_REWARD;
|
|
||||||
ret->rewardableObjectInfo.init(source, ret->getBaseTextID());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//MODS COMPATIBILITY FOR 0.96
|
//MODS COMPATIBILITY FOR 0.96
|
||||||
if(!ret->produce.nonZero())
|
if(!ret->produce.nonZero())
|
||||||
|
@ -68,11 +68,6 @@ class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFactio
|
|||||||
void loadRandomFaction();
|
void loadRandomFaction();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<typename R, typename K>
|
|
||||||
static R getMappedValue(const K key, const R defval, const std::map<K, R> & map, bool required = true);
|
|
||||||
template<typename R>
|
|
||||||
static R getMappedValue(const JsonNode & node, const R defval, const std::map<std::string, R> & map, bool required = true);
|
|
||||||
|
|
||||||
CTown * randomTown;
|
CTown * randomTown;
|
||||||
CFaction * randomFaction;
|
CFaction * randomFaction;
|
||||||
|
|
||||||
@ -98,25 +93,4 @@ protected:
|
|||||||
std::shared_ptr<CFaction> loadFromJson(const std::string & scope, const JsonNode & data, const std::string & identifier, size_t index) override;
|
std::shared_ptr<CFaction> loadFromJson(const std::string & scope, const JsonNode & data, const std::string & identifier, size_t index) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R, typename K>
|
|
||||||
R CTownHandler::getMappedValue(const K key, const R defval, const std::map<K, R> & map, bool required)
|
|
||||||
{
|
|
||||||
auto it = map.find(key);
|
|
||||||
|
|
||||||
if(it != map.end())
|
|
||||||
return it->second;
|
|
||||||
|
|
||||||
if(required)
|
|
||||||
logMod->warn("Warning: Property: '%s' is unknown. Correct the typo or update VCMI.", key);
|
|
||||||
return defval;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
R CTownHandler::getMappedValue(const JsonNode & node, const R defval, const std::map<std::string, R> & map, bool required)
|
|
||||||
{
|
|
||||||
if(!node.isNull() && node.getType() == JsonNode::JsonType::DATA_STRING)
|
|
||||||
return getMappedValue<R, std::string>(node.String(), defval, map, required);
|
|
||||||
return defval;
|
|
||||||
}
|
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CRewardableConstructor.h"
|
#include "CRewardableConstructor.h"
|
||||||
|
|
||||||
|
#include "../json/JsonUtils.h"
|
||||||
#include "../mapObjects/CRewardableObject.h"
|
#include "../mapObjects/CRewardableObject.h"
|
||||||
#include "../texts/CGeneralTextHandler.h"
|
#include "../texts/CGeneralTextHandler.h"
|
||||||
#include "../IGameCallback.h"
|
#include "../IGameCallback.h"
|
||||||
@ -24,6 +25,8 @@ void CRewardableConstructor::initTypeData(const JsonNode & config)
|
|||||||
if (!config["name"].isNull())
|
if (!config["name"].isNull())
|
||||||
VLC->generaltexth->registerString( config.getModScope(), getNameTextID(), config["name"].String());
|
VLC->generaltexth->registerString( config.getModScope(), getNameTextID(), config["name"].String());
|
||||||
|
|
||||||
|
JsonUtils::validate(config, "vcmi:rewardable", getJsonKey());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CRewardableConstructor::hasNameTextID() const
|
bool CRewardableConstructor::hasNameTextID() const
|
||||||
|
@ -476,7 +476,7 @@ void CTownRewardableBuilding::onHeroVisit(const CGHeroInstance *h) const
|
|||||||
cb->showBlockingDialog(&sd);
|
cb->showBlockingDialog(&sd);
|
||||||
};
|
};
|
||||||
|
|
||||||
if(!town->hasBuilt(bID) || cb->isVisitCoveredByAnotherQuery(town, h))
|
if(!town->hasBuilt(bID))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(!wasVisitedBefore(h))
|
if(!wasVisitedBefore(h))
|
||||||
|
@ -322,8 +322,9 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
|
|||||||
cb->heroVisitCastle(this, h);
|
cb->heroVisitCastle(this, h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(h->visitablePos() == visitablePos())
|
else
|
||||||
{
|
{
|
||||||
|
assert(h->visitablePos() == this->visitablePos());
|
||||||
bool commander_recover = h->commander && !h->commander->alive;
|
bool commander_recover = h->commander && !h->commander->alive;
|
||||||
if (commander_recover) // rise commander from dead
|
if (commander_recover) // rise commander from dead
|
||||||
{
|
{
|
||||||
@ -344,10 +345,6 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
|
|||||||
cb->showInfoDialog(&iw);
|
cb->showInfoDialog(&iw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
logGlobal->error("%s visits allied town of %s from different pos?", h->getNameTranslated(), getNameTranslated());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGTownInstance::onHeroLeave(const CGHeroInstance * h) const
|
void CGTownInstance::onHeroLeave(const CGHeroInstance * h) const
|
||||||
@ -556,14 +553,6 @@ void CGTownInstance::newTurn(vstd::RNG & rand) const
|
|||||||
for(const auto * manaVortex : getBonusingBuildings(BuildingSubID::MANA_VORTEX))
|
for(const auto * manaVortex : getBonusingBuildings(BuildingSubID::MANA_VORTEX))
|
||||||
cb->setObjPropertyValue(id, ObjProperty::STRUCTURE_CLEAR_VISITORS, manaVortex->indexOnTV); //reset visitors for Mana Vortex
|
cb->setObjPropertyValue(id, ObjProperty::STRUCTURE_CLEAR_VISITORS, manaVortex->indexOnTV); //reset visitors for Mana Vortex
|
||||||
|
|
||||||
//get Mana Vortex or Stables bonuses
|
|
||||||
//same code is in the CGameHandler::buildStructure method
|
|
||||||
if (garrisonHero != nullptr) //garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order
|
|
||||||
cb->visitCastleObjects(this, garrisonHero);
|
|
||||||
|
|
||||||
if (visitingHero != nullptr)
|
|
||||||
cb->visitCastleObjects(this, visitingHero);
|
|
||||||
|
|
||||||
if (tempOwner == PlayerColor::NEUTRAL) //garrison growth for neutral towns
|
if (tempOwner == PlayerColor::NEUTRAL) //garrison growth for neutral towns
|
||||||
{
|
{
|
||||||
std::vector<SlotID> nativeCrits; //slots
|
std::vector<SlotID> nativeCrits; //slots
|
||||||
|
@ -2431,12 +2431,27 @@ void EntitiesChanged::applyGs(CGameState * gs)
|
|||||||
void SetRewardableConfiguration::applyGs(CGameState * gs)
|
void SetRewardableConfiguration::applyGs(CGameState * gs)
|
||||||
{
|
{
|
||||||
auto * objectPtr = gs->getObjInstance(objectID);
|
auto * objectPtr = gs->getObjInstance(objectID);
|
||||||
|
|
||||||
|
if (!buildingID.hasValue())
|
||||||
|
{
|
||||||
auto * rewardablePtr = dynamic_cast<CRewardableObject *>(objectPtr);
|
auto * rewardablePtr = dynamic_cast<CRewardableObject *>(objectPtr);
|
||||||
|
|
||||||
assert(rewardablePtr);
|
assert(rewardablePtr);
|
||||||
|
|
||||||
rewardablePtr->configuration = configuration;
|
rewardablePtr->configuration = configuration;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto * townPtr = dynamic_cast<CGTownInstance*>(objectPtr);
|
||||||
|
CGTownBuilding * buildingPtr = nullptr;
|
||||||
|
|
||||||
|
for (CGTownBuilding * building : townPtr->bonusingBuildings)
|
||||||
|
if (building->getBuildingType() == buildingID)
|
||||||
|
buildingPtr = building;
|
||||||
|
|
||||||
|
auto * rewardablePtr = dynamic_cast<CTownRewardableBuilding *>(buildingPtr);
|
||||||
|
assert(rewardablePtr);
|
||||||
|
rewardablePtr->configuration = configuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SetBankConfiguration::applyGs(CGameState * gs)
|
void SetBankConfiguration::applyGs(CGameState * gs)
|
||||||
{
|
{
|
||||||
|
@ -631,10 +631,21 @@ void CGameHandler::onPlayerTurnStarted(PlayerColor which)
|
|||||||
events::PlayerGotTurn::defaultExecute(serverEventBus.get(), which);
|
events::PlayerGotTurn::defaultExecute(serverEventBus.get(), which);
|
||||||
turnTimerHandler->onPlayerGetTurn(which);
|
turnTimerHandler->onPlayerGetTurn(which);
|
||||||
|
|
||||||
handleTimeEvents(which);
|
const auto * playerState = gs->getPlayerState(which);
|
||||||
|
|
||||||
for (auto t : getPlayerState(which)->towns)
|
handleTimeEvents(which);
|
||||||
|
for (auto t : playerState->towns)
|
||||||
handleTownEvents(t);
|
handleTownEvents(t);
|
||||||
|
|
||||||
|
for (auto t : playerState->towns)
|
||||||
|
{
|
||||||
|
//garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order
|
||||||
|
if (t->garrisonHero != nullptr)
|
||||||
|
objectVisited(t, t->garrisonHero);
|
||||||
|
|
||||||
|
if (t->visitingHero != nullptr)
|
||||||
|
objectVisited(t, t->visitingHero);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::onPlayerTurnEnded(PlayerColor which)
|
void CGameHandler::onPlayerTurnEnded(PlayerColor which)
|
||||||
@ -1517,12 +1528,15 @@ void CGameHandler::takeCreatures(ObjectInstanceID objid, const std::vector<CStac
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)
|
void CGameHandler::heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)
|
||||||
|
{
|
||||||
|
if (obj->visitingHero != hero && obj->garrisonHero != hero)
|
||||||
{
|
{
|
||||||
HeroVisitCastle vc;
|
HeroVisitCastle vc;
|
||||||
vc.hid = hero->id;
|
vc.hid = hero->id;
|
||||||
vc.tid = obj->id;
|
vc.tid = obj->id;
|
||||||
vc.flags |= 1;
|
vc.flags |= 1;
|
||||||
sendAndApply(&vc);
|
sendAndApply(&vc);
|
||||||
|
}
|
||||||
visitCastleObjects(obj, hero);
|
visitCastleObjects(obj, hero);
|
||||||
giveSpells (obj, hero);
|
giveSpells (obj, hero);
|
||||||
|
|
||||||
@ -2487,9 +2501,9 @@ bool CGameHandler::buildStructure(ObjectInstanceID tid, BuildingID requestedID,
|
|||||||
changeFogOfWar(t->getSightCenter(), t->getSightRadius(), t->getOwner(), ETileVisibility::REVEALED);
|
changeFogOfWar(t->getSightCenter(), t->getSightRadius(), t->getOwner(), ETileVisibility::REVEALED);
|
||||||
|
|
||||||
if(t->garrisonHero) //garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order
|
if(t->garrisonHero) //garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order
|
||||||
visitCastleObjects(t, t->garrisonHero);
|
objectVisited(t, t->garrisonHero);
|
||||||
if(t->visitingHero)
|
if(t->visitingHero)
|
||||||
visitCastleObjects(t, t->visitingHero);
|
objectVisited(t, t->visitingHero);
|
||||||
|
|
||||||
checkVictoryLossConditionsForPlayer(t->tempOwner);
|
checkVictoryLossConditionsForPlayer(t->tempOwner);
|
||||||
return true;
|
return true;
|
||||||
|
@ -242,10 +242,7 @@ bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTy
|
|||||||
gameHandler->giveResource(player, EGameResID::GOLD, -GameConstants::HERO_GOLD_COST);
|
gameHandler->giveResource(player, EGameResID::GOLD, -GameConstants::HERO_GOLD_COST);
|
||||||
|
|
||||||
if(town)
|
if(town)
|
||||||
{
|
gameHandler->objectVisited(town, recruitedHero);
|
||||||
gameHandler->visitCastleObjects(town, recruitedHero);
|
|
||||||
gameHandler->giveSpells(town, recruitedHero);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If new hero has scouting he might reveal more terrain than we saw before
|
// If new hero has scouting he might reveal more terrain than we saw before
|
||||||
gameHandler->changeFogOfWar(recruitedHero->getSightCenter(), recruitedHero->getSightRadius(), player, ETileVisibility::REVEALED);
|
gameHandler->changeFogOfWar(recruitedHero->getSightCenter(), recruitedHero->getSightRadius(), player, ETileVisibility::REVEALED);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user