Browse Source

- Implementation of overrides for towns
- Converted dwellings.json into new format
- Implemented "mapObject" entry in town format
- Removed capital/fort/village fields from town in favor of overrides

Ivan Savenko 11 years ago
parent
commit
836c466f81

+ 1 - 1
client/CKingdomInterface.cpp

@@ -500,7 +500,7 @@ void CKingdomInterface::generateObjectsList(const std::vector<const CGObjectInst
 			OwnedObjectInfo &info = visibleObjects[object->subID];
 			if (info.count++ == 0)
 			{
-				info.hoverText = CGI->creh->creatures[CGI->objh->cregens.find(object->subID)->second]->namePl;
+				info.hoverText = object->getHoverText();
 				info.imageID = object->subID;
 			}
 		}

+ 0 - 108
config/dwellings.json

@@ -1,108 +0,0 @@
-{
-	// Indicate which dwelling produces which creature
-	// Note that it is 1<->n connection since
-	// a creature can be produced by more than one dwelling.
-	"dwellings": [
-		{ "dwelling": 0, "creature": 106 },
-		{ "dwelling": 1, "creature": 96 },
-		{ "dwelling": 2, "creature": 74 },
-		{ "dwelling": 3, "creature": 66 },
-		{ "dwelling": 4, "creature": 68 },
-		{ "dwelling": 5, "creature": 10 },
-		{ "dwelling": 6, "creature": 14 },
-		{ "dwelling": 7, "creature": 112 },
-		{ "dwelling": 8, "creature": 12 },
-		{ "dwelling": 9, "creature": 94 },
-		{ "dwelling": 10, "creature": 54 },
-		{ "dwelling": 11, "creature": 104 },
-		{ "dwelling": 12, "creature": 16 },
-		{ "dwelling": 13, "creature": 113 },
-		{ "dwelling": 14, "creature": 52 },
-		{ "dwelling": 15, "creature": 18 },
-		{ "dwelling": 16, "creature": 114 },
-		{ "dwelling": 17, "creature": 30 },
-		{ "dwelling": 18, "creature": 36 },
-		{ "dwelling": 19, "creature": 86 },
-		{ "dwelling": 20, "creature": 98 },
-		{ "dwelling": 21, "creature": 84 },
-		{ "dwelling": 22, "creature": 44 },
-		{ "dwelling": 23, "creature": 102 },
-		{ "dwelling": 24, "creature": 26 },
-		{ "dwelling": 25, "creature": 4 },
-		{ "dwelling": 26, "creature": 72 },
-		{ "dwelling": 27, "creature": 46 },
-		{ "dwelling": 28, "creature": 110 },
-		{ "dwelling": 29, "creature": 42 },
-		{ "dwelling": 30, "creature": 100 },
-		{ "dwelling": 31, "creature": 34 },
-		{ "dwelling": 32, "creature": 80 },
-		{ "dwelling": 33, "creature": 76 },
-		{ "dwelling": 34, "creature": 78 },
-		{ "dwelling": 35, "creature": 8 },
-		{ "dwelling": 36, "creature": 38 },
-		{ "dwelling": 37, "creature": 48 },
-		{ "dwelling": 38, "creature": 90 },
-		{ "dwelling": 39, "creature": 88 },
-		{ "dwelling": 40, "creature": 50 },
-		{ "dwelling": 41, "creature": 82 },
-		{ "dwelling": 42, "creature": 92 },
-		{ "dwelling": 43, "creature": 28 },
-		{ "dwelling": 44, "creature": 40 },
-		{ "dwelling": 45, "creature": 22 },
-		{ "dwelling": 46, "creature": 70 },
-		{ "dwelling": 47, "creature": 115 },
-		{ "dwelling": 48, "creature": 60 },
-		{ "dwelling": 49, "creature": 108 },
-		{ "dwelling": 50, "creature": 20 },
-		{ "dwelling": 51, "creature": 24 },
-		{ "dwelling": 52, "creature": 64 },
-		{ "dwelling": 53, "creature": 62 },
-		{ "dwelling": 54, "creature": 56 },
-		{ "dwelling": 55, "creature": 58 },
-		{ "dwelling": 56, "creature": 0 },
-		{ "dwelling": 57, "creature": 2 },
-		{ "dwelling": 58, "creature": 6 },
-		{ "dwelling": 59, "creature": 118 },
-		{ "dwelling": 60, "creature": 120 },
-		{ "dwelling": 61, "creature": 130 },
-		{ "dwelling": 62, "creature": 132 },
-		{ "dwelling": 63, "creature": 133 },
-		{ "dwelling": 64, "creature": 134 },
-		{ "dwelling": 65, "creature": 135 },
-		{ "dwelling": 66, "creature": 136 },
-		{ "dwelling": 67, "creature": 137 },
-		{ "dwelling": 68, "creature": 24 },
-		{ "dwelling": 69, "creature": 112 },
-		{ "dwelling": 70, "creature": 113 },
-		{ "dwelling": 71, "creature": 114 },
-		{ "dwelling": 72, "creature": 115 },
-		{ "dwelling": 73, "creature": 138 },
-		{ "dwelling": 74, "creature": 139 },
-		{ "dwelling": 75, "creature": 140 },
-		{ "dwelling": 76, "creature": 141 },
-		{ "dwelling": 77, "creature": 142 },
-		{ "dwelling": 78, "creature": 143 },
-		{ "dwelling": 79, "creature": 144 },
-		{ "dwelling": 80, "creature": 150 },
-		{ "dwelling": 81, "creature": 151 },
-		{ "dwelling": 82, "creature": 152 },
-		{ "dwelling": 83, "creature": 153 },
-		{ "dwelling": 84, "creature": 154 },
-		{ "dwelling": 85, "creature": 155 },
-		{ "dwelling": 86, "creature": 156 },
-		{ "dwelling": 87, "creature": 157 },
-		{ "dwelling": 88, "creature": 158 },
-		{ "dwelling": 89, "creature": 171 },
-		{ "dwelling": 90, "creature": 170 },
-		{ "dwelling": 91, "creature": 168 },
-		{ "dwelling": 92, "creature": 172 },
-		{ "dwelling": 93, "creature": 164 },
-		{ "dwelling": 94, "creature": 169 },
-		{ "dwelling": 95, "creature": 173 },
-		{ "dwelling": 96, "creature": 192 },
-		{ "dwelling": 97, "creature": 193 },
-		{ "dwelling": 98, "creature": 194 },
-		{ "dwelling": 99, "creature": 195 },
-		{ "dwelling": 100, "creature": 196 }
-	]
-}

+ 6 - 4
config/factions/castle.json

@@ -66,11 +66,13 @@
 		},
 		"town" :
 		{
-			"adventureMap" :
+			"mapObject" :
 			{
-				"castle" : "AVCcasx0.def",
-				"village" : "AVCCAST0.DEF",
-				"capitol" : "AVCCASZ0.DEF"
+				"templates" : {
+					"castle" :  { "animation" : "AVCcasx0.def" },
+					"village" : { "animation" : "AVCCAST0.DEF" },
+					"capitol" : { "animation" : "AVCCASZ0.DEF" }
+				}
 			},
 			"structures" :
 			{

+ 6 - 4
config/factions/conflux.json

@@ -66,11 +66,13 @@
 		},
 		"town" :
 		{
-			"adventureMap" :
+			"mapObject" :
 			{
-				"castle" : "avchforx.def",
-				"village" : "AVCHFOR0.DEF",
-				"capitol" : "AVCHFORZ.DEF"
+				"templates" : {
+					"castle" :  { "animation" : "avchforx.def" },
+					"village" : { "animation" : "AVCHFOR0.DEF" },
+					"capitol" : { "animation" : "AVCHFORZ.DEF" }
+				}
 			},
 			"structures" :
 			{

+ 6 - 4
config/factions/dungeon.json

@@ -66,11 +66,13 @@
 		},
 		"town" :
 		{
-			"adventureMap" :
+			"mapObject" :
 			{
-				"castle" : "AVCdunx0.def",
-				"village" : "AVCDUNG0.DEF",
-				"capitol" : "AVCDUNZ0.DEF"
+				"templates" : {
+					"castle" :  { "animation" : "AVCdunx0.def" },
+					"village" : { "animation" : "AVCDUNG0.DEF" },
+					"capitol" : { "animation" : "AVCDUNZ0.DEF" }
+				}
 			},
 			"structures" :
 			{

+ 6 - 4
config/factions/fortress.json

@@ -66,11 +66,13 @@
 		},
 		"town" :
 		{
-			"adventureMap" :
+			"mapObject" :
 			{
-				"castle" : "AVCftrx0.def",
-				"village" : "AVCFTRT0.DEF",
-				"capitol" : "AVCFORZ0.DEF"
+				"templates" : {
+					"castle" :  { "animation" : "AVCftrx0.def" },
+					"village" : { "animation" : "AVCFTRT0.DEF" },
+					"capitol" : { "animation" : "AVCFORZ0.DEF" }
+				}
 			},
 			"structures" :
 			{

+ 6 - 4
config/factions/inferno.json

@@ -66,11 +66,13 @@
 		},
 		"town" :
 		{
-			"adventureMap" :
+			"mapObject" :
 			{
-				"castle" : "AVCinfx0.def",
-				"village" : "AVCINFT0.DEF",
-				"capitol" : "AVCINFZ0.DEF"
+				"templates" : {
+					"castle" :  { "animation" : "AVCinfx0.def" },
+					"village" : { "animation" : "AVCINFT0.DEF" },
+					"capitol" : { "animation" : "AVCINFZ0.DEF" }
+				}
 			},
 			"structures" :
 			{

+ 6 - 4
config/factions/necropolis.json

@@ -66,11 +66,13 @@
 		},
 		"town" :
 		{
-			"adventureMap" :
+			"mapObject" :
 			{
-				"castle" : "AVCnecx0.def",
-				"village" : "AVCNECR0.DEF",
-				"capitol" : "AVCNECZ0.DEF"
+				"templates" : {
+					"castle" :  { "animation" : "AVCnecx0.def" },
+					"village" : { "animation" : "AVCNECR0.DEF" },
+					"capitol" : { "animation" : "AVCNECZ0.DEF" }
+				}
 			},
 			"structures" :
 			{

+ 6 - 4
config/factions/rampart.json

@@ -66,11 +66,13 @@
 		},
 		"town" :
 		{
-			"adventureMap" :
+			"mapObject" :
 			{
-				"castle" : "AVCramx0.def",
-				"village" : "AVCRAMP0.DEF",
-				"capitol" : "AVCRAMZ0.DEF"
+				"templates" : {
+					"castle" :  { "animation" : "AVCramx0.def" },
+					"village" : { "animation" : "AVCRAMP0.DEF" },
+					"capitol" : { "animation" : "AVCRAMZ0.DEF" }
+				}
 			},
 			"structures" :
 			{

+ 6 - 4
config/factions/stronghold.json

@@ -66,11 +66,13 @@
 		},
 		"town" :
 		{
-			"adventureMap" :
+			"mapObject" :
 			{
-				"castle" : "AVCstrx0.def",
-				"village" : "AVCSTRO0.DEF",
-				"capitol" : "AVCSTRZ0.DEF"
+				"templates" : {
+					"castle" :  { "animation" : "AVCstrx0.def" },
+					"village" : { "animation" : "AVCSTRO0.DEF" },
+					"capitol" : { "animation" : "AVCSTRZ0.DEF" }
+				}
 			},
 			"structures" :
 			{

+ 6 - 4
config/factions/tower.json

@@ -66,11 +66,13 @@
 		},
 		"town" :
 		{
-			"adventureMap" :
+			"mapObject" :
 			{
-				"castle" : "AVCtowx0.def",
-				"village" : "AVCTOWR0.DEF",
-				"capitol" : "AVCTOWZ0.DEF"
+				"templates" : {
+					"castle" :  { "animation" : "AVCtowx0.def" },
+					"village" : { "animation" : "AVCTOWR0.DEF" },
+					"capitol" : { "animation" : "AVCTOWZ0.DEF" }
+				}
 			},
 			"structures" :
 			{

+ 1 - 0
config/gameConfig.json

@@ -49,6 +49,7 @@
 	[
 		"config/objects/generic.json",
 		"config/objects/moddables.json",
+		"config/objects/dwellings.json",
 		"config/objects/rewardable.json"
 	],
 

+ 126 - 0
config/objects/dwellings.json

@@ -0,0 +1,126 @@
+{
+	"creatureGeneratorCommon" : {
+		"index" :17,
+		"handler": "dwelling",
+		"base" : {
+			"base" : {
+				"visitableFrom" : [ "---", "+++", "+++" ],
+				"mask" : [ "VVV", "VBB", "VAA" ]
+			}
+		},
+		"types" : {
+			"basiliskPit" :      { "index" : 0,  "creatures" :  [ [ "basilisk" ] ] },
+			"behemothCrag" :     { "index" : 1,  "creatures" :  [ [ "behemoth" ] ], "guards" : true },
+			"pillarOfEyes" :     { "index" : 2,  "creatures" :  [ [ "beholder" ] ] },
+			"hallOfDarkness" :   { "index" : 3,  "creatures" :  [ [ "blackKnight" ] ], "guards" : true },
+			"dragonVault" :      { "index" : 4,  "creatures" :  [ [ "boneDragon" ] ], "guards" : true },
+			"trainingGrounds" :  { "index" : 5,  "creatures" :  [ [ "cavalier" ] ], "guards" : true },
+			"centaurStables" :   { "index" : 6,  "creatures" :  [ [ "centaur" ] ] },
+			"airConflux" :       { "index" : 7,  "creatures" :  [ [ "airElemental" ] ] },
+			"portalOfGlory" :    { "index" : 8,  "creatures" :  [ [ "angel" ] ], "guards" : true },
+			"cyclopsCave" :      { "index" : 9,  "creatures" :  [ [ "cyclop" ] ], "guards" : true },
+			"forsakenPalace" :   { "index" : 10, "creatures" : [ [ "devil" ] ], "guards" : true },
+			"serpentFlyHive" :   { "index" : 11, "creatures" : [ [ "serpentFly" ] ] },
+			"dwarfCottage" :     { "index" : 12, "creatures" : [ [ "dwarf" ] ] },
+			"earthConflux" :     { "index" : 13, "creatures" : [ [ "earthElemental" ] ], "guards" : true },
+			"fireLake" :         { "index" : 14, "creatures" : [ [ "efreet" ] ], "guards" : true },
+			"homestead" :        { "index" : 15, "creatures" : [ [ "woodElf" ] ] },
+			"fireConflux" :      { "index" : 16, "creatures" : [ [ "fireElemental" ] ] },
+			"parapet" :          { "index" : 17, "creatures" : [ [ "stoneGargoyle" ] ] },
+			"altarOfWishes" :    { "index" : 18, "creatures" : [ [ "genie" ] ], "guards" : true },
+			"wolfPen" :          { "index" : 19, "creatures" : [ [ "goblinWolfRider" ] ] },
+			"gnollHut" :         { "index" : 20, "creatures" : [ [ "gnoll" ] ] },
+			"goblinBarracks" :   { "index" : 21, "creatures" : [ [ "goblin" ] ] },
+			"hallOfSins" :       { "index" : 22, "creatures" : [ [ "gog" ] ] },
+			"gorgonLair" :       { "index" : 23, "creatures" : [ [ "gorgon" ] ], "guards" : true },
+			"dragonCliffs" :     { "index" : 24, "creatures" : [ [ "greenDragon" ] ], "guards" : true },
+			"griffinTower" :     { "index" : 25, "creatures" : [ [ "griffin" ] ] },
+			"harpyLoft" :        { "index" : 26, "creatures" : [ [ "harpy" ] ] },
+			"kennels" :          { "index" : 27, "creatures" : [ [ "hellHound" ] ] },
+			"hydraPond" :        { "index" : 28, "creatures" : [ [ "hydra" ] ], "guards" : true },
+			"impCrucible" :      { "index" : 29, "creatures" : [ [ "imp" ] ] },
+			"lizardDen" :        { "index" : 30, "creatures" : [ [ "lizardman" ] ] },
+			"mageTower" :        { "index" : 31, "creatures" : [ [ "mage" ] ] },
+			"manticoreLair" :    { "index" : 32, "creatures" : [ [ "manticore" ] ], "guards" : true },
+			"medusaChapel" :     { "index" : 33, "creatures" : [ [ "medusa" ] ] },
+			"labyrinth" :        { "index" : 34, "creatures" : [ [ "minotaur" ] ], "guards" : true },
+			"monastery" :        { "index" : 35, "creatures" : [ [ "monk" ] ], "guards" : true },
+			"goldenPavilion" :   { "index" : 36, "creatures" : [ [ "naga" ] ], "guards" : true },
+			"demonGate" :        { "index" : 37, "creatures" : [ [ "demon" ] ] },
+			"ogreFort" :         { "index" : 38, "creatures" : [ [ "ogre" ] ] },
+			"orcTower" :         { "index" : 39, "creatures" : [ [ "orc" ] ] },
+			"hellHole" :         { "index" : 40, "creatures" : [ [ "pitFiend" ] ], "guards" : true },
+			"dragonCave" :       { "index" : 41, "creatures" : [ [ "redDragon" ] ], "guards" : true },
+			"cliffNest" :        { "index" : 42, "creatures" : [ [ "roc" ] ], "guards" : true },
+			"workshop" :         { "index" : 43, "creatures" : [ [ "gremlin" ] ] },
+			"cloudTemple" :      { "index" : 44, "creatures" : [ [ "giant" ] ], "guards" : true },
+			"dendroidArches" :   { "index" : 45, "creatures" : [ [ "dendroidGuard" ] ], "guards" : true },
+			"warren" :           { "index" : 46, "creatures" : [ [ "troglodyte" ] ] },
+			"waterConflux" :     { "index" : 47, "creatures" : [ [ "waterElemental" ] ] },
+			"tombOfSouls" :      { "index" : 48, "creatures" : [ [ "wight" ] ] },
+			"wyvernNest" :       { "index" : 49, "creatures" : [ [ "wyvern" ] ], "guards" : true },
+			"enchantedSpring" :  { "index" : 50, "creatures" : [ [ "pegasus" ] ] },
+			"unicornGladeBig" :  { "index" : 51, "creatures" : [ [ "unicorn" ] ], "guards" : true },
+			"mausoleum" :        { "index" : 52, "creatures" : [ [ "lich" ] ], "guards" : true },
+			"estate" :           { "index" : 53, "creatures" : [ [ "vampire" ] ] },
+			"cursedTemple" :     { "index" : 54, "creatures" : [ [ "skeleton" ] ] },
+			"graveyard" :        { "index" : 55, "creatures" : [ [ "walkingDead" ] ] },
+			"guardhouse" :       { "index" : 56, "creatures" : [ [ "pikeman" ] ] },
+			"archersTower" :     { "index" : 57, "creatures" : [ [ "archer" ] ] },
+			"barracks" :         { "index" : 58, "creatures" : [ [ "swordsman" ] ] },
+			"magicLantern" :     { "index" : 59, "creatures" : [ [ "pixie" ] ] },
+			"altarOfThought" :   { "index" : 60, "creatures" : [ [ "psychicElemental" ] ], "guards" : true },
+			"pyre" :             { "index" : 61, "creatures" : [ [ "firebird" ] ], "guards" : true },
+			"frozenCliffs" :     { "index" : 62, "creatures" : [ [ "azureDragon" ] ], "guards" : true },
+			"crystalCavern" :    { "index" : 63, "creatures" : [ [ "crystalDragon" ] ], "guards" : true },
+			"magicForest" :      { "index" : 64, "creatures" : [ [ "fairieDragon" ] ], "guards" : true },
+			"sulfurousLair" :    { "index" : 65, "creatures" : [ [ "rustDragon" ] ], "guards" : true },
+			"enchantersHollow" : { "index" : 66, "creatures" : [ [ "enchanter" ] ], "guards" : true },
+			"treetopTower" :     { "index" : 67, "creatures" : [ [ "sharpshooter" ] ], "guards" : true },
+			"unicornGlade" :     { "index" : 68, "creatures" : [ [ "unicorn" ] ], "guards" : true },
+			"altarOfAir" :       { "index" : 69, "creatures" : [ [ "airElemental" ] ] },
+			"altarOfEarth" :     { "index" : 70, "creatures" : [ [ "earthElemental" ] ], "guards" : true },
+			"altarOfFire" :      { "index" : 71, "creatures" : [ [ "fireElemental" ] ] },
+			"altarOfWater" :     { "index" : 72, "creatures" : [ [ "waterElemental" ] ] },
+			"thatchedHut" :      { "index" : 73, "creatures" : [ [ "halfling" ] ] },
+			"hovel" :            { "index" : 74, "creatures" : [ [ "peasant" ] ] },
+			"boarGlen" :         { "index" : 75, "creatures" : [ [ "boar" ] ] },
+			"tombOfCurses" :     { "index" : 76, "creatures" : [ [ "mummy" ] ] },
+			"nomadTent" :        { "index" : 77, "creatures" : [ [ "nomad" ] ] },
+			"rogueCavern" :      { "index" : 78, "creatures" : [ [ "rogue" ] ] },
+			"trollBridge" :      { "index" : 79, "creatures" : [ [ "troll" ] ], "guards" : true }
+		}
+	},
+	// subtype: unique special dwellings - golem factory and elemental conflux
+	"creatureGeneratorSpecial" : {
+		"index" :20,
+		"handler": "dwelling",
+		"types" : {
+			"elementalConflux" : {
+				"index" : 0,
+				"creatures" : [ // 4 separate "levels" to give them separate growth
+					[ "airElemental" ],
+					[ "waterElemental" ],
+					[ "fireElemental" ],
+					[ "earthElemental" ]
+				],
+				"guards" : {
+					"earthElemental" : 12
+				}
+			},
+			"golemFactory" : {
+				"index" : 1,
+				"creatures" : [ // 4 separate "levels" to give them separate growth
+					[ "ironGolem" ],
+					[ "stoneGolem" ],
+					[ "goldGolem" ],
+					[ "diamondGolem" ]
+				],
+				"guards" : {
+					"goldGolem" : 9,
+					"diamondGolem" : 6
+				}
+			}
+		}
+	},
+}

+ 11 - 16
config/objects/moddables.json

@@ -48,6 +48,16 @@
 				"visitableFrom" : [ "+++", "+-+", "+++" ],
 				"mask" : [ "VA" ]
 			}
+		},
+		"types" : {
+			"wood" :    { "index" : 0 },
+			"mercury" : { "index" : 1 },
+			"ore" :     { "index" : 2 },
+			"sulfur" :  { "index" : 3 },
+			"crystal" : { "index" : 4 },
+			"gems" :    { "index" : 5 },
+			"gold" :    { "index" : 6 },
+			"mithril" : { "index" : 7 } // TODO: move to WoG?
 		}
 	},
 	
@@ -56,7 +66,7 @@
 		"index" :98,
 		"handler": "town",
 		"base" : {
-			"filter" : {
+			"filters" : {
 				// village image - fort not present
 				"village" : [ "noneOf", [ "fort" ] ],
 				// fort image - fort is here but not capitol
@@ -125,21 +135,6 @@
 	// subtype: faction ID
 	"randomDwellingFaction"			: { "index" :218, "handler": "dwelling" },
 
-	// subtype: not well defined, describes various dwellings that can be placed as random
-	"creatureGeneratorCommon" : {
-		"index" :17,
-		"handler": "dwelling",
-		"base" : {
-			"base" : {
-				"visitableFrom" : [ "---", "+++", "+++" ],
-				"mask" : [ "VVV", "VBB", "VAA" ]
-			}
-		}
-	},
-	
-	// subtype: unique special dwellings - golem factory, elemental conflux
-	"creatureGeneratorSpecial"		: { "index" :20, "handler": "dwelling" },
-	
 	// don't have subtypes (at least now), but closely connected to this objects
 	"spellScroll"					: { "index" :93, "handler": "artifact" },
 	"heroPlaceholder"				: { "index" :214, "handler": "heroPlaceholder" }

+ 17 - 12
lib/CGameState.cpp

@@ -622,23 +622,28 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
 			std::pair<Obj, int> result(Obj::NO_OBJ, -1);
 			CreatureID cid = VLC->townh->factions[faction]->town->creatures[level][0];
 
-			//golem factory is not in list of cregens but can be placed as random object
-			static const CreatureID factoryCreatures[] = {CreatureID::STONE_GOLEM, CreatureID::IRON_GOLEM,
-				CreatureID::GOLD_GOLEM, CreatureID::DIAMOND_GOLEM};
-			std::vector<CreatureID> factory(factoryCreatures, factoryCreatures + ARRAY_COUNT(factoryCreatures));
-			if (vstd::contains(factory, cid))
-				result = std::make_pair(Obj::CREATURE_GENERATOR4, 1);
-
 			//NOTE: this will pick last dwelling with this creature (Mantis #900)
 			//check for block map equality is better but more complex solution
-			for(auto &iter : VLC->objh->cregens)
-				if (iter.second == cid)
-					result = std::make_pair(Obj::CREATURE_GENERATOR1, iter.first);
+			auto testID = [&](Obj primaryID) -> void
+			{
+				auto dwellingIDs = VLC->objtypeh->knownSubObjects(primaryID);
+				for (si32 entry : dwellingIDs)
+				{
+					auto handler = dynamic_cast<const CDwellingInstanceConstructor*>(VLC->objtypeh->getHandlerFor(primaryID, entry).get());
+
+					if (handler->producesCreature(VLC->creh->creatures[cid]))
+						result = std::make_pair(primaryID, entry);
+				}
+			};
+
+			testID(Obj::CREATURE_GENERATOR1);
+			if (result.first == Obj::NO_OBJ)
+				testID(Obj::CREATURE_GENERATOR4);
 
 			if (result.first == Obj::NO_OBJ)
 			{
-                logGlobal->errorStream() << "Error: failed to find creature for dwelling of "<< int(faction) << " of level " << int(level);
-				result = std::make_pair(Obj::CREATURE_GENERATOR1, RandomGeneratorUtil::nextItem(VLC->objh->cregens, rand)->first);
+				logGlobal->errorStream() << "Error: failed to find dwelling for "<< VLC->townh->factions[faction]->name << " of level " << int(level);
+				result = std::make_pair(Obj::CREATURE_GENERATOR1, *RandomGeneratorUtil::nextItem(VLC->objtypeh->knownSubObjects(Obj::CREATURE_GENERATOR1), rand));
 			}
 
 			return result;

+ 9 - 6
lib/CModHandler.cpp

@@ -128,7 +128,7 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(std::string scope, std::
 	if (idList.size() == 1)
 		return idList.front().id;
 	if (!silent)
-		logGlobal->errorStream() << "Failed to resolve identifier " << name << " from mod " << scope;
+		logGlobal->errorStream() << "Failed to resolve identifier " << name << " of type " << type << " from mod " << scope;
 
 	return boost::optional<si32>();
 }
@@ -141,7 +141,7 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(std::string type, const
 	if (idList.size() == 1)
 		return idList.front().id;
 	if (!silent)
-		logGlobal->errorStream() << "Failed to resolve identifier " << name.String() << " from mod " << type;
+		logGlobal->errorStream() << "Failed to resolve identifier " << name.String() << " of type " << type << " from mod " << name.meta;
 
 	return boost::optional<si32>();
 }
@@ -155,7 +155,7 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(const JsonNode & name, b
 	if (idList.size() == 1)
 		return idList.front().id;
 	if (!silent)
-		logGlobal->errorStream() << "Failed to resolve identifier " << name.String() << " from mod " << name.meta;
+		logGlobal->errorStream() << "Failed to resolve identifier " << name.String() << " of type " << pair2.first << " from mod " << name.meta;
 
 	return boost::optional<si32>();
 }
@@ -223,7 +223,9 @@ bool CIdentifierStorage::resolveIdentifier(const ObjectCallback & request)
 	}
 
 	if (request.optional && identifiers.empty()) // failed to resolve optinal ID
+	{
 		return true;
+	}
 
 	// error found. Try to generate some debug info
 	if (identifiers.size() == 0)
@@ -244,16 +246,17 @@ void CIdentifierStorage::finalize()
 {
 	bool errorsFound = false;
 
-	for(const ObjectCallback & request : scheduledRequests)
+	//Note: we may receive new requests during resolution phase -> end may change -> range for can't be used
+	for(auto it = scheduledRequests.begin(); it != scheduledRequests.end(); it++)
 	{
-		errorsFound |= !resolveIdentifier(request);
+		errorsFound |= !resolveIdentifier(*it);
 	}
 
 	if (errorsFound)
 	{
 		for(auto object : registeredObjects)
 		{
-			logGlobal->traceStream() << object.first << " -> " << object.second.id;
+			logGlobal->traceStream() << object.second.scope << " : " << object.first << " -> " << object.second.id;
 		}
 		logGlobal->errorStream() << "All known identifiers were dumped into log file";
 	}

+ 28 - 25
lib/CTownHandler.cpp

@@ -554,10 +554,6 @@ void CTownHandler::loadClientData(CTown &town, const JsonNode & source)
 		info.tavernVideo = "TAVERN.BIK";
 	//end of legacy assignment 
 
-	info.advMapVillage = source["adventureMap"]["village"].String();
-	info.advMapCastle  = source["adventureMap"]["castle"].String();
-	info.advMapCapitol = source["adventureMap"]["capitol"].String();
-
 	loadTownHall(town,   source["hallSlots"]);
 	loadStructures(town, source["structures"]);
 	loadSiegeScreen(town, source["siege"]);
@@ -723,6 +719,8 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
 	auto object = loadFromJson(data, name);
 
 	object->index = factions.size();
+	factions.push_back(object);
+
 	if (object->town)
 	{
 		auto & info = object->town->clientInfo;
@@ -730,9 +728,16 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
 		info.icons[0][1] = 8 + object->index * 4 + 1;
 		info.icons[1][0] = 8 + object->index * 4 + 2;
 		info.icons[1][1] = 8 + object->index * 4 + 3;
-	}
 
-	factions.push_back(object);
+		VLC->modh->identifiers.requestIdentifier(scope, "object", "town", [=](si32 index)
+		{
+			// register town once objects are loaded
+			JsonNode config = data["town"]["mapObject"];
+			config["faction"].String() = object->identifier;
+			config["faction"].meta = scope;
+			VLC->objtypeh->loadSubObject(object->identifier, config, index, object->index);
+		});
+	}
 
 	VLC->modh->identifiers.registerObject(scope, "faction", name, object->index);
 }
@@ -741,6 +746,9 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
 {
 	auto object = loadFromJson(data, name);
 	object->index = index;
+	assert(factions[index] == nullptr); // ensure that this id was not loaded before
+	factions[index] = object;
+
 	if (object->town)
 	{
 		auto & info = object->town->clientInfo;
@@ -748,10 +756,16 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
 		info.icons[0][1] = (GameConstants::F_NUMBER + object->index) * 2 + 1;
 		info.icons[1][0] = object->index * 2 + 0;
 		info.icons[1][1] = object->index * 2 + 1;
-	}
 
-	assert(factions[index] == nullptr); // ensure that this id was not loaded before
-	factions[index] = object;
+		VLC->modh->identifiers.requestIdentifier(scope, "object", "town", [=](si32 index)
+		{
+			// register town once objects are loaded
+			JsonNode config = data["town"]["mapObject"];
+			config["faction"].String() = object->identifier;
+			config["faction"].meta = scope;
+			VLC->objtypeh->loadSubObject(object->identifier, config, index, object->index);
+		});
+	}
 
 	VLC->modh->identifiers.registerObject(scope, "faction", name, object->index);
 }
@@ -761,31 +775,20 @@ void CTownHandler::afterLoadFinalization()
 	initializeRequirements();
 	for (CFaction * fact : factions)
 	{
+		// MODS COMPATIBILITY FOR 0.96
 		if (fact->town)
 		{
-			VLC->objtypeh->loadSubObject(fact->identifier, JsonNode(), Obj::TOWN, fact->index);
-			if (!fact->town->clientInfo.advMapCastle.empty())
-			{
-				JsonNode templ;
-				templ["animation"].String() = fact->town->clientInfo.advMapCastle;
-				VLC->objtypeh->getHandlerFor(Obj::TOWN, fact->index)->addTemplate(templ);
-			}
-
 			assert(fact->town->dwellings.size() == fact->town->dwellingNames.size());
 			for (size_t i=0; i<fact->town->dwellings.size(); i++)
 			{
 				//both unupgraded and upgraded get same dwelling
 				for (auto cre : fact->town->creatures[i])
 				{
-					if (VLC->objh->cregens.count(cre) == 0)
-					{
-						JsonNode templ;
-						templ["animation"].String() = fact->town->dwellings[i];
+					JsonNode templ;
+					templ["animation"].String() = fact->town->dwellings[i];
 
-						VLC->objtypeh->loadSubObject("", JsonNode(), Obj::CREATURE_GENERATOR1, 80 + cre);
-						VLC->objtypeh->getHandlerFor(Obj::CREATURE_GENERATOR1, 80 + cre)->addTemplate(templ);
-						VLC->objh->cregens[80 + cre] = cre; //map of dwelling -> creature id
-					}
+					VLC->objtypeh->loadSubObject("", JsonNode(), Obj::CREATURE_GENERATOR1, 100 + cre);
+					VLC->objtypeh->getHandlerFor(Obj::CREATURE_GENERATOR1, 100 + cre)->addTemplate(templ);
 				 }
 			}
 		}

+ 1 - 5
lib/CTownHandler.h

@@ -190,10 +190,6 @@ public:
 		/// NOTE: index in vector is meaningless. Vector used instead of list for a bit faster access
 		std::vector<ConstTransitivePtr<CStructure> > structures;
 
-		std::string advMapVillage;
-		std::string advMapCastle;
-		std::string advMapCapitol;
-
 		std::string siegePrefix;
 		std::vector<Point> siegePositions;
 		CreatureID siegeShooter; // shooter creature ID
@@ -201,7 +197,7 @@ public:
 		template <typename Handler> void serialize(Handler &h, const int version)
 		{
 			h & icons & iconSmall & iconLarge & tavernVideo & musicTheme & townBackground & guildBackground & guildWindow & buildingsIcons & hallBackground;
-			h & advMapVillage & advMapCastle & advMapCapitol & hallSlots & structures;
+			h & hallSlots & structures;
 			h & siegePrefix & siegePositions & siegeShooter;
 		}
 	} clientInfo;

+ 1 - 1
lib/JsonNode.cpp

@@ -737,7 +737,7 @@ void JsonUtils::mergeCopy(JsonNode & dest, JsonNode source)
 
 void JsonUtils::inherit(JsonNode & descendant, const JsonNode & base)
 {
-	JsonNode inheritedNode(base);		
+	JsonNode inheritedNode(base);
 	merge(inheritedNode,descendant);
 	descendant.swap(inheritedNode);
 }

+ 2 - 2
lib/VCMI_Lib.cpp

@@ -45,11 +45,11 @@ DLL_LINKAGE void preinitDLL(CConsoleHandler *Console)
 
 DLL_LINKAGE void loadDLLClasses()
 {
-	try
+//	try
 	{
 		VLC->init();
 	}
-	HANDLE_EXCEPTION;
+//	HANDLE_EXCEPTION;
 }
 
 const IBonusTypeHandler * LibClasses::getBth() const

+ 11 - 48
lib/mapObjects/CGTownInstance.cpp

@@ -13,6 +13,7 @@
 
 #include "../NetPacks.h"
 #include "../CGeneralTextHandler.h"
+#include "../mapObjects/CObjectClassesHandler.h"
 
 using namespace boost::assign;
 
@@ -24,54 +25,18 @@ void CGDwelling::initObj()
 	switch(ID)
 	{
 	case Obj::CREATURE_GENERATOR1:
+	case Obj::CREATURE_GENERATOR4:
 		{
-			CreatureID crid = VLC->objh->cregens[subID];
-			const CCreature *crs = VLC->creh->creatures[crid];
+			VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, cb->gameState()->getRandomGenerator());
 
-			creatures.resize(1);
-			creatures[0].second.push_back(crid);
-			if (subID >= VLC->generaltexth->creGens.size()) //very messy workaround
-			{
-				auto & dwellingNames = VLC->townh->factions[crs->faction]->town->dwellingNames;
-				assert (dwellingNames.size() > crs->level - 1);
-				hoverName = dwellingNames[crs->level - 1];
-			}
-			else
-				hoverName = VLC->generaltexth->creGens[subID];
-			if(crs->level > 4)
-				putStack(SlotID(0), new CStackInstance(crs, (crs->growth) * 3));
 			if (getOwner() != PlayerColor::NEUTRAL)
 				cb->gameState()->players[getOwner()].dwellings.push_back (this);
 		}
-		break;
+			//putStack(SlotID(0), new CStackInstance(CreatureID::GOLD_GOLEM, 9));
+			//putStack(SlotID(1), new CStackInstance(CreatureID::DIAMOND_GOLEM, 6));
 
-	case Obj::CREATURE_GENERATOR4:
-		creatures.resize(4);
-		if(subID == 1) //Golem Factory
-		{
-			creatures[0].second.push_back(CreatureID::STONE_GOLEM);
-			creatures[1].second.push_back(CreatureID::IRON_GOLEM);
-			creatures[2].second.push_back(CreatureID::GOLD_GOLEM);
-			creatures[3].second.push_back(CreatureID::DIAMOND_GOLEM);
-			//guards
-			putStack(SlotID(0), new CStackInstance(CreatureID::GOLD_GOLEM, 9));
-			putStack(SlotID(1), new CStackInstance(CreatureID::DIAMOND_GOLEM, 6));
-		}
-		else if(subID == 0) // Elemental Conflux
-		{
-			creatures[0].second.push_back(CreatureID::AIR_ELEMENTAL);
-			creatures[1].second.push_back(CreatureID::FIRE_ELEMENTAL);
-			creatures[2].second.push_back(CreatureID::EARTH_ELEMENTAL);
-			creatures[3].second.push_back(CreatureID::WATER_ELEMENTAL);
-			//guards
-			putStack(SlotID(0), new CStackInstance(CreatureID::EARTH_ELEMENTAL, 12));
-		}
-		else
-		{
-			assert(0);
-		}
-		hoverName = VLC->generaltexth->creGens4[subID];
-		break;
+			//putStack(SlotID(0), new CStackInstance(CreatureID::EARTH_ELEMENTAL, 12));
+			break;
 
 	case Obj::REFUGEE_CAMP:
 		//is handled within newturn func
@@ -811,12 +776,10 @@ void CGTownInstance::setType(si32 ID, si32 subID)
 
 void CGTownInstance::updateAppearance()
 {
-	if (!hasFort())
-		appearance.animationFile = town->clientInfo.advMapVillage;
-	else if(hasCapitol())
-		appearance.animationFile = town->clientInfo.advMapCapitol;
-	else
-		appearance.animationFile = town->clientInfo.advMapCastle;
+	//FIXME: not the best way to do this
+	auto app = VLC->objtypeh->getHandlerFor(ID, subID)->getOverride(cb->gameState()->getTile(visitablePos())->terType, this);
+	if (app)
+		appearance = app.get();
 }
 
 std::string CGTownInstance::nodeName() const

+ 3 - 5
lib/mapObjects/CObjectClassesHandler.cpp

@@ -153,6 +153,7 @@ void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContai
 	}
 	
 	obj->objects[id] = handler;
+	logGlobal->debugStream() << "Loaded object " << obj->id << ":" << id;
 }
 
 CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const JsonNode & json)
@@ -198,8 +199,9 @@ void CObjectClassesHandler::loadSubObject(std::string name, JsonNode config, si3
 		config["index"].Float() = subID.get();
 	}
 
+	std::string oldMeta = config.meta; // FIXME: move into inheritNode?
 	JsonUtils::inherit(config, objects.at(ID)->base);
-	logGlobal->errorStream() << "JSON: " << config;
+	config.setMeta(oldMeta);
 	loadObjectEntry(config, objects[ID]);
 }
 
@@ -339,9 +341,6 @@ void AObjectTypeHandler::addTemplate(ObjectTemplate templ)
 
 void AObjectTypeHandler::addTemplate(JsonNode config)
 {
-	logGlobal->errorStream() << "INPUT  FOR: " << type << ":" << subtype << " " << config;
-	logGlobal->errorStream() << "BASE   FOR: " << type << ":" << subtype << " " << base;
-
 	config.setType(JsonNode::DATA_STRUCT); // ensure that input is not null
 	JsonUtils::inherit(config, base);
 	ObjectTemplate tmpl;
@@ -349,7 +348,6 @@ void AObjectTypeHandler::addTemplate(JsonNode config)
 	tmpl.subid = subtype;
 	tmpl.stringID = ""; // TODO?
 	tmpl.readJson(config);
-	logGlobal->errorStream() << "DATA  FOR: " << type << ":" << subtype << " " << config;
 	addTemplate(tmpl);
 }
 

+ 1 - 1
lib/mapObjects/CObjectClassesHandler.h

@@ -68,7 +68,7 @@ public:
 
 class CGObjectInstance;
 
-class AObjectTypeHandler
+class AObjectTypeHandler : public boost::noncopyable
 {
 	RandomMapInfo rmgInfo;
 

+ 1 - 10
lib/mapObjects/CObjectHandler.cpp

@@ -157,15 +157,6 @@ static void readBankLevel(const JsonNode &level, BankConfig &bc)
 
 CObjectHandler::CObjectHandler()
 {
-    logGlobal->traceStream() << "\t\tReading cregens ";
-
-	const JsonNode config(ResourceID("config/dwellings.json"));
-	for(const JsonNode &dwelling : config["dwellings"].Vector())
-	{
-		cregens[dwelling["dwelling"].Float()] = CreatureID((si32)dwelling["creature"].Float());
-	}
-    logGlobal->traceStream() << "\t\tDone loading cregens!";
-
     logGlobal->traceStream() << "\t\tReading resources prices ";
 	const JsonNode config2(ResourceID("config/resources.json"));
 	for(const JsonNode &price : config2["resources_prices"].Vector())
@@ -342,10 +333,10 @@ void CGObjectInstance::setType(si32 ID, si32 subID)
 
 	this->ID = Obj(ID);
 	this->subID = subID;
-	this->appearance = VLC->objtypeh->getHandlerFor(ID, subID)->getTemplates(tile.terType).front();
 
 	//recalculate blockvis tiles - new appearance might have different blockmap than before
 	cb->gameState()->map->removeBlockVisTiles(this, true);
+	this->appearance = VLC->objtypeh->getHandlerFor(ID, subID)->getTemplates(tile.terType).at(0);
 	cb->gameState()->map->addBlockVisTiles(this);
 }
 

+ 1 - 2
lib/mapObjects/CObjectHandler.h

@@ -187,7 +187,6 @@ struct BankConfig
 class DLL_LINKAGE CObjectHandler
 {
 public:
-	std::map<si32, CreatureID> cregens; //type 17. dwelling subid -> creature ID
 	std::map <ui32, std::vector < ConstTransitivePtr<BankConfig> > > banksInfo; //[index][preset]
 	std::map <ui32, std::string> creBanksNames; //[crebank index] -> name of this creature bank
 	std::vector<ui32> resVals; //default values of resources in gold
@@ -199,6 +198,6 @@ public:
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & cregens & banksInfo & creBanksNames & resVals;
+		h & banksInfo & creBanksNames & resVals;
 	}
 };

+ 66 - 9
lib/mapObjects/CommonConstructors.cpp

@@ -26,23 +26,27 @@ bool CObstacleConstructor::isStaticObject()
 	return true;
 }
 
-CTownInstanceConstructor::CTownInstanceConstructor()
+CTownInstanceConstructor::CTownInstanceConstructor():
+	faction(nullptr)
 {
 }
 
 void CTownInstanceConstructor::initTypeData(const JsonNode & input)
 {
-	VLC->modh->identifiers.requestIdentifier("faction", input["faction"],
-			[&](si32 index) { faction = VLC->townh->factions[index]; });
+	VLC->modh->identifiers.requestIdentifier("faction", input["faction"], [&](si32 index)
+	{
+		faction = VLC->townh->factions[index];
+	});
 
 	filtersJson = input["filters"];
 }
 
 void CTownInstanceConstructor::afterLoadFinalization()
 {
+	assert(faction);
 	for (auto entry : filtersJson.Struct())
 	{
-		filters[entry.first] = LogicalExpression<BuildingID>(entry.second, [&](const JsonNode & node)
+		filters[entry.first] = LogicalExpression<BuildingID>(entry.second, [this](const JsonNode & node)
 		{
 			return BuildingID(VLC->modh->identifiers.getIdentifier("building." + faction->identifier, node.Vector()[0]).get());
 		});
@@ -121,12 +125,13 @@ void CDwellingInstanceConstructor::initTypeData(const JsonNode & input)
 		availableCreatures[i].resize(creatures.size());
 		for (size_t j=0; j<creatures.size(); j++)
 		{
-			VLC->modh->identifiers.requestIdentifier("creature", creatures[j], [&] (si32 index)
+			VLC->modh->identifiers.requestIdentifier("creature", creatures[j], [=] (si32 index)
 			{
 				availableCreatures[i][j] = VLC->creh->creatures[index];
 			});
 		}
 	}
+	guards = input["guards"];
 }
 
 bool CDwellingInstanceConstructor::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const
@@ -137,17 +142,69 @@ bool CDwellingInstanceConstructor::objectFilter(const CGObjectInstance *, const
 CGObjectInstance * CDwellingInstanceConstructor::create(ObjectTemplate tmpl) const
 {
 	CGDwelling * obj = createTyped(tmpl);
-	for (auto entry : availableCreatures)
-	{
-		obj->creatures.resize(obj->creatures.size()+1);
 
+	obj->creatures.resize(availableCreatures.size());
+	for (auto & entry : availableCreatures)
+	{
 		for (const CCreature * cre : entry)
 			obj->creatures.back().second.push_back(cre->idNumber);
 	}
 	return obj;
 }
 
-void CDwellingInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
+namespace
+{
+	si32 loadValue(const JsonNode & value, CRandomGenerator & rng, si32 defaultValue = 0)
+	{
+		if (value.isNull())
+			return defaultValue;
+		if (value.getType() == JsonNode::DATA_FLOAT)
+			return value.Float();
+		si32 min = value["min"].Float();
+		si32 max = value["max"].Float();
+		return rng.getIntRange(min, max)();
+	}
+
+	std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng)
+	{
+		std::vector<CStackBasicDescriptor> ret;
+		for (auto & pair : value.Struct())
+		{
+			CStackBasicDescriptor stack;
+			stack.type = VLC->creh->creatures[VLC->modh->identifiers.getIdentifier(pair.second.meta, "creature", pair.first).get()];
+			stack.count = loadValue(pair.second, rng);
+			ret.push_back(stack);
+		}
+		return ret;
+	}
+}
+
+void CDwellingInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator &rng) const
 {
+	CGDwelling * dwelling = dynamic_cast<CGDwelling*>(object);
+
+	dwelling->creatures.clear();
+	dwelling->creatures.resize(availableCreatures.size());
 
+	for (auto & entry : availableCreatures)
+	{
+		for (const CCreature * cre : entry)
+			dwelling->creatures.back().second.push_back(cre->idNumber);
+	}
+
+	for (auto & stack : loadCreatures(guards, rng))
+	{
+		dwelling->putStack(SlotID(dwelling->stacksCount()), new CStackInstance(stack.type->idNumber, stack.count));
+	}
+}
+
+bool CDwellingInstanceConstructor::producesCreature(const CCreature * crea) const
+{
+	for (auto & entry : availableCreatures)
+	{
+		for (const CCreature * cre : entry)
+			if (crea == cre)
+				return true;
+	}
+	return false;
 }

+ 6 - 1
lib/mapObjects/CommonConstructors.h

@@ -91,14 +91,19 @@ public:
 
 class CDwellingInstanceConstructor : public CDefaultObjectTypeHandler<CGDwelling>
 {
+	std::vector<std::vector<const CCreature *>> availableCreatures;
+
+	JsonNode guards;
+
 protected:
 	bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const;
 
 public:
-	std::vector<std::vector<CCreature *>> availableCreatures;
 
 	CDwellingInstanceConstructor();
 	CGObjectInstance * create(ObjectTemplate tmpl) const;
 	void initTypeData(const JsonNode & input);
 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const;
+
+	bool producesCreature(const CCreature * crea) const;
 };