Pārlūkot izejas kodu

Merge pull request #30 from vcmi/RMG

Since there are no objections, I finally merge this branch.
DjWarmonger 11 gadi atpakaļ
vecāks
revīzija
a842068d54

+ 0 - 11
Mods/WoG/config/defaultMods.json

@@ -1,11 +0,0 @@
-{
-	"textData" :
-	{
-		"heroClass"  : 18,
-		"artifact"   : 171,
-		"creature"   : 197,
-		"faction"    : 9,
-		"hero"       : 156,
-		"mapVersion" : 51 // WoG
-	}
-}

+ 0 - 309
Mods/WoG/config/wog/artifacts.json

@@ -1,309 +0,0 @@
-{
-	"art144": // placeholder for selection image
-	{
-		"index" : 144,
-		"type" : ["HERO"]
-	},
-	"art145": // placeholder for lock image
-	{
-		"index" : 145,
-		"type" : ["HERO"]
-	},
-	"axeOfSmashing": //TODO: move growing bonuses to this config, someday
-	{
-		"bonuses" : [
-			{
-				"subtype" : "primSkill.attack",
-				"type" : "PRIMARY_SKILL",
-				"val" : 6,
-				"valueType" : "BASE_NUMBER"
-			}
-		],
-		"index" : 146,
-		"type" : ["COMMANDER"],
-		"growing":
-		{
-			"bonusesPerLevel":
-			[
-				{
-					"level": 6,
-					"bonus": 
-					{
-						"type" : "PRIMARY_SKILL",
-						"subtype" : "primSkill.attack",
-						"val" : 1
-					}
-				}
-			]
-		}
-	},
-	"mithrilMail":
-	{
-		"bonuses" : [
-			{
-				"type" : "STACK_HEALTH",
-				"val" : 12,
-				"valueType" : "PERCENT_TO_ALL"
-			}
-		],
-		"index" : 147,
-		"type" : ["COMMANDER"],
-		"growing":
-		{
-			"bonusesPerLevel":
-			[
-				{
-					"level": 1,
-					"bonus": 
-					{
-						"type" : "STACK_HEALTH",
-						"val" : 1
-					}
-				}
-			]
-		}
-	},
-	"swordOfSharpness":
-	{
-		"bonuses" : [
-			{
-				"subtype" : 0,
-				"type" : "CREATURE_DAMAGE",
-				"val" : 12,
-				"valueType" : "PERCENT_TO_ALL"
-			}
-		],
-		"index" : 148,
-		"type" : ["COMMANDER"],
-		"growing":
-		{
-			"bonusesPerLevel":
-			[
-				{
-					"level": 1,
-					"bonus": 
-					{
-						"type" : "CREATURE_DAMAGE",
-						"val" : 1
-					}
-				}
-			]
-		}
-	},
-	"helmOfImmortality": //TODO: implement
-	{
-		"index" : 149,
-		"type" : ["COMMANDER"]
-	},
-	"pendantOfSorcery":
-	{
-		"bonuses" : [
-			{
-				"type" : "CASTS",
-				"val" : 1,
-				"valueType" : "BASE_NUMBER"
-			}
-		],
-		"index" : 150,
-		"type" : ["COMMANDER"],
-		"growing":
-		{
-			"bonusesPerLevel":
-			[
-				{
-					"level": 10,
-					"bonus": 
-					{
-						"type" : "CREATURE_ENCHANT_POWER",
-						"val" : 1
-					}
-				}
-			]
-		}
-	},
-	"bootsOfHaste":
-	{
-		"bonuses" : [
-			{
-				"type" : "STACKS_SPEED",
-				"val" : 1,
-				"valueType" : "BASE_NUMBER"
-			}
-		],
-		"index" : 151,
-		"type" : ["COMMANDER"],
-		"growing":
-		{
-			"bonusesPerLevel":
-			[
-				{
-					"level": 10,
-					"bonus": 
-					{
-						"type" : "STACKS_SPEED",
-						"val" : 1
-					}
-				}
-			]
-		}
-	},
-	"bowOfSeeking":
-	{
-		"index" : 152,
-		"type" : ["COMMANDER"],
-		"growing":
-		{
-			"thresholdBonuses":
-			[
-				{
-					"level": 5,
-					"bonus":
-					{
-						"type" : "SHOOTER"
-					}
-				},
-				{
-					"level": 25,
-					"bonus": 
-					{
-						"type" : "NO_WALL_PENALTY"
-					}
-				},
-				{
-					"level": 50,
-					"bonus": 
-					{
-						"type" : "NO_DISTANCE_PENALTY"
-					}
-				}
-			]
-		}
-	},
-	"dragonEyeRing": //TODO: implement
-	{
-		"index" : 153,
-		"type" : ["COMMANDER"],
-	},
-	"hardenedShield":
-	{
-		"bonuses" : [
-			{
-				"subtype" : "primSkill.attack",
-				"type" : "PRIMARY_SKILL",
-				"val" : 6,
-				"valueType" : "BASE_NUMBER"
-			}
-		],
-		"index" : 154,
-		"type" : ["COMMANDER"],
-		"growing":
-		{
-			"bonusesPerLevel":
-			[
-				{
-					"level": 6,
-					"bonus": 
-					{
-						"type" : "PRIMARY_SKILL",
-						"subtype" : "primSkill.defence",
-						"val" : 1
-					}
-				}
-			]
-		}
-	},
-	"slavasRingOfPower": //TODO: implement if possible
-	{
-		"index" : 155,
-		"type" : ["COMMANDER"]
-	},
-	"warlordsBanner":
-	{
-		"bonuses" : [
-			{
-				"type" : "STACK_HEALTH",
-				"val" : 2,
-				"valueType" : "BASE_NUMBER"
-			}
-		],
-		"index" : 156,
-		"type" : ["CREATURE"]
-	},
-	"crimsonShieldOfRetribution": //TODO: implement
-	{
-		"index" : 157,
-		"type" : ["HERO"]
-	},
-	"barbarianLordsAxeOfFerocity": //TODO: implement
-	{
-		"index" : 158,
-		"type" : ["HERO"],
-		"components":
-		[
-			"ogresClubOfHavoc",
-			"targOfTheRampagingOgre",
-			"crownOfTheSupremeMagi",
-			"tunicOfTheCyclopsKing"
-		]
-	},
-	"dragonheart":
-	{
-		"index" : 159,
-		"type" : ["HERO"]
-	},
-	"gateKey":
-	{
-		"index" : 160,
-		"type" : ["HERO"]
-	},
-	"art161":
-	{
-		"index" : 161,
-		"type" : ["HERO"]
-	},
-	"art162":
-	{
-		"index" : 162,
-		"type" : ["HERO"]
-	},
-	"art163":
-	{
-		"index" : 163,
-		"type" : ["HERO"]
-	},
-	"art164":
-	{
-		"index" : 164,
-		"type" : ["HERO"]
-	},
-	"art165":
-	{
-		"index" : 165,
-		"type" : ["HERO"]
-	},
-	"art166":
-	{
-		"index" : 166,
-		"type" : ["HERO"]
-	},
-	"art167":
-	{
-		"index" : 167,
-		"type" : ["HERO"]
-	},
-	"art168":
-	{
-		"index" : 168,
-		"type" : ["HERO"]
-	},
-	"art169":
-	{
-		"index" : 169,
-		"type" : ["HERO"]
-	},
-	"art170":
-	{
-		"index" : 170,
-		"type" : ["HERO"]
-	}
-}

+ 0 - 817
Mods/WoG/config/wog/creatureBanks.json

@@ -1,817 +0,0 @@
-{
-	"core:creatureBank" : {
-		"types" : {
-			"huntingLodge" : {
-				"name" : "Hunting Lodge",
-				"index" : 11,
-				"levels": [
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 3, "type" : "dendroidGuard" },
-							{ "amount": 4, "type" : "woodElf" },
-							{ "amount": 3, "type" : "dendroidGuard" },
-							{ "amount": 4, "type" : "woodElf" }
-						],
-						"combat_value": 100,
-						"reward" : {
-							"resources":
-							{
-								"wood" : 15,
-								"gold" : 500
-							}
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 4, "type" : "dendroidGuard" },
-							{ "amount": 6, "type" : "woodElf" },
-							{ "amount": 4, "type" : "dendroidGuard" },
-							{ "amount": 6, "type" : "woodElf" }
-						],
-						"combat_value": 150,
-						"reward" : {
-							"resources":
-							{
-								"wood" : 20,
-								"gold" : 500
-							},
-							"value": 3000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 5, "type" : "dendroidGuard" },
-							{ "amount": 8, "type" : "woodElf" },
-							{ "amount": 5, "type" : "dendroidGuard" },
-							{ "amount": 8, "type" : "woodElf" }
-						],
-						"combat_value": 200,
-						"reward" : {
-							"resources":
-							{
-								"wood" : 25,
-								"gold" : 500
-							},
-							"value": 4000
-						}
-					},
-					{
-						"chance": 10,
-						"guards": [
-							{ "amount": 6,  "type" : "dendroidGuard" },
-							{ "amount": 10, "type" : "woodElf" },
-							{ "amount": 6,  "type" : "dendroidGuard" },
-							{ "amount": 10, "type" : "woodElf" }
-						],
-						"combat_value": 300,
-						"reward" : {
-							"resources":
-							{
-								"wood" : 40,
-								"gold" : 1000
-							},
-							"value": 6000
-						}
-					}
-				]
-			},
-			"snowGrotto" : 
-			{
-				"name" : "Snow-covered Grotto",
-				"index" : 12,
-				"levels": [
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 5,  "type" :  "ironGolem" },
-							{ "amount": 20, "type" :  "masterGremlin" },
-							{ "amount": 5,  "type" :  "ironGolem" },
-							{ "amount": 20, "type" :  "masterGremlin" }
-						],
-						"combat_value": 100,
-						"reward" : {
-							"resources":
-							{
-								"ore" : 15,
-								"gold" : 500
-							}
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 6,  "type" :  "ironGolem" },
-							{ "amount": 30, "type" :  "masterGremlin" },
-							{ "amount": 6,  "type" :  "ironGolem" },
-							{ "amount": 30, "type" :  "masterGremlin" }
-						],
-						"combat_value": 150,
-						"reward" : {
-							"resources":
-							{
-								"ore" : 20,
-								"gold" : 500
-							},
-							"value": 3000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 7,  "type" :  "ironGolem" },
-							{ "amount": 40, "type" :  "masterGremlin" },
-							{ "amount": 7,  "type" :  "ironGolem" },
-							{ "amount": 40, "type" :  "masterGremlin" }
-						],
-						"combat_value": 200,
-						"reward" : {
-							"resources":
-							{
-								"ore" : 30,
-								"gold" : 500
-							},
-							"value": 4000
-						}
-					},
-					{
-						"chance": 10,
-						"guards": [
-							{ "amount": 8,  "type" :  "ironGolem" },
-							{ "amount": 50, "type" :  "masterGremlin" },
-							{ "amount": 8,  "type" :  "ironGolem" },
-							{ "amount": 50, "type" :  "masterGremlin" }
-						],
-						"combat_value": 300,
-						"reward" : {
-							"resources":
-							{
-								"ore" : 40,
-								"gold" : 1000
-							},
-							"value": 6000
-						}
-					}
-				]
-			},
-			"martialSpiritPalace" : 
-			{
-				"name" : "Palace of Martial Spirit",
-				"index" : 13,
-				"levels": [
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 10, "type" :  "godWar" },
-							{ "amount": 10, "type" :  "godWar" },
-							{ "amount": 10, "type" :  "godWar" },
-							{ "amount": 10, "type" :  "godWar" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godWar" }
-							],
-							"value": 38000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 15, "type" :  "godWar" },
-							{ "amount": 15, "type" :  "godWar" },
-							{ "amount": 15, "type" :  "godWar" },
-							{ "amount": 15, "type" :  "godWar" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godWar" }
-							],
-							"value": 57000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 20, "type" :  "godWar" },
-							{ "amount": 20, "type" :  "godWar" },
-							{ "amount": 20, "type" :  "godWar" },
-							{ "amount": 20, "type" :  "godWar" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godWar" }
-							],
-							"value": 75000
-						}
-					},
-					{
-						"chance": 10,
-						"guards": [
-							{ "amount": 30, "type" :  "godWar" },
-							{ "amount": 30, "type" :  "godWar" },
-							{ "amount": 30, "type" :  "godWar" },
-							{ "amount": 30, "type" :  "godWar" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godWar" }
-							],
-							"value": 90000
-						}
-					}
-				]
-			},
-			"pacificationCitadel" :
-			{
-				"name" : "Citadel of Pacification",
-				"index" : 14,
-				"levels": [
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 10, "type" :  "godPeace" },
-							{ "amount": 10, "type" :  "godPeace" },
-							{ "amount": 10, "type" :  "godPeace" },
-							{ "amount": 10, "type" :  "godPeace" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godPeace" }
-							],
-							"value": 38000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 15, "type" :  "godPeace" },
-							{ "amount": 15, "type" :  "godPeace" },
-							{ "amount": 15, "type" :  "godPeace" },
-							{ "amount": 15, "type" :  "godPeace" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godPeace" }
-							],
-							"value": 57000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 20, "type" :  "godPeace" },
-							{ "amount": 20, "type" :  "godPeace" },
-							{ "amount": 20, "type" :  "godPeace" },
-							{ "amount": 20, "type" :  "godPeace" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godPeace" }
-							],
-							"value": 75000
-						}
-					},
-					{
-						"chance": 10,
-						"guards": [
-							{ "amount": 30, "type" :  "godPeace" },
-							{ "amount": 30, "type" :  "godPeace" },
-							{ "amount": 30, "type" :  "godPeace" },
-							{ "amount": 30, "type" :  "godPeace" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godPeace" }
-							],
-							"value": 90000
-						}
-					}
-				]
-			},
-			"magiciansMonastery" :
-			{
-				"name" : "Monastery of Magicians",
-				"index" : 15,
-				"levels": [
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 10, "type" :  "godMana" },
-							{ "amount": 10, "type" :  "godMana" },
-							{ "amount": 10, "type" :  "godMana" },
-							{ "amount": 10, "type" :  "godMana" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godMana" }
-							],
-							"value": 38000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 15, "type" :  "godMana" },
-							{ "amount": 15, "type" :  "godMana" },
-							{ "amount": 15, "type" :  "godMana" },
-							{ "amount": 15, "type" :  "godMana" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godMana" }
-							],
-							"value": 57000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 20, "type" :  "godMana" },
-							{ "amount": 20, "type" :  "godMana" },
-							{ "amount": 20, "type" :  "godMana" },
-							{ "amount": 20, "type" :  "godMana" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godMana" }
-							],
-							"value": 75000
-						}
-					},
-					{
-						"chance": 10,
-						"guards": [
-							{ "amount": 30, "type" :  "godMana" },
-							{ "amount": 30, "type" :  "godMana" },
-							{ "amount": 30, "type" :  "godMana" },
-							{ "amount": 30, "type" :  "godMana" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godMana" }
-							],
-							"value": 90000
-						}
-					}
-				]
-			},
-			"legendsLibrary" :
-			{
-				"name" : "Library of Legends",
-				"index" : 16,
-				"levels": [
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 10, "type" :  "godLore" },
-							{ "amount": 10, "type" :  "godLore" },
-							{ "amount": 10, "type" :  "godLore" },
-							{ "amount": 10, "type" :  "godLore" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godLore" }
-							],
-							"value": 38000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 15, "type" :  "godLore" },
-							{ "amount": 15, "type" :  "godLore" },
-							{ "amount": 15, "type" :  "godLore" },
-							{ "amount": 15, "type" :  "godLore" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godLore" }
-							],
-							"value": 57000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 20, "type" :  "godLore" },
-							{ "amount": 20, "type" :  "godLore" },
-							{ "amount": 20, "type" :  "godLore" },
-							{ "amount": 20, "type" :  "godLore" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godLore" }
-							],
-							"value": 75000
-						}
-					},
-					{
-						"chance": 10,
-						"guards": [
-							{ "amount": 30, "type" :  "godLore" },
-							{ "amount": 30, "type" :  "godLore" },
-							{ "amount": 30, "type" :  "godLore" },
-							{ "amount": 30, "type" :  "godLore" }
-						],
-						"combat_value": 2000,
-						"reward" : {
-							"creatures": [
-								{ "amount": 1, "type" :  "godLore" }
-							],
-							"value": 90000
-						}
-					}
-				]
-			},
-			"transylvanianTavern" :
-			{
-				"name" : "Transylvanian Tavern",
-				"index" : 17,
-				"levels": [
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 2, "type" :  "vampire" },
-							{ "amount": 2, "type" :  "vampire" },
-							{ "amount": 2, "type" :  "vampire" },
-							{ "amount": 2, "type" :  "vampire" },
-							{ "amount": 2, "type" :  "vampire" }
-						],
-						"combat_value": 100,
-						"reward" : {
-							"resources":
-							{
-								"gold" : 1500
-							},
-							"creatures": [
-								{ "amount": 3, "type" :  "vampireLord" }
-							]
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 3, "type" :  "vampire" },
-							{ "amount": 3, "type" :  "vampire" },
-							{ "amount": 3, "type" :  "vampire" },
-							{ "amount": 3, "type" :  "vampire" },
-							{ "amount": 3, "type" :  "vampire" }
-						],
-						"combat_value": 150,
-						"reward" : {
-							"resources":
-							{
-								"gold" : 2500
-							},
-							"creatures": [
-								{ "amount": 5, "type" :  "vampireLord" }
-							],
-							"value": 3000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 4, "type" :  "vampire" },
-							{ "amount": 4, "type" :  "vampire" },
-							{ "amount": 4, "type" :  "vampire" },
-							{ "amount": 4, "type" :  "vampire" },
-							{ "amount": 4, "type" :  "vampire" }
-						],
-						"combat_value": 200,
-						"reward" : {
-							"resources":
-							{
-								"gold" : 3500
-							},
-							"creatures": [
-								{ "amount": 7, "type" :  "vampireLord" }
-							],
-							"value": 4000
-						}
-					},
-					{
-						"chance": 10,
-						"guards": [
-							{ "amount": 6, "type" :  "vampire" },
-							{ "amount": 6, "type" :  "vampire" },
-							{ "amount": 6, "type" :  "vampire" },
-							{ "amount": 6, "type" :  "vampire" },
-							{ "amount": 6, "type" :  "vampire" }
-						],
-						"combat_value": 250,
-						"reward" : {
-							"resources":
-							{
-								"gold" : 5000
-							},
-							"creatures": [
-								{ "amount": 9, "type" :  "vampireLord" }
-							],
-							"value": 5000
-						}
-					}
-				]
-			},
-			"homeofthebat" :
-			{
-				"name" : "Home of the Bat",
-				"index" : 18,
-				"levels": [
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 2, "type" :  "vampire" },
-							{ "amount": 2, "type" :  "vampire" },
-							{ "amount": 2, "type" :  "vampire", "upgrade_chance": 50 },
-							{ "amount": 2, "type" :  "vampire" },
-							{ "amount": 2, "type" :  "vampire" }
-						],
-						"combat_value": 100,
-						"reward" : {
-							"resources":
-							{
-								"mercury" : 2,
-								"sulfur" : 2,
-								"crystal" : 2,
-								"gems" : 2
-							},
-							"creatures": [
-								{ "amount": 3, "type" :  "vampireLord" }
-							]
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 3, "type" :  "vampire" },
-							{ "amount": 3, "type" :  "vampire" },
-							{ "amount": 3, "type" :  "vampire", "upgrade_chance": 70 },
-							{ "amount": 3, "type" :  "vampire" },
-							{ "amount": 3, "type" :  "vampire" }
-						],
-						"combat_value": 150,
-						"reward" : {
-							"resources":
-							{
-								"mercury" : 3,
-								"sulfur" : 3,
-								"crystal" : 3,
-								"gems" : 3
-							},
-							"creatures": [
-								{ "amount": 5, "type" :  "vampireLord" }
-							],
-							"value": 3000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 4, "type" :  "vampire" },
-							{ "amount": 4, "type" :  "vampire" },
-							{ "amount": 4, "type" :  "vampire", "upgrade_chance": 80 },
-							{ "amount": 4, "type" :  "vampire" },
-							{ "amount": 4, "type" :  "vampire" }
-						],
-						"combat_value": 200,
-						"reward" : {
-							"resources":
-							{
-								"mercury" : 4,
-								"sulfur" : 4,
-								"crystal" : 4,
-								"gems" : 4
-							},
-							"creatures": [
-								{ "amount": 7, "type" :  "vampireLord" }
-							],
-							"value": 4000
-						}
-					},
-					{
-						"chance": 10,
-						"guards": [
-							{ "amount": 6, "type" :  "vampire" },
-							{ "amount": 6, "type" :  "vampire" },
-							{ "amount": 6, "type" :  "vampire", "upgrade_chance": 50 },
-							{ "amount": 6, "type" :  "vampire" },
-							{ "amount": 6, "type" :  "vampire" }
-						],
-						"combat_value": 250,
-						"reward" : {
-							"resources":
-							{
-								"mercury" : 5,
-								"sulfur" : 5,
-								"crystal" : 5,
-								"gems" : 5
-							},
-							"creatures": [
-								{ "amount": 9, "type" :  "vampireLord" }
-							],
-							"value": 5000
-						}
-					}
-				]
-			},
-			"lostBottle" :
-			{
-				"name" : "Lost Bottle",
-				"index" : 19,
-				"levels": [
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 2, "type" :  "genie" },
-							{ "amount": 2, "type" :  "genie" },
-							{ "amount": 2, "type" :  "genie", "upgrade_chance": 50 },
-							{ "amount": 2, "type" :  "genie" },
-							{ "amount": 2, "type" :  "genie" }
-						],
-						"combat_value": 100,
-						"reward" : {
-							"resources":
-							{
-								"mercury" : 2,
-								"sulfur" : 2,
-								"crystal" : 2,
-								"gems" : 2
-							},
-							"creatures": [
-								{ "amount": 3, "type" :  "genie" }
-							]
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 3, "type" :  "genie" },
-							{ "amount": 3, "type" :  "genie" },
-							{ "amount": 3, "type" :  "genie", "upgrade_chance": 70 },
-							{ "amount": 3, "type" :  "genie" },
-							{ "amount": 3, "type" :  "genie" }
-						],
-						"combat_value": 150,
-						"reward" : {
-							"resources":
-							{
-								"mercury" : 3,
-								"sulfur" : 3,
-								"crystal" : 3,
-								"gems" : 3
-							},
-							"creatures": [
-								{ "amount": 5, "type" :  "genie" }
-							],
-							"value": 3000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 4, "type" :  "genie" },
-							{ "amount": 4, "type" :  "genie" },
-							{ "amount": 4, "type" :  "genie", "upgrade_chance": 80 },
-							{ "amount": 4, "type" :  "genie" },
-							{ "amount": 4, "type" :  "genie" }
-						],
-						"combat_value": 200,
-						"reward" : {
-							"resources":
-							{
-								"mercury" : 4,
-								"sulfur" : 4,
-								"crystal" : 4,
-								"gems" : 4
-							},
-							"creatures": [
-								{ "amount": 7, "type" :  "genie" }
-							],
-							"value": 4000
-						}
-					},
-					{
-						"chance": 10,
-						"guards": [
-							{ "amount": 6, "type" :  "genie" },
-							{ "amount": 6, "type" :  "genie" },
-							{ "amount": 6, "type" :  "genie", "upgrade_chance": 90 },
-							{ "amount": 6, "type" :  "genie" },
-							{ "amount": 6, "type" :  "genie" }
-						],
-						"combat_value": 250,
-						"reward" : {
-							"resources":
-							{
-								"mercury" : 5,
-								"sulfur" : 5,
-								"crystal" : 5,
-								"gems" : 5
-							},
-							"creatures": [
-								{ "amount": 9, "type" :  "genie" }
-							],
-							"value": 5000
-						}
-					}
-				]
-			},
-			"grotto" :
-			{
-				"name" : "Grotto",
-				"index" : 20,
-				"levels": [
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 3, "type" :  "harpy" },
-							{ "amount": 3, "type" :  "beholder" },
-							{ "amount": 3, "type" :  "harpy" },
-							{ "amount": 3, "type" :  "beholder" }
-						],
-						"combat_value": 200,
-						"reward" : {
-							"resources":
-							{
-								"ore" : 20,
-								"gold" : 1000
-							}
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 4, "type" :  "harpy" },
-							{ "amount": 4, "type" :  "beholder" },
-							{ "amount": 4, "type" :  "harpy" },
-							{ "amount": 4, "type" :  "beholder" }
-						],
-						"combat_value": 300,
-						"reward" : {
-							"resources":
-							{
-								"ore" : 25,
-								"gold" : 1000
-							},
-							"value": 3000
-						}
-					},
-					{
-						"chance": 30,
-						"guards": [
-							{ "amount": 5, "type" :  "harpy" },
-							{ "amount": 5, "type" :  "beholder" },
-							{ "amount": 5, "type" :  "harpy" },
-							{ "amount": 5, "type" :  "beholder" }
-						],
-						"combat_value": 400,
-						"reward" : {
-							"resources":
-							{
-								"ore" : 30,
-								"gold" : 1500
-							},
-							"value": 4000
-						}
-					},
-					{
-						"chance": 10,
-						"guards": [
-							{ "amount": 6, "type" :  "harpy" },
-							{ "amount": 6, "type" :  "beholder" },
-							{ "amount": 6, "type" :  "harpy" },
-							{ "amount": 6, "type" :  "beholder" }
-						],
-						"combat_value": 500,
-						"reward" : {
-							"resources":
-							{
-								"ore" : 35,
-								"gold" : 2000
-							},
-							"value": 5000
-						}
-					}
-				]
-			}
-		}
-	}
-}

+ 0 - 1586
Mods/WoG/config/wog/creatures.json

@@ -1,1586 +0,0 @@
-{
-	"supremeArchangel" :
-	{
-		"index": 150,
-		"level": 8,
-		"faction": "castle",
-		"abilities":
-		{
-			"resurrection100hp" : 
-			{
-				"type" : "SPECIFIC_SPELL_POWER",
-				"subtype" : "spell.resurrection",
-				"val" : 100
-			},
-			"resurrects" :
-			{
-				"type" : "SPELLCASTER",
-				"subtype" : "spell.resurrection"
-			},
-			"fearless" :
-			{
-				"type" : "FEARLESS"
-			},
-			"spellpoints" :
-			{
-				"type" : "CASTS",
-				"val" : 2
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM150Z.DEF"
-		},
-		"sound" :
-		{
-			"attack": "AAGLATTK.wav",
-			"defend": "AAGLDFND.wav",
-			"killed": "AAGLKILL.wav",
-			"move": "AAGLMOVE.wav",
-			"wince": "AAGLWNCE.wav"
-		}
-	},
-	"diamondDragon" :
-	{
-		"index": 151,
-		"level": 8,
-		"faction": "rampart",
-		"abilities":
-		{
-			"dragon" :
-			{
-				"type" : "DRAGON_NATURE"
-			},
-			"fireBreath" :
-			{
-				"type" : "TWO_HEX_ATTACK_BREATH"
-			},
-			"spellImmunity" :
-			{
-				"type" : "LEVEL_SPELL_IMMUNITY",
-				"val" : 5
-			},
-			"fearless" :
-			{
-				"type" : "FEARLESS"
-			},
-		},
-		"graphics" :
-		{
-			"animation": "ZM151Z.DEF",
-		},
-		"sound" :
-		{
-			"attack": "GODRATTK.wav",
-			"defend": "GODRDFND.wav",
-			"killed": "GODRKILL.wav",
-			"move": "GODRMOVE.wav",
-			"wince": "GODRWNCE.wav"
-		}
-	},
-	"lordofThunder" :
-	{
-		"index": 152,
-		"level": 8,
-		"faction": "tower",
-		"abilities" :
-		{
-			"additionalAttack" :
-			{
-				"type" : "ADDITIONAL_ATTACK",
-				"val" : 1
-			},
-			"thunderStrength" :
-			{
-				"type" : "SPECIFIC_SPELL_POWER",
-				"subtype" : "spell.thunderbolt",
-				"val" : 10
-			},
-			"thunderOnAttack" :
-			{
-				"type" : "SPELL_AFTER_ATTACK",
-				"subtype" : "spell.thunderbolt",
-				"val" : 20
-			},
-			"castsAirShield" :
-			{
-				"type" : "ENCHANTED",
-				"subtype" : "spell.airShield",
-				"val" : 3,
-				"addInfo" : 1
-			},
-			"noPenalty" : 
-			{
-				"type" : "NO_WALL_PENALTY"
-			},
-			"noDistancePenalty" :
-			{
-				"type" : "NO_DISTANCE_PENALTY"
-			}
-		},		
-		"graphics" :
-		{
-			"animation": "ZM152Z.DEF",
-			"missile" :
-			{
-				"projectile": "CPRGTIX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "GTITATTK.wav",
-			"defend": "GTITDFND.wav",
-			"killed": "GTITKILL.wav",
-			"move": "GTITMOVE.wav",
-			"shoot": "GTITSHOT.wav",
-			"wince": "GTITWNCE.wav"
-		}
-	},
-	"hellBaron" :
-	{
-		"index": 153,
-		"level": 8,
-		"faction": "inferno",
-		"abilities":
-		{
-			"fearless" :
-			{
-				"type" : "FEARLESS"
-			},
-			"petrify" :
-			{
-				"type" : "SPELL_AFTER_ATTACK",
-				"subtype" : "spell.stoneGaze",
-				"val" : 50,
-				"addInfo" : 3
-			},
-			"descreaseLuck" :
-			{
-				"type" : "LUCK",
-				"effectRange" : "ONLY_ENEMY_ARMY",
-				"val" : -1
-			},
-			"blockRetaliation" :
-			{
-				"type" : "BLOCKS_RETALIATION"
-			}
-		},
-		"graphics" :
-		{
-			"missile" : null,
-			"animation": "ZM153Z.DEF"
-		},
-		"sound" :
-		{
-			"attack": "ADVLATTK.wav",
-			"defend": "ADVLDFND.wav",
-			"killed": "ADVLKILL.wav",
-			"move": "ADVLMOVE.wav",
-			"wince": "ADVLWNCE.wav",
-			"startMoving": "ADVLEXT1.wav",
-			"endMoving": "ADVLEXT2.wav"
-		}
-	},
-	"bloodDragon" :
-	{
-		"index": 154,
-		"level": 8,
-		"faction": "necropolis",
-		"abilities":
-		{
-			"drainsLife" : 
-			{
-				"type" : "LIFE_DRAIN",
-				"val" : 40
-			},
-			"dragon" :
-			{
-				"type" : "DRAGON_NATURE"
-			},
-			"descreaseLuck" :
-			{
-				"type" : "LUCK",
-				"effectRange" : "ONLY_ENEMY_ARMY",
-				"val" : -1
-			},
-			"fearless" :
-			{
-				"type" : "FEARLESS"
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM154Z.DEF"
-		},
-		"sound" :
-		{
-			"attack": "GHDRATTK.wav",
-			"defend": "GHDRDFND.wav",
-			"killed": "GHDRKILL.wav",
-			"move": "GHDRMOVE.wav",
-			"wince": "GHDRWNCE.wav"
-		}
-	},
-	"darknessDragon" :
-	{
-		"index": 155,
-		"level": 8,
-		"faction": "dungeon",
-		"abilities":
-		{
-			"dragon" :
-			{
-				"type" : "DRAGON_NATURE"
-			},
-			"spellImmunity" :
-			{
-				"type" : "LEVEL_SPELL_IMMUNITY",
-				"val" : 5
-			},
-			"fearless" :
-			{
-				"type" : "FEARLESS"
-			},
-			"fear" :
-			{
-				"type" : "FEAR"
-			},
-			"strikeAndReturn" : 
-			{
-				"type" : "RETURN_AFTER_STRIKE",
-				"val" : 0,
-				"valueType" : "BASE_NUMBER"
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM155Z.DEF"
-		},
-		"sound" :
-		{
-			"attack": "BKDRATTK.wav",
-			"defend": "BKDRDFND.wav",
-			"killed": "BKDRKILL.wav",
-			"move": "BKDRMOVE.wav",
-			"wince": "BKDRWNCE.wav"
-		}
-	},
-	"ghostBehemoth" :
-	{
-		"index": 156,
-		"level": 8,
-		"faction": "stronghold",
-		"abilities" :
-		{
-			"canFly" : 
-			{
-				"type" : "FLYING"
-			},
-			"fearless" :
-			{
-				"type" : "FEARLESS"
-			},
-			"fear" :
-			{
-				"type" : "FEAR"
-			},
-			"selfMorale" :
-			{
-				"type" : "SELF_MORALE",
-				"effectRange" : "ONLY_ENEMY_ARMY",
-				"val" : 1
-			},
-			"extraRetaliation" :
-			{
-				"type" : "ADDITIONAL_RETALIATION",
-				"val" : 2
-			},
-			"reduceDefence" :
-			{
-				"type" : "ENEMY_DEFENCE_REDUCTION",
-				"val" : 100
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM156Z.DEF"
-		},
-		"sound" :
-		{
-			"attack": "BMTHATTK.wav",
-			"defend": "BMTHDFND.wav",
-			"killed": "BMTHKILL.wav",
-			"move": "BMTHMOVE.wav",
-			"wince": "BMTHWNCE.wav"
-		}
-	},
-	"hellHydra" :
-	{
-		"index": 157,
-		"level": 8,
-		"faction": "fortress",
-		"abilities":
-		{
-			"acidBreath" :
-			{
-				"type" : "ACID_BREATH",
-				"val" : 25,
-				"addInfo" : 20
-			},
-			"reduceDefence" :
-			{
-				"type" : "SPELL_AFTER_ATTACK",
-				"subtype" : "spell.acidBreath",
-				"val" : 100
-			},
-			"noRetaliation" : 
-			{
-				"type" : "BLOCKS_RETALIATION"
-			},
-			"regenerates" :
-			{
-				"type" : "HP_REGENERATION",
-				"val" : 40
-			},
-			"fearless" :
-			{
-				"type" : "FEARLESS"
-			},
-			"SHOOTER" : null
-		},
-		"graphics" :
-		{
-			"animation": "ZM157Z.DEF"
-		},
-		"sound" :
-		{
-			"attack": "CHYDATTK.wav",
-			"defend": "CHYDDFND.wav",
-			"killed": "CHYDKILL.wav",
-			"move": "CHYDMOVE.wav",
-			"wince": "CHYDWNCE.wav"
-		}
-	},
-	"sacredPhoenix" :
-	{
-		"index": 158,
-		"level": 8,
-		"faction": "conflux",
-		"abilities":
-		{
-			"rebirthOnce" :
-			{
-				"type" : "CASTS",
-				"val" : 1
-			},
-			"immuneToFire" :
-			{
-				"type" : "FIRE_IMMUNITY",
-				"subtype" : 0 //this IS important
-			},
-			"rebirth" : 
-			{
-				"type" : "REBIRTH",
-				"val" : 100
-			},
-			"fireShield" :
-			{
-				"type" : "FIRE_SHIELD",
-				"subtype" : 100,
-				"val" : 100
-			},
-			"spellSlayer" :
-			{
-				"type" : "ENCHANTED",
-				"subtype" : "spell.slayer",
-				"val" : 3,
-				"addInfo" : 100
-			},
-			"fearless" :
-			{
-				"type" : "FEARLESS"
-			},
-			"spellpower" :
-			{
-				"type" : "CREATURE_SPELL_POWER",
-				"val" : 100
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM158Z.DEF"
-		},
-		"sound" :
-		{
-			"attack": "PHOEATTK.wav",
-			"defend": "PHOEDFND.wav",
-			"killed": "PHOEKILL.wav",
-			"move": "PHOEMOVE.wav",
-			"wince": "PHOEWNCE.wav"
-		}
-	},
-	"ghost" :
-	{
-		"index": 159,
-		"growth" : 7,
-		"level": 3,
-		"faction": "necropolis",
-		"abilities":
-		{
-			"fearless" :
-			{
-				"type" : "FEARLESS"
-			},
-			"armageddonImmunity" : 
-			{
-				"type" : "SPELL_IMMUNITY",
-				"subtype" : "spell.armageddon"
-			},
-		},
-		"graphics" :
-		{
-			"animation": "ZM159G.DEF"
-		},
-		"sound" :
-		{
-			"attack": "WRTHATTK.wav",
-			"defend": "WRTHDFND.wav",
-			"killed": "WRTHKILL.wav",
-			"move": "WRTHMOVE.wav",
-			"wince": "WRTHWNCE.wav"
-		}
-	},
-	"godWar" :
-	{
-		"disabled" : true,
-		"index": 160,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM160G.DEF"
-		}
-	},
-	"godPeace" :
-	{
-		"disabled" : true,
-		"index": 161,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM161G.DEF"
-		}
-	},
-	"godMana" :
-	{
-		"disabled" : true,
-		"index": 162,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM162G.DEF"
-		}
-	},
-	"godLore" :
-	{
-		"disabled" : true,
-		"index": 163,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM163G.DEF"
-		}
-	},
-	"minotaurKing2" :// WTF is this? Same ID as Minotaur King from Dungeon
-	{
-		"index": 164,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM164GD.DEF"
-		},
-		"sound" :
-		{
-			"attack": "SGLMATTK.wav",
-			"defend": "SGLMDFND.wav",
-			"killed": "SGLMKILL.wav",
-			"move": "SGLMMOVE.wav",
-			"wince": "SGLMWNCE.wav"
-		}
-	},
-	"mineralElemental" :
-	{
-		"index": 165,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM165GD.DEF"
-		},
-		"sound" :
-		{
-			"attack": "SGLMATTK.wav",
-			"defend": "SGLMDFND.wav",
-			"killed": "SGLMKILL.wav",
-			"move": "SGLMMOVE.wav",
-			"wince": "SGLMWNCE.wav"
-		}
-	},
-	"electricityElemental" :
-	{
-		"index": 166,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM166GD.DEF"
-		},
-		"sound" :
-		{
-			"attack": "SGLMATTK.wav",
-			"defend": "SGLMDFND.wav",
-			"killed": "SGLMKILL.wav",
-			"move": "SGLMMOVE.wav",
-			"wince": "SGLMWNCE.wav"
-		}
-	},
-	"ancientBasilisk" :
-	{
-		"index": 167,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM167GD.DEF"
-		},
-		"sound" :
-		{
-			"attack": "SGLMATTK.wav",
-			"defend": "SGLMDFND.wav",
-			"killed": "SGLMKILL.wav",
-			"move": "SGLMMOVE.wav",
-			"wince": "SGLMWNCE.wav"
-		}
-	},
-	"gorynych" :
-	{
-		"index": 168,
-		"level": 7,
-		"faction": "neutral",
-		"abilities":
-		{
-			"canFly" :
-			{
-				"type" : "FLYING"
-			},
-			"noRetaliation" : 
-			{
-				"type" : "BLOCKS_RETALIATION"
-			},
-			"fearless" :
-			{
-				"type" : "FEARLESS"
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM168DG.DEF"
-		},
-		"sound" :
-		{
-			"attack": "BKDRATTK.wav",
-			"defend": "BKDRDFND.wav",
-			"killed": "BKDRKILL.wav",
-			"move": "BKDRMOVE.wav",
-			"wince": "BKDRWNCE.wav"
-		}
-	},
-	"warZealot" :
-	{
-		"index": 169,
-		"level": 6,
-		"growth" : 3,
-		"faction": "castle",
-		"abilities":
-		{
-			"spellMagicMirror" :
-			{
-				"type" : "ENCHANTED",
-				"subtype" : "spell.magicMirror",
-				"val" : 3,
-				"addInfo" : 100
-			},
-			"fearless" :
-			{
-				"type" : "FEARLESS"
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM169ZL.DEF",
-			"missile" :
-			{
-				"projectile": "CPRZEAX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "ZELTATTK.wav",
-			"defend": "ZELTDFND.wav",
-			"killed": "ZELTKILL.wav",
-			"move": "ZELTMOVE.wav",
-			"shoot": "ZELTSHOT.wav",
-			"wince": "ZELTWNCE.wav"
-		}
-	},
-	"arcticSharpshooter" :
-	{
-		"index": 170,
-		"level": 5,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM170SW.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "HCRSATTK.wav",
-			"defend": "HCRSDFND.wav",
-			"killed": "HCRSKILL.wav",
-			"move": "HCRSMOVE.wav",
-			"shoot": "HCRSSHOT.wav",
-			"wince": "HCRSWNCE.wav"
-		}
-	},
-	"lavaSharpshooter" :
-	{
-		"index": 171,
-		"level": 5,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM171SR.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "HCRSATTK.wav",
-			"defend": "HCRSDFND.wav",
-			"killed": "HCRSKILL.wav",
-			"move": "HCRSMOVE.wav",
-			"shoot": "HCRSSHOT.wav",
-			"wince": "HCRSWNCE.wav"
-		}
-	},
-	"nightmare" :
-	{
-		"index": 172,
-		"level": 6,
-		"faction": "neutral",
-		"abilities":
-		{
-			"deathStare" : 
-			{
-				"type" : "DEATH_STARE",
-				"subtype" : 0,
-				"val" : 10
-			},
-			"mindImmunity" :
-			{
-				"type" : "MIND_IMMUNITY"
-			},
-			"fearless" :
-			{
-				"type" : "FEARLESS"
-			}
-		},
-		"upgrades": ["hellSteed"],
-		"graphics" :
-		{
-			"animation": "ZM172N.DEF"
-		},
-		"sound" :
-		{
-			"attack": "BGORATTK.wav",
-			"defend": "BGORDFND.wav",
-			"killed": "BGORKILL.wav",
-			"move": "BGORMOVE.wav",
-			"wince": "BGORWNCE.wav"
-		}
-	},
-	"santaGremlin" :
-	{
-		"index": 173,
-		"level": 3,
-		"faction": "tower",
-		"growth" : 16,
-		"abilities":
-		{
-			"castsImplosion" :
-			{
-				"type" : "SPELLCASTER",
-				"subtype" : "spell.iceBolt",
-				"addInfo" : 2,
-				"val" : 2
-			},
-			"spellpower" :
-			{
-				"type" : "CREATURE_SPELL_POWER",
-				"val" : 100
-			},
-			"casts" :
-			{
-				"type" : "CASTS",
-				"val" : 12
-			},
-		},	
-		"graphics" :
-		{
-			"animation": "ZM173M.DEF"
-		},
-		"sound" :
-		{
-			"attack": "AAGLATTK.wav",
-			"defend": "AAGLDFND.wav",
-			"killed": "AAGLKILL.wav",
-			"move": "AAGLMOVE.wav",
-			"wince": "AAGLWNCE.wav"
-		}
-	},
-	"paladin1" :
-	{
-		"special" : true,
-		"index": 174,
-		"level": 0,
-		"faction": "neutral",
-		"abilities":
-		{
-			"magicResistance" :
-			{
-				"type" : "MAGIC_RESISTANCE",
-				"val" : 5
-			},
-			"castsAmount" :
-			{
-				"type" : "CASTS",
-				"val" : 1
-			},
-			"enchant" :
-			{
-				"type" : "CREATURE_ENCHANT_POWER",
-				"val" : 1
-			},
-			"spellpower" :
-			{
-				"type" : "CREATURE_SPELL_POWER",
-				"val" : 100
-			},
-			"canCast" :
-			{
-				"type" : "SPELLCASTER",
-				"subtype" : "spell.cure",
-				"val" : 3
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM174NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "CRUSATTK.wav",
-			"defend": "CRUSDFND.wav",
-			"killed": "CRUSKILL.wav",
-			"move": "CRUSMOVE.wav",
-			"wince": "CRUSWNCE.wav"
-		}
-	},
-	"hierophant1" :
-	{
-		"special" : true,
-		"index": 175,
-		"level": 0,
-		"faction": "neutral",
-		"abilities":
-		{
-			"magicResistance" :
-			{
-				"type" : "MAGIC_RESISTANCE",
-				"val" : 5
-			},
-			"castsAmount" :
-			{
-				"type" : "CASTS",
-				"val" : 1
-			},
-			"enchant" :
-			{
-				"type" : "CREATURE_ENCHANT_POWER",
-				"val" : 1
-			},
-			"spellpower" :
-			{
-				"type" : "CREATURE_SPELL_POWER",
-				"val" : 100
-			},
-			"canCast" :
-			{
-				"type" : "SPELLCASTER",
-				"subtype" : "spell.shield",
-				"val" : 3
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM175NPC.DEF",
-			"missile" :
-			{
-				"projectile": "CPRZEAX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "MONKATTK.wav",
-			"defend": "MONKDFND.wav",
-			"killed": "MONKKILL.wav",
-			"move": "MONKMOVE.wav",
-			"shoot": "MONKSHOT.wav",
-			"wince": "MONKWNCE.wav"
-		}
-	},
-	"templeGuardian1" :
-	{
-		"special" : true,
-		"index": 176,
-		"level": 0,
-		"faction": "neutral",
-		"abilities":
-		{
-			"magicResistance" :
-			{
-				"type" : "MAGIC_RESISTANCE",
-				"val" : 5
-			},
-			"castsAmount" :
-			{
-				"type" : "CASTS",
-				"val" : 1
-			},
-			"enchant" :
-			{
-				"type" : "CREATURE_ENCHANT_POWER",
-				"val" : 1
-			},
-			"spellpower" :
-			{
-				"type" : "CREATURE_SPELL_POWER",
-				"val" : 100
-			},
-			"canCast" :
-			{
-				"type" : "SPELLCASTER",
-				"subtype" : "spell.precision",
-				"val" : 3
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM176NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "LICHATTK.wav",
-			"defend": "LICHDFND.wav",
-			"killed": "LICHKILL.wav",
-			"move": "LICHMOVE.wav",
-			"shoot": "LICHSHOT.wav",
-			"wince": "LICHWNCE.wav"
-		}
-	},
-	"succubus1" :
-	{
-		"special" : true,
-		"index": 177,
-		"level": 0,
-		"faction": "neutral",
-		"abilities":
-		{
-			"magicResistance" :
-			{
-				"type" : "MAGIC_RESISTANCE",
-				"val" : 5
-			},
-			"castsAmount" :
-			{
-				"type" : "CASTS",
-				"val" : 1
-			},
-			"enchant" :
-			{
-				"type" : "CREATURE_ENCHANT_POWER",
-				"val" : 1
-			},
-			"spellpower" :
-			{
-				"type" : "CREATURE_SPELL_POWER",
-				"val" : 100
-			},
-			"canCast" :
-			{
-				"type" : "SPELLCASTER",
-				"subtype" : "spell.fireShield",
-				"val" : 3
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM177NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "SGRGATTK.wav",
-			"defend": "SGRGDFND.wav",
-			"killed": "SGRGKILL.wav",
-			"move": "SGRGMOVE.wav",
-			"wince": "SGRGWNCE.wav"
-		}
-	},
-	"soulEater1" :
-	{
-		"special" : true,
-		"index": 178,
-		"level": 0,
-		"faction": "neutral",
-		"abilities":
-		{
-			"magicResistance" :
-			{
-				"type" : "MAGIC_RESISTANCE",
-				"val" : 5
-			},
-			"castsAmount" :
-			{
-				"type" : "CASTS",
-				"val" : 1
-			},
-			"enchant" :
-			{
-				"type" : "CREATURE_ENCHANT_POWER",
-				"val" : 1
-			},
-			"spellpower" :
-			{
-				"type" : "CREATURE_SPELL_POWER",
-				"val" : 100
-			},
-			"canCast" :
-			{
-				"type" : "SPELLCASTER",
-				"subtype" : "spell.animateDead",
-				"val" : 3
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM178NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "GNOLATTK.wav",
-			"defend": "GNOLDFND.wav",
-			"killed": "GNOLKILL.wav",
-			"move": "GNOLMOVE.wav",
-			"wince": "GNOLWNCE.wav"
-		}
-	},
-	"brute1" :
-	{
-		"special" : true,
-		"index": 179,
-		"level": 0,
-		"faction": "neutral",
-		"abilities":
-		{
-			"magicResistance" :
-			{
-				"type" : "MAGIC_RESISTANCE",
-				"val" : 5
-			},
-			"castsAmount" :
-			{
-				"type" : "CASTS",
-				"val" : 1
-			},
-			"enchant" :
-			{
-				"type" : "CREATURE_ENCHANT_POWER",
-				"val" : 1
-			},
-			"spellpower" :
-			{
-				"type" : "CREATURE_SPELL_POWER",
-				"val" : 100
-			},
-			"canCast" :
-			{
-				"type" : "SPELLCASTER",
-				"subtype" : "spell.stoneSkin",
-				"val" : 3
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM179NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "PFOEATTK.wav",
-			"defend": "PFOEDFND.wav",
-			"killed": "PFOEKILL.wav",
-			"move": "PFOEMOVE.wav",
-			"wince": "PFOEWNCE.wav"
-		}
-	},
-	"ogreLeader1" :
-	{
-		"special" : true,
-		"index": 180,
-		"level": 0,
-		"faction": "neutral",
-		"abilities":
-		{
-			"magicResistance" :
-			{
-				"type" : "MAGIC_RESISTANCE",
-				"val" : 5
-			},
-			"castsAmount" :
-			{
-				"type" : "CASTS",
-				"val" : 1
-			},
-			"enchant" :
-			{
-				"type" : "CREATURE_ENCHANT_POWER",
-				"val" : 1
-			},
-			"spellpower" :
-			{
-				"type" : "CREATURE_SPELL_POWER",
-				"val" : 100
-			},
-			"canCast" :
-			{
-				"type" : "SPELLCASTER",
-				"subtype" : "spell.cure",
-				"val" : 3
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM180NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "TRLLATTK.wav",
-			"defend": "TRLLDFND.wav",
-			"killed": "TRLLKILL.wav",
-			"move": "TRLLMOVE.wav",
-			"wince": "TRLLWNCE.wav"
-		}
-	},
-	"shaman1" :
-	{
-		"special" : true,
-		"index": 181,
-		"level": 0,
-		"faction": "neutral",
-		"abilities":
-		{
-			"magicResistance" :
-			{
-				"type" : "MAGIC_RESISTANCE",
-				"val" : 5
-			},
-			"castsAmount" :
-			{
-				"type" : "CASTS",
-				"val" : 1
-			},
-			"enchant" :
-			{
-				"type" : "CREATURE_ENCHANT_POWER",
-				"val" : 1
-			},
-			"spellpower" :
-			{
-				"type" : "CREATURE_SPELL_POWER",
-				"val" : 100
-			},
-			"canCast" :
-			{
-				"type" : "SPELLCASTER",
-				"subtype" : "spell.haste",
-				"val" : 3
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM181NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "AMAGATTK.wav",
-			"defend": "AMAGDFND.wav",
-			"killed": "AMAGKILL.wav",
-			"move": "AMAGMOVE.wav",
-			"shoot": "AMAGSHOT.wav",
-			"wince": "AMAGWNCE.wav"
-		}
-	},
-	"astralSpirit1" :
-	{
-		"special" : true,
-		"index": 182,
-		"level": 0,
-		"faction": "neutral",
-		"abilities":
-		{
-			"magicResistance" :
-			{
-				"type" : "MAGIC_RESISTANCE",
-				"val" : 5
-			},
-			"castsAmount" :
-			{
-				"type" : "CASTS",
-				"val" : 1
-			},
-			"enchant" :
-			{
-				"type" : "CREATURE_ENCHANT_POWER",
-				"val" : 1
-			},
-			"spellpower" :
-			{
-				"type" : "CREATURE_SPELL_POWER",
-				"val" : 100
-			},
-			"canCast" :
-			{
-				"type" : "SPELLCASTER",
-				"subtype" : "spell.counterstrike",
-				"val" : 3
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM182NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "GENIATTK.wav",
-			"defend": "GENIDFND.wav",
-			"killed": "GENIKILL.wav",
-			"move": "GENIMOVE.wav",
-			"wince": "GENIWNCE.wav"
-		}
-	},
-	"paladin2" :
-	{
-		"special" : true,
-		"index": 183,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM174NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		}
-	},
-	"hierophant2" :
-	{
-		"special" : true,
-		"disabled" : true,
-		"index": 184,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM175NPC.DEF",
-			"missile" :
-			{
-				"projectile": "CPRZEAX.DEF"
-			}
-		}
-	},
-	"templeGuardian2" :
-	{
-		"special" : true,
-		"disabled" : true,
-		"index": 185,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM176NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		}
-	},
-	"succubus2" :
-	{
-		"special" : true,
-		"disabled" : true,
-		"index": 186,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM177NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		}
-	},
-	"soulEater2" :
-	{
-		"special" : true,
-		"disabled" : true,
-		"index": 187,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM178NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		}
-	},
-	"brute2" :
-	{
-		"special" : true,
-		"disabled" : true,
-		"index": 188,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM179NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		}
-	},
-	"ogreLeader2" :
-	{
-		"special" : true,
-		"disabled" : true,
-		"index": 189,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM180NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		}
-	},
-	"shaman2" :
-	{
-		"special" : true,
-		"disabled" : true,
-		"index": 190,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM181NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		}
-	},
-	"astralSpirit2" :
-	{
-		"special" : true,
-		"disabled" : true,
-		"index": 191,
-		"level": 0,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM182NPC.DEF",
-			"missile" :
-			{
-				"projectile": "PLCBOWX.DEF"
-			}
-		}
-	},
-	"sylvanCentaur" :
-	{
-		"index": 192,
-		"growth" : 14,
-		"level": 3,
-		"doubleWide" : true,
-		"faction": "rampart",
-		"abilities" :
-		{
-			"additionalAttack" :
-			{
-				"type" : "ADDITIONAL_ATTACK",
-				"val" : 1
-			},
-			"spellMirth" :
-			{
-				"type" : "ENCHANTED",
-				"subtype" : "spell.mirth",
-				"val" : 1,
-				"addInfo" : 3 
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM192Z.DEF",
-			"missile" :
-			{
-				"projectile": "PELFX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "ECNTATTK.wav",
-			"defend": "ECNTDFND.wav",
-			"killed": "ECNTKILL.wav",
-			"move": "ECNTMOVE.wav",
-			"shoot": "ECNTSHOT.wav",
-			"wince": "ECNTWNCE.wav"
-		}
-	},
-	"sorceress" :
-	{
-		"index": 193,
-		"level": 6,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM193Z.DEF",
-			"missile" :
-			{
-				"projectile": "CPRZEAX.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "MONKATTK.wav",
-			"defend": "MONKDFND.wav",
-			"killed": "MONKKILL.wav",
-			"move": "MONKMOVE.wav",
-			"shoot": "MONKSHOT.wav",
-			"wince": "MONKWNCE.wav"
-		}
-	},
-	"werewolf" :
-	{
-		"index": 194,
-		"level": 4,
-		"faction": "neutral",
-		"graphics" :
-		{
-			"animation": "ZM194Z.DEF"
-		}
-	},
-	"hellSteed" :
-	{
-		"index": 195,
-		"level": 6,
-		"faction": "neutral",
-		"abilities":
-		{
-			"immuneToFire" :
-			{
-				"type" : "FIRE_IMMUNITY",
-				"subtype" : 0 //this IS important
-			},
-			"fireShield" :
-			{
-				"type" : "FIRE_SHIELD",
-				"subtype" : 100,
-				"val" : 100
-			},
-			"spellFireWall" :
-			{
-				"type" : "SPELL_AFTER_ATTACK",
-				"subtype" : "spell.fireWall",
-				"val" : 12,
-				"addInfo" : 3
-			},
-			"spellpower" :
-			{
-				"type" : "CREATURE_SPELL_POWER",
-				"val" : 100
-			}
-		},
-		"upgrades": ["nightmare"],
-		"graphics" :
-		{
-			"animation": "ZM195Z.DEF"
-		},
-		"sound" :
-		{
-			"attack": "BGORATTK.wav",
-			"defend": "BGORDFND.wav",
-			"killed": "BGORKILL.wav",
-			"move": "BGORMOVE.wav",
-			"wince": "BGORWNCE.wav"
-		}
-	},
-	"dracolich" :
-	{
-		"index": 196,
-		"level": 10,
-		"faction": "neutral",
-		"abilities":
-		{
-			"dragon" : 
-			{
-				"type" : "DRAGON_NATURE",
-			},
-			"dragonBreath" :
-			{
-				"type" : "TWO_HEX_ATTACK_BREATH"
-			},
-			"undead" :
-			{
-				"type" : "UNDEAD"
-			},
-			"canFly" : 
-			{
-				"type" : "FLYING"
-			},
-			"deathCloud" :
-			{
-				"type" : "SPELL_LIKE_ATTACK",
-				"subtype" : "spell.deathCloud"
-			},
-			"canShoot" :
-			{
-				"type" : "SHOOTER"
-			}
-		},
-		"graphics" :
-		{
-			"animation": "ZM196Z.DEF",
-			"missile" :
-			{
-				"projectile": "ZSHOT195.DEF"
-			}
-		},
-		"sound" :
-		{
-			"attack": "GHDRATTK.wav",
-			"defend": "GHDRDFND.wav",
-			"killed": "GHDRKILL.wav",
-			"move": "GHDRMOVE.wav",
-			"shoot": "GHDRSHOT.wav",
-			"wince": "GHDRWNCE.wav"
-		}
-	}
-}
-
-// For future reference. Creatures from WoG and their sound prefixes.
-//aagl ZM150Z.def SupremeArchangel
-//godr ZM151Z.def DiamondDragon
-//gtit ZM152Z.def LordofThunder
-//advl ZM153Z.def HellBaron
-//ghdr ZM154Z.def BloodDragon
-//bkdr ZM155Z.def DarknessDragon
-//bmth ZM156Z.def GhostBehemoth
-//chyd ZM157Z.def HellHydra
-//phoe ZM158Z.def SacredPhoenix
-//wrth ZM159G.def Ghost
-//aagl ZM160G.def God1War
-//aagl ZM161G.def God2Peace
-//aagl ZM162G.def God3Mana
-//aagl ZM163G.def God4Lore
-//sglm ZM164GD.def MinotaurKing
-//sglm ZM165GD.def MineralElemental
-//sglm ZM166GD.def ElectricityElemental
-//sglm ZM167GD.def AncientBasilisk
-//bkdr ZM168DG.def Gorynych
-//zelt ZM169ZL.def WarZealot
-//hcrs ZM170SW.def Myriad
-//hcrs ZM171SR.def MedusaMatriarch
-//bgor ZM172N.def Nightmare
-//aagl ZM173M.def SantaGremlin
-
-//crus ZM174NPC.def Paladin2
-//monk ZM175NPC.def Hierophant2
-//lich ZM176NPC.def TempleGuardian2
-//sgrg ZM177NPC.def Succubus2
-//gnol ZM178NPC.def SoulEater2
-///pfoe ZM179NPC.def Brute2
-//trll ZM180NPC.def OgreLeader2
-//amag ZM181NPC.def Shaman2
-//geni ZM182NPC.def AstralSpirit2
-
-//ecnt ZM192Z.def SylvanCentaur
-//monk ZM193Z.def Sorceress
-//monk ZM194Z.def Werewolf
-//bgor ZM195Z.def HellSteed
-//ghdr ZM196Z.def Dracolich

+ 0 - 31
Mods/WoG/config/wog/dwellings.json

@@ -1,31 +0,0 @@
-{
-	"core:creatureGeneratorCommon" : {
-		"types" : {
-			"supremeArchangel" : { "index" : 80, "creatures" : [[ "supremeArchangel" ]] },
-			"diamondDragon" : { "index" : 81, "creatures" : [[ "diamondDragon" ]] },
-			"lordofThunder" : { "index" : 82, "creatures" : [[ "lordofThunder" ]] },
-			"hellBaron" : { "index" : 83, "creatures" : [[ "hellBaron" ]] },
-			"bloodDragon" : { "index" : 84, "creatures" : [[ "bloodDragon" ]] },
-
-			"darknessDragon" : { "index" : 85, "creatures" : [[ "darknessDragon" ]] },
-			"ghostBehemoth" : { "index" : 86, "creatures" : [[ "ghostBehemoth" ]] },
-			"hellHydra" : { "index" : 87, "creatures" : [[ "hellHydra" ]] },
-			"sacredPhoenix" : { "index" : 88, "creatures" : [[ "sacredPhoenix" ]] },
-			"lavaSharpshooter" : { "index" : 89, "creatures" : [[ "lavaSharpshooter" ]] },
-
-			"arcticSharpshooter" : { "index" : 90, "creatures" : [[ "arcticSharpshooter" ]] },
-			"gorynych" : { "index" : 91, "creatures" : [[ "gorynych" ]] },
-			"nightmare" : { "index" : 92, "creatures" : [[ "nightmare" ]] },
-			"minotaurKing2" : { "index" : 93, "creatures" : [[ "minotaurKing2" ]] },
-			"warZealot" : { "index" : 94, "creatures" : [[ "warZealot" ]] },
-
-			"santaGremlin" : { "index" : 95, "creatures" : [[ "santaGremlin" ]] },
-			"sylvanCentaur" : { "index" : 96, "creatures" : [[ "sylvanCentaur" ]] },
-			"sorceress" : { "index" : 97, "creatures" : [[ "sorceress" ]] },
-			"werewolf" : { "index" : 98, "creatures" : [[ "werewolf" ]] },
-			"hellSteed" : { "index" : 99, "creatures" : [[ "hellSteed" ]] },
-
-			"dracolich" : { "index" :100, "creatures" : [[ "dracolich" ]] }
-		}
-	}
-}

+ 0 - 74
Mods/WoG/config/wog/heroClasses.json

@@ -1,74 +0,0 @@
-{
-        "core:knight" :
-        {
-                "commander" : "paladin1"
-        },
-        "core:cleric" :
-        {
-                "commander" : "paladin1"
-        },
-        "core:planeswalker" :
-        {
-                "commander" : "astralSpirit1"
-        },
-        "core:elementalist" :
-        {
-                "commander" : "astralSpirit1"
-        },
-        "core:warlock" :
-        {
-                "commander" : "brute1"
-        },
-        "core:overlord" :
-        {
-                "commander" : "brute1"
-        },
-        "core:beastmaster" :
-        {
-                "commander" : "shaman1"
-        },
-        "core:witch" :
-        {
-                "commander" : "shaman1"
-        },
-        "core:demoniac" :
-        {
-                "commander" : "succubus1"
-        },
-        "core:heretic" :
-        {
-                "commander" : "succubus1"
-        },
-        "core:deathknight" :
-        {
-                "commander" : "soulEater1"
-        },
-        "core:necromancer" :
-        {
-                "commander" : "soulEater1"
-        },
-        "core:ranger" :
-        {
-                "commander" : "hierophant1"
-        },
-        "core:druid" :
-        {
-                "commander" : "hierophant1"
-        },
-        "core:barbarian" :
-        {
-                "commander" : "ogreLeader1"
-        },
-        "core:battlemage" :
-        {
-                "commander" : "ogreLeader1"
-        },
-        "core:alchemist" :
-        {
-                "commander" : "templeGuardian1"
-        },
-        "core:wizard" :
-        {
-                "commander" : "templeGuardian1"
-        }
-}

+ 0 - 57
Mods/WoG/config/wog/spells.json

@@ -1,57 +0,0 @@
-{
-
-        "core:implosion" :
-        {
-                "graphics" : {
-			"iconImmune" : "ZVS/LIB1.RES/E_SPIMP"
-		}
-        },
-
-        "core:meteorShower" : {
-		"graphics" : {
-			"iconImmune" : "ZVS/LIB1.RES/E_SPMET"
-		}
-	},
-	"core:armageddon" : {
-
-		"graphics" : {
-			"iconImmune" : "ZVS/LIB1.RES/E_SPARM"
-		}
-
-	},
-	"core:dispel" : {
-
-		"graphics" : {
-			"iconImmune" : "ZVS/LIB1.RES/E_SPDISP"
-		}
-
-	},
-        "core:slow" : {
-		"graphics" : {
-			"iconImmune" : "ZVS/LIB1.RES/E_SPSLOW"
-		}
-        },
-
-        "core:berserk" : {
-		"graphics" : {
-			"iconImmune" : "ZVS/LIB1.RES/E_SPBERS"
-		}
-        },
-	"core:hypnotize" : {
-                "graphics" : {
-			"iconImmune" : "ZVS/LIB1.RES/E_SPHYPN"
-		}
-        },
-
-        "core:blind" : {
-		"graphics" : {
-			"iconImmune" : "ZVS/LIB1.RES/E_SPBLIND"
-		}
-        },
-
-        "core:dispelHelpful" : {
-		"graphics" : {
-			"iconImmune" : "ZVS/LIB1.RES/E_SPDISB"
-		}
-        }
-}

+ 0 - 45
Mods/WoG/config/wogFileOverrides.json

@@ -1,45 +0,0 @@
-{
-	// Text configs
-	"data/crgen1.txt"   : "data/zcrgn1.txt",
-	"data/crtraits.txt" : "data/zcrtrait.txt",
-	"data/help.txt"     : "data/zelp.txt",
-	"data/objects.txt"  : "data/zobjcts.txt",
-
-	// main menu images
-	"data/gamselb0.bmp" : "data/ZPIC1000.bmp", // map selection screen
-	"data/gamselb1.bmp" : "data/ZPIC1001.bmp", // map selection screen
-	"data/loadbar.bmp"  : "data/ZPIC106.bmp",  // loading screen
-	"data/gamselbk.bmp" : "data/ZPIC1005.bmp", // background
-	"data/newgame.bmp"  : "data/ZNEWGAM.bmp",  // "new  game" text
-	"data/loadgame.bmp" : "data/ZLOADGAM.bmp", // "load game" text
-
-	// main menu buttons
-	"sprites/mmenung.def" : "sprites/zmenung.def",
-	"sprites/mmenulg.def" : "sprites/zmenulg.def",
-	"sprites/mmenuhs.def" : "sprites/zmenuhs.def",
-	"sprites/mmenucr.def" : "sprites/zmenucr.def",
-	"sprites/mmenuqt.def" : "sprites/zmenuqt.def",
-
-	// game type select (single/multi/campaign)
-	"sprites/gtsingl.def" : "sprites/ztsingl.def",
-	"sprites/gtmulti.def" : "sprites/ztmulti.def",
-	"sprites/gtcampn.def" : "sprites/ztcampn.def",
-	"sprites/gttutor.def" : "sprites/zttutor.def",
-	"sprites/gtback.def"  : "sprites/ztback.def",
-
-	// campaigns
-	"sprites/csssod.def" : "sprites/zsssod.def",
-	"sprites/cssroe.def" : "sprites/zssroe.def",
-	"sprites/cssarm.def" : "sprites/zssarm.def",
-	"sprites/csscus.def" : "sprites/zsscus.def",
-
-	// resource bars
-	"data/tresbar.bmp" : "data/zresbar.bmp",
-	"data/kresbar.bmp" : "data/z2esbar.bmp",
-	"data/aresbar.bmp" : "data/zresbar.bmp",
-
-	// misc
-	"data/tpcainfo.bmp" : "data/zpcainfo.bmp", // stats images for town fort
-	"music/mainmenu.mp3" : "music/mainmenuwog.mp3",
-	"video/credits.bik" : "video/acredit.bik"
-}

+ 0 - 72
Mods/WoG/mod.json

@@ -1,72 +0,0 @@
-{
-	"name" : "In The Wake of Gods",
-	"description" : "Unnofficial addon for Heroes of Might and Magic III",
-
-	"version" : "0.0.0",
-	"author" : "WoG Team",
-	"contact" : "http://forum.vcmi.eu/index.php",
-	"modType" : "Expansion",
-
-	"artifacts" : 
-	[
-		"config/wog/artifacts.json"
-	],
-
-	"creatures" : 
-	[
-		"config/wog/creatures.json"
-	],
-
-	"heroClasses" : 
-	[
-		"config/wog/heroClasses.json"
-	],
-
-	"objects" :
-	[
-		"config/wog/dwellings.json",
-		"config/wog/creatureBanks.json"
-	],
-
-	"filesystem":
-	{
-		"" :
-		[
-			{ "type" : "map", "path" : "/Config/wogFileOverrides.json"}
-		],
-		"CONFIG/" :
-		[
-			{ "type" : "dir", "path" : "/Config"}
-		],
-		"DATA/" :
-		[
-			{"type" : "lod", "path" : "/Data/hmm35wog.pac"},
-			{"type" : "dir", "path" : "/Data"}
-		],
-		"SPRITES/":
-		[
-			{"type" : "lod", "path" : "/Data/hmm35wog.pac"},
-			{"type" : "lod", "path" : "/Data/wog - animated objects.pac"},
-			{"type" : "lod", "path" : "/Data/wog - animated trees.pac"},
-			{"type" : "lod", "path" : "/Data/wog - battle decorations.pac"}
-		],
-		"SOUNDS/":
-		[
-			{"type" : "snd", "path" : "/Data/wog - sounds.snd"},
-			{"type" : "snd", "path" : "/Data/wog.snd"}
-		],
-		"MUSIC/":
-		[
-			{"type" : "dir", "path" : "/Mp3"}
-		],
-		"VIDEO/":
-		[
-			{"type" : "vid", "path" : "/Data/wog - video.vid"},
-			{"type" : "vid", "path" : "/Data/wog.vid"}
-		],
-		"MAPS/":
-		[
-			{"type" : "dir", "path" : "/Maps"}
-		]
-	}
-}

+ 3 - 0
client/CPreGame.cpp

@@ -881,6 +881,9 @@ void CSelectionScreen::startScenario()
 
 		if(sInfo.mapGenOptions)
 		{
+			//copy settings from interface to actual options. TODO: refactor, it used to have no effect at all -.-
+			sInfo.mapGenOptions = std::shared_ptr<CMapGenOptions>(new CMapGenOptions(randMapTab->getMapGenOptions()));
+
 			// Update player settings for RMG
 			for(const auto & psetPair : sInfo.playerInfos)
 			{

+ 50 - 2
config/objects/creatureBanks.json

@@ -7,6 +7,10 @@
 			{
 				"index" : 0,
 				"name" : "Cyclops Stockpile",
+				"rmg" : {
+					"value"		: 3000,
+					"rarity"	: 100
+				},
 				"levels": [
 					{
 						"chance": 30,
@@ -17,7 +21,7 @@
 							{ "amount": 4, "type": "cyclop" },
 							{ "amount": 4, "type": "cyclop" }
 						],
-						
+
 						"combat_value": 506,
 						"reward" : {
 							"value": 10000,
@@ -108,6 +112,10 @@
 				"index" : 1,
 				"resetDuraition" : 28,
 				"name" : "Dwarven Treasury",
+				"rmg" : {
+					"value"		: 2000,
+					"rarity"	: 100
+				},
 				"levels": [
 					{
 						"chance": 30,
@@ -191,6 +199,10 @@
 				"index" : 2,
 				"resetDuraition" : 28,
 				"name" : "Griffin Conservatory",
+				"rmg" : {
+					"value"		: 2000,
+					"rarity"	: 100
+				},
 				"levels": [
 					{
 						"chance": 30,
@@ -258,6 +270,10 @@
 				"index" : 3,
 				"resetDuraition" : 28,
 				"name" : "Imp Cache",
+				"rmg" : {
+					"value"		: 5000,
+					"rarity"	: 100
+				},
 				"levels": [
 					{
 						"chance": 30,
@@ -340,6 +356,10 @@
 				"index" : 4,
 				"resetDuraition" : 28,
 				"name" : "Medusa Stores",
+				"rmg" : {
+					"value"		: 1500,
+					"rarity"	: 100
+				},
 				"levels": [
 					{
 						"chance": 30,
@@ -423,6 +443,10 @@
 				"index" : 5,
 				"resetDuraition" : 28,
 				"name" : "Naga Bank",
+				"rmg" : {
+					"value"		: 3000,
+					"rarity"	: 100
+				},
 				"levels": [
 					{
 						"chance": 30,
@@ -506,6 +530,10 @@
 				"index" : 6,
 				"resetDuraition" : 28,
 				"name" : "Dragon Fly Hive",
+				"rmg" : {
+					"value"		: 9000,
+					"rarity"	: 100
+				},
 				"levels": [
 					{
 						"chance": 30,
@@ -579,6 +607,10 @@
 				"index" : 0,
 				"resetDuraition" : 28,
 				"name" : "Shipwreck",
+				"rmg" : {
+					"value"		: 2000,
+					"rarity"	: 100
+				},
 				"levels": [
 					{
 						"chance": 30,
@@ -666,6 +698,10 @@
 				"index" : 0,
 				"resetDuraition" : 28,
 				"name" : "Derelict Ship",
+				"rmg" : {
+					"value"		: 4000,
+					"rarity"	: 20
+				},
 				"levels": [
 					{
 						"chance": 30,
@@ -754,6 +790,10 @@
 				"index" : 0,
 				"resetDuraition" : 28,
 				"name" : "Crypt",
+				"rmg" : {
+					"value"		: 1000,
+					"rarity"	: 100
+				},
 				"levels": [
 					{
 						"chance": 30,
@@ -839,6 +879,10 @@
 				"index" : 0,
 				"resetDuraition" : 28,
 				"name" : "Dragon Utopia",
+				"rmg" : {
+					"value"		: 10000,
+					"rarity"	: 100
+				},
 				"levels": [
 					{
 						"chance": 30,
@@ -944,6 +988,10 @@
 				"index" : 0,
 				"resetDuraition" : 28,
 				"name" : "Pyramid",
+				"rmg" : {
+					"value"		: 5000,
+					"rarity"	: 20
+				},
 				"levels": [
 					{
 						"chance": 100,
@@ -963,4 +1011,4 @@
 			}
 		}
 	}
-}
+}

+ 450 - 40
config/objects/generic.json

@@ -9,56 +9,402 @@
 		}
 	},
 
-	"altarOfSacrifice"				: { "index" :2,   "handler": "market", "types" : { "object" : { "index" : 0} } },
-	"tradingPost"					: { "index" :221, "handler": "market", "types" : { "object" : { "index" : 0} } },
-	"tradingPostDUPLICATE"			: { "index" :99,  "handler": "market", "types" : { "object" : { "index" : 0} } },
-	"freelancersGuild"				: { "index" :213, "handler": "market", "types" : { "object" : { "index" : 0} } },
+	"altarOfSacrifice" : {
+		"index" :2,
+		"handler" : "market",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 100,
+					"rarity"	: 20
+				}
+			}
+		}
+	},
+	"tradingPost" : {
+		"index" :221,
+		"handler" : "market",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 100,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"tradingPostDUPLICATE"		: {
+		"index" :99, 
+		"handler" : "market",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 100,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"freelancersGuild" : {
+		"index" :213,
+		"handler" : "market",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"value"		: 100,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
 
-	"blackMarket"					: { "index" :7,   "handler": "blackMarket", "types" : { "object" : { "index" : 0} } },
+	"blackMarket" : {
+		"index" :7,
+		"handler" : "blackMarket",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 8000,
+					"rarity"	: 20
+				}
+			}
+		}
+	},
 
-	"pandoraBox"					: { "index" :6,   "handler": "pandora", "types" : { "object" : { "index" : 0} } },
-	"event"							: { "index" :26,  "handler": "event", "types" : { "object" : { "index" : 0} } },
+	"pandoraBox" : {
+		"index" :6,
+		"handler" : "pandora",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"templates" : {
+					"normal" : { "animation" : "ava0128.def", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] }
+				},
+				"rmg" : {
+				}
+			}
+		}
+	},
+	"event" : {
+		"index" :26, 
+		"handler" : "event",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+				}
+			}
+		}
+	},
 
-	"redwoodObservatory"			: { "index" :58,  "handler": "observatory", "types" : { "object" : { "index" : 0} } },
-	"pillarOfFire"					: { "index" :60,  "handler": "observatory", "types" : { "object" : { "index" : 0} } },
-	"coverOfDarkness"				: { "index" :15,  "handler": "observatory", "types" : { "object" : { "index" : 0} } },
+	"redwoodObservatory" : {
+		"index" :58, 
+		"handler" : "observatory",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 750,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"pillarOfFire" : {
+		"index" :60, 
+		"handler" : "observatory",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 750,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"coverOfDarkness" : {
+		"index" :15, 
+		"handler" : "observatory",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+				}
+			}
+		}
+	},
 	
-	"whirlpool"						: { "index" :111, "handler": "teleport", "types" : { "object" : { "index" : 0} } },
+	"whirlpool" : {
+		"index" :111,
+		"handler" : "teleport",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+				}
+			}
+		}
+	},
 	"subterraneanGate" : {
 		"index" :103,
-		"handler": "teleport",
+		"handler" : "teleport",
 		"types" : {
-			"object" : { "index" : 0 },
+			"object" : {
+				"index" : 0 },
 			"objectWoG" : { "index" : 1 } // WoG object? Present on VCMI Test 2011b
 		}
 	},
 
-	"refugeeCamp"					: { "index" :78,  "handler": "dwelling", "types" : { "object" : { "index" : 0} } },
-	"warMachineFactory"				: { "index" :106, "handler": "dwelling", "types" : { "object" : { "index" : 0} } },
-
-	"shrineOfMagicLevel1"			: { "index" :88,  "handler": "shrine", "types" : { "object" : { "index" : 0} } },
-	"shrineOfMagicLevel2"			: { "index" :89,  "handler": "shrine", "types" : { "object" : { "index" : 0} } },
-	"shrineOfMagicLevel3"			: { "index" :90,  "handler": "shrine", "types" : { "object" : { "index" : 0} } },
-
-	"eyeOfTheMagi"					: { "index" :27,  "handler": "magi", "types" : { "object" : { "index" : 0} } },
-	"hutOfTheMagi"					: { "index" :37,  "handler": "magi", "types" : { "object" : { "index" : 0} } },
-
-	"lighthouse"					: { "index" :42,  "handler": "lighthouse", "types" : { "object" : { "index" : 0} } },
-	"obelisk"						: { "index" :57,  "handler": "obelisk", "types" : { "object" : { "index" : 0} } },
-	"oceanBottle"					: { "index" :59,  "handler": "sign", "types" : { "object" : { "index" : 0} } },
-	"scholar"						: { "index" :81,  "handler": "scholar", "types" : { "object" : { "index" : 0} } },
-	"shipyard"						: { "index" :87,  "handler": "shipyard", "types" : { "object" : { "index" : 0} } },
-	"sign"							: { "index" :91,  "handler": "sign", "types" : { "object" : { "index" : 0} } },
-	"sirens"						: { "index" :92,  "handler": "siren", "types" : { "object" : { "index" : 0} } },
-	"denOfThieves"					: { "index" :97,  "handler": "denOfThieves", "types" : { "object" : { "index" : 0} } },
-	"university"					: { "index" :104, "handler": "university", "types" : { "object" : { "index" : 0} } },
-	"witchHut"						: { "index" :113, "handler": "witch", "types" : { "object" : { "index" : 0} } },
-	"questGuard"					: { "index" :215, "handler": "questGuard", "types" : { "object" : { "index" : 0} } },
+	"refugeeCamp" : {
+		"index" :78, 
+		"handler" : "dwelling",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"value"		: 5000,
+					"rarity"	: 20
+				}
+			}
+		}
+	},
+	"warMachineFactory" : {
+		"index" :106,
+		"handler" : "dwelling",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 1500,
+					"rarity"	: 50
+				}
+			}
+		}
+	},
+	"shrineOfMagicLevel1" : {//incantation
+		"index" :88, 
+		"handler" : "shrine",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 500,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"shrineOfMagicLevel2" : {//gesture
+		"index" :89, 
+		"handler" : "shrine",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 2000,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"shrineOfMagicLevel3" : {//thinking
+		"index" :90, 
+		"handler" : "shrine",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 3000,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"eyeOfTheMagi" : {
+		"index" :27, 
+		"handler" : "magi",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+				}
+			}
+		}
+	},
+	"hutOfTheMagi" : {
+		"index" :37, 
+		"handler" : "magi",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+				}
+			}
+		}
+	},
+	"lighthouse" : {
+		"index" :42, 
+		"handler" : "lighthouse",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+				}
+			}
+		}
+	},
+	"obelisk" : {
+		"index" :57, 
+		"handler" : "obelisk",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 48,
+					"value"		: 3500,
+					"rarity"	: 200
+				}
+			}
+		}
+	},
+	"oceanBottle" : {
+		"index" :59, 
+		"handler" : "sign",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+				}
+			}
+		}
+	},
+	"scholar" : {
+		"index" :81, 
+		"handler" : "scholar",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"value"		: 1500,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"shipyard" : {
+		"index" :87, 
+		"handler" : "shipyard",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+				}
+			}
+		}
+	},
+	"sign" : {
+		"index" :91, 
+		"handler" : "sign",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+				}
+			}
+		}
+	},
+	"sirens" : {
+		"index" :92, 
+		"handler" : "siren",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 100,
+					"rarity"	: 20
+				}
+			}
+		}
+	},
+	"denOfThieves" : {
+		"index" :97, 
+		"handler" : "denOfThieves",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+				}
+			}
+		}
+	},
+	"university" : {
+		"index" :104,
+		"handler" : "university",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 2500,
+					"rarity"	: 20
+				}
+			}
+		}
+	},
+	"witchHut" : {
+		"index" :113,
+		"handler" : "witch",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 3,
+					"mapLimit"	: 32,
+					"value"		: 1500,
+					"rarity"	: 80
+				}
+			}
+		}
+	},
+	"questGuard" : {
+		"index" :215,
+		"handler" : "questGuard",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+				}
+			}
+		}
+	},
 	"magicWell" : {
 		"index" :49,
-		"handler": "magicWell",
+		"handler" : "magicWell",
 		"types" : {
-			"object" : { "index" : 0},
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"value"		: 250,
+					"rarity"	: 100
+				}
+			},
 			"objectWoG" : { "index" : 1} // WoG object? Present on VCMI_Test 2011b
 		}
 	},
@@ -99,6 +445,10 @@
 		"types" : {
 			"object" : {
 				"index" : 0,
+				"rmg" : {
+					"value"		: 2000,
+					"rarity"	: 150
+				},
 				"templates" : {
 					"normal" : { "animation" : "AVArnd1", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] }
 				}
@@ -111,6 +461,10 @@
 		"types" : {
 			"object" : {
 				"index" : 0,
+				"rmg" : {
+					"value"		: 5000,
+					"rarity"	: 150
+				},
 				"templates" : {
 					"normal" : { "animation" : "AVArnd2", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] }
 				}
@@ -123,6 +477,10 @@
 		"types" : {
 			"object" : {
 				"index" : 0,
+				"rmg" : {
+					"value"		: 10000,
+					"rarity"	: 150
+				},
 				"templates" : {
 					"normal" : { "animation" : "AVArnd3", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] }
 				}
@@ -135,6 +493,10 @@
 		"types" : {
 			"object" : {
 				"index" : 0,
+				"rmg" : {
+					"value"		: 20000,
+					"rarity"	: 150
+				},
 				"templates" : {
 					"normal" : { "animation" : "AVArnd4", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] }
 				}
@@ -240,10 +602,58 @@
 	},
 
 	/// Classes without dedicated object
-	"hillFort"						: { "index" :35,  "handler": "generic", "types" : { "object" : { "index" : 0} } },
-	"grail"							: { "index" :36,  "handler": "generic", "types" : { "object" : { "index" : 0} } },
-	"tavern"						: { "index" :95,  "handler": "generic", "types" : { "object" : { "index" : 0} } },
-	"sanctuary"						: { "index" :80,  "handler": "generic", "types" : { "object" : { "index" : 0} } },
+	"hillFort" : {
+		"index" :35, 
+		"handler": "generic",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 7000,
+					"rarity"	: 20
+				}
+			}
+		}
+	},
+	"grail" : {
+		"index" :36, 
+		"handler": "generic",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+				}
+			}
+		}
+	},
+	"tavern" : {
+		"index" :95, 
+		"handler": "generic",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"value"		: 100,
+					"rarity"	: 20
+				}
+			}
+		}
+	},
+	"sanctuary" : {
+		"index" :80, 
+		"handler": "generic",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 100,
+					"rarity"	: 50
+				}
+			}
+		}
+	},
 
 	/// Passive objects, terrain overlays
 	"cursedGround"					: { "index" :21,  "handler": "generic", "types" : { "object" : { "index" : 0} } },

+ 20 - 20
config/objects/moddables.json

@@ -50,13 +50,13 @@
 			}
 		},
 		"types" : {
-			"wood" :    { "index" : 0, "templates" : { "res" : { "animation" : "AVTwood0.def" } } },
-			"mercury" : { "index" : 1, "templates" : { "res" : { "animation" : "AVTmerc0.def" } } },
-			"ore" :     { "index" : 2, "templates" : { "res" : { "animation" : "AVTore0.def"  } } },
-			"sulfur" :  { "index" : 3, "templates" : { "res" : { "animation" : "AVTsulf0.def" } } },
-			"crystal" : { "index" : 4, "templates" : { "res" : { "animation" : "AVTcrys0.def" } } },
-			"gems" :    { "index" : 5, "templates" : { "res" : { "animation" : "AVTgems0.def" } } },
-			"gold" :    { "index" : 6, "templates" : { "res" : { "animation" : "AVTgold0.def" } } },
+			"wood" :    { "index" : 0, "rmg" : { "value" : 1400, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTwood0.def" } } },
+			"mercury" : { "index" : 1, "rmg" : { "value" : 2000, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTmerc0.def" } } },
+			"ore" :     { "index" : 2, "rmg" : { "value" : 1400, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTore0.def"  } } },
+			"sulfur" :  { "index" : 3, "rmg" : { "value" : 2000, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTsulf0.def" } } },
+			"crystal" : { "index" : 4, "rmg" : { "value" : 2000, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTcrys0.def" } } },
+			"gems" :    { "index" : 5, "rmg" : { "value" : 2000, "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTgems0.def" } } },
+			"gold" :    { "index" : 6, "rmg" : { "value" : 750,  "rarity" : 300 }, "templates" : { "res" : { "animation" : "AVTgold0.def" } } },
 			"mithril" : { "index" : 7 } // TODO: move to WoG?
 		}
 	},
@@ -101,9 +101,9 @@
 			}
 		},
 		"types" : {
-			"evil" : { "index" : 0 },
-			"good" : { "index" : 1 },
-			"neutral" : { "index" : 2 },
+			"evil" : { "index" : 0,	"rmg" : { "mapLimit" : 64 } },
+			"good" : { "index" : 1, "rmg" : { "mapLimit" : 64 } },
+			"neutral" : { "index" : 2, "rmg" : { "mapLimit" : 64 } },
 		}
 	},
 
@@ -156,9 +156,9 @@
 		"index" :13,
 		"handler": "cartographer",
 		"types" : {
-			"water" : { "index" : 0 },
-			"land" : { "index" : 1 },
-			"subterra" : { "index" : 2 }
+			"water" : { "index" : 0, "rmg" : { "zoneLimit" : 1,  "value" : 5000, "rarity" : 20 } },
+			"land" : { "index" : 1, "rmg" : { "zoneLimit" : 1,  "value" : 10000, "rarity" : 20 } },
+			"subterra" : { "index" : 2, "rmg" : { "zoneLimit" : 1,  "value" : 7500, "rarity" : 20 } }
 		}
 	},
 
@@ -167,13 +167,13 @@
 		"index" :53,
 		"handler": "mine",
 		"types" : {
-			"sawmill" :       { "index" : 0 },
-			"alchemistLab" :  { "index" : 1 },
-			"orePit" :        { "index" : 2 },
-			"sulfurDune" :    { "index" : 3 },
-			"crystalCavern" : { "index" : 4 },
-			"gemPond" :       { "index" : 5 },
-			"goldMine" :      { "index" : 6 },
+			"sawmill" :       { "index" : 0, "rmg" : { "value" : 1500 } },
+			"alchemistLab" :  { "index" : 1, "rmg" : { "value" : 3500 } },
+			"orePit" :        { "index" : 2, "rmg" : { "value" : 1500 } },
+			"sulfurDune" :    { "index" : 3, "rmg" : { "value" : 3500 } },
+			"crystalCavern" : { "index" : 4, "rmg" : { "value" : 3500 } },
+			"gemPond" :       { "index" : 5, "rmg" : { "value" : 3500 } },
+			"goldMine" :      { "index" : 6, "rmg" : { "value" : 7000 } },
 		}
 	},
 	"abandonedMine" : {

+ 482 - 37
config/objects/rewardable.json

@@ -1,51 +1,496 @@
 {
 	/// These are objects that covered by concept of "configurable object"
 	/// Most or even all of their configuration located in this file
-	"magicSpring"					: { "index" :48, "handler": "magicSpring", "types" : { "object" : { "index" : 0} } },
+	"magicSpring" : {//magic source
+		"index" : 48,
+		"handler": "magicSpring",
+		"types" : {
+			"object" : {
+				"index" : 0//,
+				//"rmg" : {
+				//	"zoneLimit"	: 1,
+				//	"mapLimit"	: 32,
+				//	"value"		: 500,
+				//	"rarity"	: 50
+				//}
+				//banned due to problems with 2 viistable offsets
+			}
+		}
+	},
 
-	"mysticalGarden"				: { "index" :55, "handler": "oncePerWeek", "types" : { "object" : { "index" : 0} } },
-	"windmill"						: { "index" :112, "handler": "oncePerWeek", "types" : { "object" : { "index" : 0} } },
-	"waterWheel"					: { "index" :109, "handler": "oncePerWeek", "types" : { "object" : { "index" : 0} } },
+	"mysticalGarden" : {
+		"index" : 55,
+		"handler": "oncePerWeek",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 500,
+					"rarity"	: 50
+				}
+			}
+		}
+	},
+	"windmill" :{
+		"index" : 112,
+		"handler": "oncePerWeek",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 1500,
+					"rarity"	: 80
+				}
+			}
+		}
+	},
+	"waterWheel" : {
+		"index" : 109,
+		"handler": "oncePerWeek",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 750,
+					"rarity"	: 50
+				}
+			}
+		}
+	},
 	
-	"leanTo"						: { "index" :39, "handler": "onceVisitable", "types" : { "object" : { "index" : 0} } },
-	"corpse"						: { "index" :22, "handler": "onceVisitable", "types" : { "object" : { "index" : 0} } },
-	"wagon"							: { "index" :105, "handler": "onceVisitable", "types" : { "object" : { "index" : 0} } },
-	"warriorTomb"					: { "index" :108, "handler": "onceVisitable", "types" : { "object" : { "index" : 0} } },
+	"leanTo" :{
+		"index" : 39,
+		"handler": "onceVisitable",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 500,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"corpse" :{
+		"index" : 22,
+		"handler": "onceVisitable",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 500,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"wagon" :{
+		"index" : 105,
+		"handler": "onceVisitable",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 500,
+					"rarity"	: 50
+				}
+			}
+		}
+	},
+	"warriorTomb" : {
+		"index" : 108,
+		"handler": "onceVisitable",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 6000,
+					"rarity"	: 20
+				}
+			}
+		}
+	},
 
-	"campfire"						: { "index" :12, "handler": "pickable", "types" : { "object" : { "index" : 0} } },
-	"flotsam"						: { "index" :29, "handler": "pickable", "types" : { "object" : { "index" : 0} } },
-	"seaChest"						: { "index" :82, "handler": "pickable", "types" : { "object" : { "index" : 0} } },
-	"shipwreckSurvivor"				: { "index" :86, "handler": "pickable", "types" : { "object" : { "index" : 0} } },
-	"treasureChest"					: { "index" :101, "handler": "pickable", "types" : { "object" : { "index" : 0} } },
+	"campfire" :{
+		"index" : 12,
+		"handler": "pickable",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"value"		: 2000,
+					"rarity"	: 500
+				}
+			}
+		}
+	},
+	"flotsam" :{
+		"index" : 29,
+		"handler": "pickable",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"value"		: 2000,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"seaChest" :{
+		"index" : 82,
+		"handler": "pickable",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"value"		: 1500,
+					"rarity"	: 500
+				}
+			}
+		}
+	},
+	"shipwreckSurvivor" : {
+		"index" : 86,
+		"handler": "pickable",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"value"		: 1500,
+					"rarity"	: 50
+				}
+			}
+		}
+	},
+	"treasureChest" : {
+		"index" : 101,
+		"handler": "pickable",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"value"		: 1500,
+					"rarity"	: 1000
+				}
+			}
+		}
+	},
 
-	"arena"							: { "index" :4,  "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
-	"marlettoTower"					: { "index" :23, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
-	"gardenOfRevelation"			: { "index" :32, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
-	"libraryOfEnlightenment"		: { "index" :41, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
-	"mercenaryCamp"					: { "index" :51, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
-	"starAxis"						: { "index" :61, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
-	"treeOfKnowledge"				: { "index" :102, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
-	"schoolOfMagic"					: { "index" :47, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
-	"schoolOfWar"					: { "index" :107, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } },
+	"arena" : {
+		"index" : 4,
+		"handler": "oncePerHero",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 3000,
+					"rarity"	: 50
+				}
+			}
+		}
+	},
+	"marlettoTower" : {
+		"index" : 23,
+		"handler": "oncePerHero",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 1500,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"gardenOfRevelation" : {
+		"index" : 32,
+		"handler": "oncePerHero",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 1500,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"libraryOfEnlightenment" : {
+		"index" : 41,
+		"handler": "oncePerHero",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 12000,
+					"rarity"	: 20
+				}
+			}
+		}
+	},
+	"mercenaryCamp" : {
+		"index" : 51,
+		"handler": "oncePerHero",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 1500,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"starAxis" :{
+		"index" : 61,
+		"handler": "oncePerHero",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 1500,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"treeOfKnowledge" : {
+		"index" : 102,
+		"handler": "oncePerHero",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 2500,
+					"rarity"	: 50
+				}
+			}
+		}
+	},
+	"schoolOfMagic" : {
+		"index" : 47,
+		"handler": "oncePerHero",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 1000,
+					"rarity"	: 50
+				}
+			}
+		}
+	},
+	"schoolOfWar" : {
+		"index" : 107,
+		"handler": "oncePerHero",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 1000,
+					"rarity"	: 50
+				}
+			}
+		}
+	},
 	"learningStone" : {
-		"index" :100,
+		"index" : 100,
 		"handler": "oncePerHero",
 		"types" : {
-			"object" : { "index" : 0},
-			"objectWoG" : { "index" : 1} // WoG object? Present on VCMI_Tests 2011
+			"object" : { 
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 1500,
+					"rarity"	: 200
+				} 
+			},
+			"objectWoG" : { "index" : 1 } // WoG object? Present on VCMI_Tests 2011
 		}
 	},
 
-	"buoy"							: { "index" :11, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
-	"swanPond"						: { "index" :14, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
-	"faerieRing"					: { "index" :28, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
-	"fountainOfFortune"				: { "index" :30, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
-	"fountainOfYouth"				: { "index" :31, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
-	"idolOfFortune"					: { "index" :38, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
-	"mermaids"						: { "index" :52, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
-	"oasis"							: { "index" :56, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
-	"stables"						: { "index" :94, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
-	"temple"						: { "index" :96, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
-	"rallyFlag"						: { "index" :64, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } },
-	"wateringHole"					: { "index" :110, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }
+	"buoy" : {
+		"index" : 11,
+		"handler": "bonusingObject",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"value"		: 100,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"swanPond" : {
+		"index" : 14,
+		"handler": "bonusingObject",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 100,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"faerieRing" : {
+		"index" : 28,
+		"handler": "bonusingObject",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 100,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"fountainOfFortune" : {
+		"index" : 30,
+		"handler": "bonusingObject",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 100,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"fountainOfYouth" : {
+		"index" : 31,
+		"handler": "bonusingObject",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 100,
+					"rarity"	: 50
+				}
+			}
+		}
+	},
+	"idolOfFortune" : {
+		"index" : 38,
+		"handler": "bonusingObject",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 100,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"mermaids" : {
+		"index" : 52,
+		"handler": "bonusingObject",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"mapLimit"	: 32,
+					"value"		: 100,
+					"rarity"	: 20
+				}
+			}
+		}
+	},
+	"oasis" : {
+		"index" : 56,
+		"handler": "bonusingObject",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 100,
+					"rarity"	: 50
+				}
+			}
+		}
+	},
+	"stables" : {
+		"index" : 94,
+		"handler": "bonusingObject",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 200,
+					"rarity"	: 40
+				}
+			}
+		}
+	},
+	"temple" : {
+		"index" : 96,
+		"handler": "bonusingObject",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 100,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"rallyFlag" : {
+		"index" : 64,
+		"handler": "bonusingObject",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 100,
+					"rarity"	: 100
+				}
+			}
+		}
+	},
+	"wateringHole" : {//waters
+		"index" : 110,
+		"handler": "bonusingObject",
+		"types" : {
+			"object" : {
+				"index" : 0,
+				"rmg" : {
+					"zoneLimit"	: 1,
+					"value"		: 500,
+					"rarity"	: 50
+				}
+			} 
+		}
+	}
 }

+ 17 - 17
config/rmg.json

@@ -2,13 +2,13 @@
 {
 	"Analogy" : 
 	{
-		"minSize" : "m", "maxSize" : "m",
+		"minSize" : "m", "maxSize" : "m+u",
 		"players" : "4",
 		"zones" :
 		{
 			"1" :
 			{
-				"type" : "playerStart", "size" : 1, "owner" : 1,
+				"type" : "playerStart", "size" : 2, "owner" : 1,
 				"playerTowns" : { "castles" : 1 }, "neutralTowns" : { "towns" : 1 }, "townsAreSameType" : true,
 				"monsters" : "normal",
 				"mines" : {"wood" : 1, "ore" : 1, "gems" : 1, "crystal" : 1, "sulfur" : 1, "mercury" : 1},
@@ -19,7 +19,7 @@
 			},
 			"2" :
 			{
-				"type" : "playerStart", "size" : 1, "owner" : 2,
+				"type" : "playerStart", "size" : 2, "owner" : 2,
 				"playerTowns" : { "castles" : 1 }, "neutralTowns" : { "towns" : 1 }, "townsAreSameType" : true,
 				"monsters" : "normal",
 				"minesLikeZone" : 1,
@@ -27,7 +27,7 @@
 			},
 			"3" :
 			{
-				"type" : "playerStart", "size" : 1, "owner" : 3,
+				"type" : "playerStart", "size" : 2, "owner" : 3,
 				"playerTowns" : { "castles" : 1 }, "neutralTowns" : { "towns" : 1 }, "townsAreSameType" : true,
 				"monsters" : "normal",
 				"minesLikeZone" : 1,
@@ -35,7 +35,7 @@
 			},
 			"4" :
 			{
-				"type" : "playerStart", "size" : 1, "owner" : 4,
+				"type" : "playerStart", "size" : 2, "owner" : 4,
 				"playerTowns" : { "castles" : 1 }, "neutralTowns" : { "towns" : 1 }, "townsAreSameType" : true,
 				"monsters" : "normal",
 				"minesLikeZone" : 1,
@@ -43,7 +43,7 @@
 			},
 			"5" :
 			{
-				"type" : "treasure", "size" : 2, "terrainTypes" : [ "sand" ], "matchTerrainToTown" : false,
+				"type" : "treasure", "size" : 3, "terrainTypes" : [ "sand" ], "matchTerrainToTown" : false,
 				"neutralTowns" : { "castles" : 1 },
 				"monsters" : "strong",
 				"mines" : {"gold" : 2},
@@ -63,13 +63,13 @@
 	},
 	"Upgrade" :
 	{
-		"minSize" : "s", "maxSize" : "m",
+		"minSize" : "s+u", "maxSize" : "m",
 		"players" : "2",
 		"zones" :
 		{
 			"1" :
 			{
-				"type" : "playerStart", "size" : 1, "owner" : 1,
+				"type" : "playerStart", "size" : 3, "owner" : 1,
 				"playerTowns" : { "castles" : 1 },
 				"monsters" : "normal",
 				"mines" : {"wood" : 1, "ore" : 1},
@@ -80,7 +80,7 @@
 			},
 			"2" :
 			{
-				"type" : "playerStart", "size" : 1, "owner" : 2,
+				"type" : "playerStart", "size" : 3, "owner" : 2,
 				"playerTowns" : { "castles" : 1 },
 				"monsters" : "normal",
 				"minesLikeZone" : 1,
@@ -88,7 +88,7 @@
 			},
 			"3" :
 			{
-				"type" : "treasure", "size" : 2, "neutralTowns" : { "towns" : 1 }, "townTypeLikeZone" : 1,
+				"type" : "treasure", "size" : 4, "neutralTowns" : { "towns" : 1 }, "townTypeLikeZone" : 1,
 				"monsters" : "weak",
 				"mines" : {"gems" : 1, "crystal" : 1, "sulfur" : 1, "mercury" : 1, "gold" : 1},
 				"treasure" : [
@@ -98,14 +98,14 @@
 			},
 			"4" :
 			{
-				"type" : "treasure", "size" : 2, "neutralTowns" : { "towns" : 1 }, "townTypeLikeZone" : 2,
+				"type" : "treasure", "size" : 4, "neutralTowns" : { "towns" : 1 }, "townTypeLikeZone" : 2,
 				"monsters" : "weak",
 				"minesLikeZone" : 3,
 				"treasureLikeZone" : 3
 			},
 			"5" :
 			{
-				"type" : "treasure", "size" : 3, "neutralTowns" : { "castles" : 1 }, "terrainTypes" : [ "sand" ],
+				"type" : "treasure", "size" : 5, "neutralTowns" : { "castles" : 1 }, "terrainTypes" : [ "sand" ],
 				"monsters" : "strong",
 				"mines" : {"gold" : 2},
 				"treasure" : [
@@ -126,13 +126,13 @@
 	},
 	"Golden Ring" :
 	{
-		"minSize" : "m", "maxSize" : "l",
+		"minSize" : "m+u", "maxSize" : "l",
 		"players" : "3",
 		"zones" :
 		{
 			"1" :
 			{
-				"type" : "playerStart", "size" : 3, "owner" : 1,
+				"type" : "playerStart", "size" : 2, "owner" : 1,
 				"playerTowns" : { "castles" : 1 },
 				"monsters" : "normal",
 				"mines" : {"wood" : 1, "ore" : 1},
@@ -143,7 +143,7 @@
 			},
 			"2" :
 			{
-				"type" : "playerStart", "size" : 3, "owner" : 2,
+				"type" : "playerStart", "size" : 2, "owner" : 2,
 				"playerTowns" : { "castles" : 1 },
 				"monsters" : "normal",
 				"minesLikeZone" : 1,
@@ -151,7 +151,7 @@
 			},
 			"3" :
 			{
-				"type" : "playerStart", "size" : 3, "owner" : 3,
+				"type" : "playerStart", "size" : 2, "owner" : 3,
 				"playerTowns" : { "castles" : 1 },
 				"monsters" : "normal",
 				"minesLikeZone" : 1,
@@ -243,7 +243,7 @@
 	},
 	"Jebus Cross":
 	{
-		"minSize" : "l", "maxSize" : "xl",
+		"minSize" : "l+u", "maxSize" : "xl+u",
 		"players" : "4",
 		"zones":
 		{

+ 1 - 1
lib/CRandomGenerator.h

@@ -117,7 +117,7 @@ namespace RandomGeneratorUtil
 		int n = (container.end() - container.begin());
 		for (int i = n-1; i>0; --i)
 		{
-			std::swap (container.begin()[i],container.begin()[rand.nextInt(i+1)]);
+			std::swap (container.begin()[i],container.begin()[rand.nextInt(i)]);
 		}
 	}
 }

+ 1 - 7
lib/mapObjects/CObjectHandler.cpp

@@ -241,13 +241,7 @@ int CGObjectInstance::getSightRadious() const
 
 int3 CGObjectInstance::getVisitableOffset() const
 {
-	for(int y = 0; y < appearance.getHeight(); y++)
-		for (int x = 0; x < appearance.getWidth(); x++)
-			if (appearance.isVisitableAt(x, y))
-				return int3(x,y,0);
-
-    //logGlobal->warnStream() << "Warning: getVisitableOffset called on non-visitable obj!";
-	return int3(0,0,0);
+	return appearance.getVisitableOffset();
 }
 
 void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) const

+ 11 - 0
lib/mapObjects/CommonConstructors.cpp

@@ -218,6 +218,17 @@ bool CDwellingInstanceConstructor::producesCreature(const CCreature * crea) cons
 	return false;
 }
 
+std::vector<const CCreature *> CDwellingInstanceConstructor::getProducedCreatures() const
+{
+	std::vector<const CCreature *> creatures; //no idea why it's 2D, to be honest
+	for (auto & entry : availableCreatures)
+	{
+		for (const CCreature * cre : entry)
+			creatures.push_back(cre);
+	}
+	return creatures;
+}
+
 CBankInstanceConstructor::CBankInstanceConstructor()
 {
 }

+ 2 - 0
lib/mapObjects/CommonConstructors.h

@@ -13,6 +13,7 @@
  *
  */
 
+class CGObjectInstance;
 class CGTownInstance;
 class CGHeroInstance;
 class CGDwelling;
@@ -123,6 +124,7 @@ public:
 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const;
 
 	bool producesCreature(const CCreature * crea) const;
+	std::vector<const CCreature *> getProducedCreatures() const;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 11 - 0
lib/mapObjects/MiscObjects.cpp

@@ -871,6 +871,12 @@ void CGArtifact::initObj()
 	blockVisit = true;
 	if(ID == Obj::ARTIFACT)
 	{
+		if (!storedArtifact)
+		{
+			auto a = new CArtifactInstance();
+			cb->gameState()->map->addNewArtifactInstance(a);
+			storedArtifact = a;
+		}
 		if(!storedArtifact->artType)
 			storedArtifact->setType(VLC->arth->artifacts[subID]);
 	}
@@ -963,6 +969,11 @@ void CGArtifact::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer)
 
 void CGWitchHut::initObj()
 {
+	if (allowedAbilities.empty()) //this can happen for RMG. regular maps load abilities from map file
+	{
+		for (int i = 0; i < GameConstants::SKILL_QUANTITY; i++)
+			allowedAbilities.push_back(i);
+	}
 	ability = *RandomGeneratorUtil::nextItem(allowedAbilities, cb->gameState()->getRandomGenerator());
 }
 

+ 2 - 0
lib/mapObjects/MiscObjects.h

@@ -158,6 +158,8 @@ public:
 	CArtifactInstance *storedArtifact;
 	std::string message;
 
+	CGArtifact() : CArmedInstance() {storedArtifact = nullptr;};
+
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
 	void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;

+ 21 - 3
lib/mapObjects/ObjectTemplate.cpp

@@ -23,7 +23,7 @@
  *
  */
 
-static bool isVisitableFromTop(int identifier, int type)
+static bool isOnVisitableFromTopList(int identifier, int type)
 {
 	if(type == 2 || type == 3 || type == 4 || type == 5) //creature, hero, artifact, resource
 		return true;
@@ -106,7 +106,7 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser)
 	int type  = boost::lexical_cast<int>(strings[7]);
 	printPriority = boost::lexical_cast<int>(strings[8]) * 100; // to have some space in future
 
-	if (isVisitableFromTop(id, type))
+	if (isOnVisitableFromTopList(id, type))
 		visitDir = 0xff;
 	else
 		visitDir = (8|16|32|64|128);
@@ -168,7 +168,7 @@ void ObjectTemplate::readMap(CBinaryReader & reader)
 	int type = reader.readUInt8();
 	printPriority = reader.readUInt8() * 100; // to have some space in future
 
-	if (isVisitableFromTop(id, type))
+	if (isOnVisitableFromTopList(id, type))
 		visitDir = 0xff;
 	else
 		visitDir = (8|16|32|64|128);
@@ -354,6 +354,24 @@ bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const
 	return dirMap[dy][dx] != 0;
 }
 
+int3 ObjectTemplate::getVisitableOffset() const
+{
+	for(int y = 0; y < getHeight(); y++)
+		for (int x = 0; x < getWidth(); x++)
+			if (isVisitableAt(x, y))
+				return int3(x,y,0);
+
+    //logGlobal->warnStream() << "Warning: getVisitableOffset called on non-visitable obj!";
+	return int3(0,0,0);
+}
+
+bool ObjectTemplate::isVisitableFromTop() const
+{
+	return visitDir & 2;
+	//for some reason the line below is never called :?
+	//return isVisitableFrom (0, 1);
+}
+
 bool ObjectTemplate::canBePlacedAt(ETerrainType terrain) const
 {
 	return allowedTerrains.count(terrain) != 0;

+ 4 - 0
lib/mapObjects/ObjectTemplate.h

@@ -62,6 +62,8 @@ public:
 
 	// Checks if object is visitable from certain direction. X and Y must be between -1..+1
 	bool isVisitableFrom(si8 X, si8 Y) const;
+	int3 getVisitableOffset() const;
+	bool isVisitableFromTop() const;
 
 	// Checks if object can be placed on specific terrain
 	bool canBePlacedAt(ETerrainType terrain) const;
@@ -73,6 +75,8 @@ public:
 	void readMap(CBinaryReader & reader);
 	void readJson(const JsonNode & node);
 
+	bool operator==(const ObjectTemplate& ot) const { return (id == ot.id && subid == ot.subid); }
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & usedTiles & allowedTerrains & animationFile & stringID;

+ 3 - 6
lib/rmg/CMapGenOptions.cpp

@@ -175,14 +175,11 @@ const std::map<std::string, CRmgTemplate *> & CMapGenOptions::getAvailableTempla
 	return VLC->tplh->getTemplates();
 }
 
-void CMapGenOptions::finalize()
-{
-	CRandomGenerator rand;
-	finalize(rand);
-}
-
 void CMapGenOptions::finalize(CRandomGenerator & rand)
 {
+	logGlobal->infoStream() << boost::format ("RMG settings: players %d, teams %d, computer players %d, computer teams %d, water %d, monsters %d")
+											% playerCount % teamCount % compOnlyPlayerCount % compOnlyTeamCount % waterContent % monsterStrength;
+
 	if(!mapTemplate)
 	{
 		mapTemplate = getPossibleTemplate(rand);

+ 0 - 1
lib/rmg/CMapGenOptions.h

@@ -145,7 +145,6 @@ public:
 	/// Finalizes the options. All random sizes for various properties will be overwritten by numbers from
 	/// a random number generator by keeping the options in a valid state. Check options should return true, otherwise
 	/// this function fails.
-	void finalize();
 	void finalize(CRandomGenerator & rand);
 
 	/// Returns false if there is no template available which fits to the currently selected options.

+ 119 - 23
lib/rmg/CMapGenerator.cpp

@@ -11,6 +11,7 @@
 #include "CRmgTemplate.h"
 #include "CRmgTemplateZone.h"
 #include "CZonePlacer.h"
+#include "../mapObjects/CObjectClassesHandler.h"
 
 void CMapGenerator::foreach_neighbour(const int3 &pos, std::function<void(int3& pos)> foo)
 {
@@ -24,7 +25,7 @@ void CMapGenerator::foreach_neighbour(const int3 &pos, std::function<void(int3&
 
 
 CMapGenerator::CMapGenerator(shared_ptr<CMapGenOptions> mapGenOptions, int RandomSeed /*= std::time(nullptr)*/) :
-	mapGenOptions(mapGenOptions), randomSeed(RandomSeed), monolithIndex(0)
+	mapGenOptions(mapGenOptions), randomSeed(RandomSeed), monolithIndex(0), zonesTotal(0)
 {
 	rand.setSeed(randomSeed);
 }
@@ -215,9 +216,9 @@ void CMapGenerator::fillZones()
 	logGlobal->infoStream() << "Started filling zones";
 
 	createConnections();
+	//make sure all connections are passable before creating borders
 	for (auto it : zones)
 	{
-		//make sure all connections are passable before creating borders
 		it.second->createBorder(this);
 		it.second->fill(this);
 	}	
@@ -239,24 +240,95 @@ void CMapGenerator::createConnections()
 		int3 guardPos(-1,-1,-1);
 
 		auto otherZoneTiles = zoneB->getTileInfo();
-		//auto otherZoneCenter = zoneB->getPos();
 
-		for (auto tile : tiles)
+		int3 posA = zoneA->getPos();
+		int3 posB = zoneB->getPos();
+
+		if (posA.z == posB.z)
 		{
-			foreach_neighbour (tile, [&guardPos, tile, &otherZoneTiles](int3 &pos)
+			for (auto tile : tiles)
 			{
-				if (vstd::contains(otherZoneTiles, pos))
-					guardPos = tile;
-			});
-			if (guardPos.valid())
+				if (isBlocked(tile)) //tiles may be occupied by subterranean gates already placed
+					continue;
+				foreach_neighbour (tile, [&guardPos, tile, &otherZoneTiles, this](int3 &pos)
+				{
+					//if (vstd::contains(otherZoneTiles, pos) && !this->isBlocked(pos))
+					if (vstd::contains(otherZoneTiles, pos))
+						guardPos = tile;
+				});
+				if (guardPos.valid())
+				{
+					setOccupied (guardPos, ETileType::FREE); //just in case monster is too weak to spawn
+					zoneA->addMonster (this, guardPos, connection.getGuardStrength(), false, true);
+					//zones can make paths only in their own area
+					zoneA->crunchPath (this, guardPos, posA, zoneA->getId(), zoneA->getFreePaths()); //make connection towards our zone center
+					zoneB->crunchPath (this, guardPos, posB, zoneB->getId(), zoneB->getFreePaths()); //make connection towards other zone center
+					break; //we're done with this connection
+				}
+			}
+		}
+		else //create subterranean gates between two zones
+		{	
+			//find point on the path between zones
+			float3 offset (posB.x - posA.x, posB.y - posA.y, 0);
+
+			float distance = posB.dist2d(posA);
+			vstd::amax (distance, 0.5f);
+			offset /= distance; //get unit vector
+			float3 vec (0, 0, 0);
+			//use reduced size of underground zone - make sure gate does not stand on rock
+			int3 tile = posA;
+			int3 otherTile = tile;
+
+			bool stop = false;
+			while (!stop)
 			{
-				setOccupied (guardPos, ETileType::FREE); //just in case monster is too weak to spawn
-				zoneA->addMonster (this, guardPos, connection.getGuardStrength()); //TODO: set value according to template
-				//zones can make paths only in their own area
-				zoneA->crunchPath (this, guardPos, zoneA->getPos(), zoneA->getId(), zoneA->getFreePaths()); //make connection towards our zone center
-				zoneB->crunchPath (this, guardPos, zoneB->getPos(), zoneB->getId(), zoneB->getFreePaths()); //make connection towards other zone center
-				break; //we're done with this connection
+				vec += offset; //this vector may extend beyond line between zone centers, in case they are directly over each other
+				tile = posA + int3(vec.x, vec.y, 0);
+				float distanceFromA = posA.dist2d(tile);
+				float distanceFromB = posB.dist2d(tile);
+
+				if (distanceFromA + distanceFromB > std::max<int>(zoneA->getSize() + zoneB->getSize(), distance))
+					break; //we are too far away to ever connect
+
+				//if zone is underground, gate must fit within its (reduced) radius
+				if (distanceFromA > 5 && (!posA.z || distanceFromA < zoneA->getSize() - 3) &&
+					distanceFromB > 5 && (!posB.z || distanceFromB < zoneB->getSize() - 3))
+				{
+					otherTile = tile;
+					otherTile.z = posB.z;
+
+					if (vstd::contains(tiles, tile) && vstd::contains(otherZoneTiles, otherTile))
+					{
+						bool withinZone = true;
+
+						foreach_neighbour (tile, [&withinZone, &tiles](int3 &pos)
+						{
+							if (!vstd::contains(tiles, pos))
+								withinZone = false;
+						});
+						foreach_neighbour (otherTile, [&withinZone, &otherZoneTiles](int3 &pos)
+						{
+							if (!vstd::contains(otherZoneTiles, pos))
+								withinZone = false;
+						});
+
+						if (withinZone)
+						{
+							auto gate1 = new CGTeleport;
+							gate1->ID = Obj::SUBTERRANEAN_GATE;
+							gate1->subID = 0;
+							zoneA->placeAndGuardObject(this, gate1, tile, connection.getGuardStrength());
+							auto gate2 = new CGTeleport(*gate1);
+							zoneB->placeAndGuardObject(this, gate2, otherTile, connection.getGuardStrength());
+
+							stop = true; //we are done, go to next connection
+						}
+					}
+				}
 			}
+			if (stop)
+				continue;
 		}
 		if (!guardPos.valid())
 		{
@@ -299,36 +371,43 @@ bool CMapGenerator::isBlocked(const int3 &tile) const
 bool CMapGenerator::shouldBeBlocked(const int3 &tile) const
 {
 	if (!map->isInTheMap(tile))
-		throw  rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
+		throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
 
 	return tiles[tile.x][tile.y][tile.z].shouldBeBlocked();
 }
 bool CMapGenerator::isPossible(const int3 &tile) const
 {
 	if (!map->isInTheMap(tile))
-		throw  rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
+		throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
 
 	return tiles[tile.x][tile.y][tile.z].isPossible();
 }
 bool CMapGenerator::isFree(const int3 &tile) const
 {
 	if (!map->isInTheMap(tile))
-		throw  rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
+		throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
 
 	return tiles[tile.x][tile.y][tile.z].isFree();
 }
-void CMapGenerator::setOccupied(const int3 &tile, ETileType::ETileType state)
+bool CMapGenerator::isUsed(const int3 &tile) const
 {
 	if (!map->isInTheMap(tile))
 		throw  rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
 
+	return tiles[tile.x][tile.y][tile.z].isUsed();
+}
+void CMapGenerator::setOccupied(const int3 &tile, ETileType::ETileType state)
+{
+	if (!map->isInTheMap(tile))
+		throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
+
 	tiles[tile.x][tile.y][tile.z].setOccupied(state);
 }
 
 CTileInfo CMapGenerator::getTile(const int3&  tile) const
 {
 	if (!map->isInTheMap(tile))
-		throw  rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
+		throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
 
 	return tiles[tile.x][tile.y][tile.z];
 }
@@ -336,7 +415,7 @@ CTileInfo CMapGenerator::getTile(const int3&  tile) const
 void CMapGenerator::setNearestObjectDistance(int3 &tile, int value)
 {
 	if (!map->isInTheMap(tile))
-		throw  rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
+		throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
 
 	tiles[tile.x][tile.y][tile.z].setNearestObjectDistance(value);
 }
@@ -344,12 +423,29 @@ void CMapGenerator::setNearestObjectDistance(int3 &tile, int value)
 int CMapGenerator::getNearestObjectDistance(const int3 &tile) const
 {
 	if (!map->isInTheMap(tile))
-		throw  rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
+		throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));
 
 	return tiles[tile.x][tile.y][tile.z].getNearestObjectDistance();
 }
 
 int CMapGenerator::getNextMonlithIndex()
 {
-	return monolithIndex++;
+	if (monolithIndex >= VLC->objtypeh->knownSubObjects(Obj::MONOLITH_TWO_WAY).size())
+		throw rmgException(boost::to_string(boost::format("There is no Monolith Two Way with index %d available!") % monolithIndex));
+	else
+		return monolithIndex++;
+}
+
+void CMapGenerator::registerZone (TFaction faction)
+{
+	zonesPerFaction[faction]++;
+	zonesTotal++;
+}
+ui32 CMapGenerator::getZoneCount(TFaction faction)
+{
+	return zonesPerFaction[faction];
+}
+ui32 CMapGenerator::getTotalZoneCount() const
+{
+	return zonesTotal;
 }

+ 6 - 0
lib/rmg/CMapGenerator.h

@@ -70,6 +70,7 @@ public:
 	bool shouldBeBlocked(const int3 &tile) const;
 	bool isPossible(const int3 &tile) const;
 	bool isFree(const int3 &tile) const;
+	bool isUsed(const int3 &tile) const;
 	void setOccupied(const int3 &tile, ETileType::ETileType state);
 	CTileInfo getTile(const int3 & tile) const;
 
@@ -77,9 +78,14 @@ public:
 	void setNearestObjectDistance(int3 &tile, int value);
 
 	int getNextMonlithIndex();
+	void registerZone (TFaction faction);
+	ui32 getZoneCount(TFaction faction);
+	ui32 getTotalZoneCount() const;
 
 private:
 	std::map<TRmgTemplateZoneId, CRmgTemplateZone*> zones;
+	std::map<TFaction, ui32> zonesPerFaction;
+	ui32 zonesTotal; //zones that have their main town only
 
 	CTileInfo*** tiles;
 

+ 628 - 211
lib/rmg/CRmgTemplateZone.cpp

@@ -19,12 +19,14 @@
 #include "../CCreatureHandler.h"
 #include "../CSpellHandler.h" //for choosing random spells
 
-#include "../mapObjects/CObjectClassesHandler.h"
+#include "../mapObjects/CommonConstructors.h"
+#include "../mapObjects/MapObjects.h" //needed to resolve templates for CommonConstructors.h
 #include "../mapObjects/CGPandoraBox.h"
 #include "../mapObjects/CRewardableObject.h"
 
 class CMap;
 class CMapEditManager;
+//class CGObjectInstance;
 
 CRmgTemplateZone::CTownInfo::CTownInfo() : townCount(0), castleCount(0), townDensity(0), castleDensity(0)
 {
@@ -109,6 +111,10 @@ bool CTileInfo::isFree() const
 {
 	return occupied == ETileType::FREE;
 }
+bool CTileInfo::isUsed() const
+{
+	return occupied == ETileType::USED;
+}
 void CTileInfo::setOccupied(ETileType::ETileType value)
 {
 	occupied = value;
@@ -354,6 +360,24 @@ std::set<int3> CRmgTemplateZone::getTileInfo () const
 	return tileinfo;
 }
 
+void CRmgTemplateZone::discardDistantTiles (CMapGenerator* gen, float distance)
+{
+	//TODO: mark tiles beyond zone as unavailable, but allow to connect with adjacent zones
+
+	//for (auto tile : tileinfo)
+	//{
+	//	if (tile.dist2d(this->pos) > distance)
+	//	{
+	//		gen->setOccupied(tile, ETileType::USED);
+	//		//gen->setOccupied(tile, ETileType::BLOCKED); //fixme: crash at rendering?
+	//	}
+	//}
+	vstd::erase_if (tileinfo, [distance, this](const int3 &tile) -> bool
+	{
+		return tile.dist2d(this->pos) > distance;
+	});
+}
+
 void CRmgTemplateZone::createBorder(CMapGenerator* gen)
 {
 	for (auto tile : tileinfo)
@@ -374,12 +398,13 @@ void CRmgTemplateZone::createBorder(CMapGenerator* gen)
 
 void CRmgTemplateZone::fractalize(CMapGenerator* gen)
 {
-	std::vector<int3> clearedTiles;
+	std::vector<int3> clearedTiles (freePaths.begin(), freePaths.end());
 	std::set<int3> possibleTiles;
 	std::set<int3> tilesToClear; //will be set clear
 	std::set<int3> tilesToIgnore; //will be erased in this iteration
 
-	const float minDistance = std::sqrt(totalDensity);
+	//the more treasure density, the greater distance between paths. Scaling is experimental.
+	const float minDistance = std::sqrt(totalDensity * 3);
 	for (auto tile : tileinfo)
 	{
 		if (gen->isFree(tile))
@@ -387,10 +412,7 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen)
 		else if (gen->isPossible(tile))
 			possibleTiles.insert(tile);
 	}
-	if (clearedTiles.empty()) //this should come from zone connections
-	{
-		clearedTiles.push_back(pos); //zone center should be always clear
-	}
+	assert (clearedTiles.size()); //this should come from zone connections
 
 	while (possibleTiles.size())
 	{
@@ -440,6 +462,34 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen)
 		tilesToClear.clear(); //empty this container
 		tilesToIgnore.clear();
 	}
+
+	for (auto tile : clearedTiles)
+	{
+		freePaths.insert(tile);
+	}
+
+	
+
+	if (0) //enable to debug
+	{
+		std::ofstream out(boost::to_string(boost::format("zone %d") % id));
+		int levels = gen->map->twoLevel ? 2 : 1;
+		int width =  gen->map->width;
+		int height = gen->map->height;
+		for (int k = 0; k < levels; k++)
+		{
+			for(int j=0; j<height; j++)
+			{
+				for (int i=0; i<width; i++)
+				{
+					out << (int)vstd::contains(freePaths, int3(i,j,k));
+				}
+				out << std::endl;
+			}
+			out << std::endl;
+		}
+	}
+
 	logGlobal->infoStream() << boost::format ("Zone %d subdivided fractally") %id;
 }
 
@@ -514,13 +564,13 @@ void CRmgTemplateZone::addRequiredObject(CGObjectInstance * obj, si32 strength)
 	requiredObjects.push_back(std::make_pair(obj, strength));
 }
 
-bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength)
+bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength, bool clearSurroundingTiles, bool zoneGuard)
 {
 	//precalculate actual (randomized) monster strength based on this post
 	//http://forum.vcmi.eu/viewtopic.php?p=12426#12426
 
 	int mapMonsterStrength = gen->mapGenOptions->getMonsterStrength();
-	int monsterStrength = zoneMonsterStrength + mapMonsterStrength - 1; //array index from 0 to 4
+	int monsterStrength = (zoneGuard ? 0 : zoneMonsterStrength) + mapMonsterStrength - 1; //array index from 0 to 4
 	static const int value1[] = {2500, 1500, 1000, 500, 0};
 	static const int value2[] = {7500, 7500, 7500, 5000, 5000};
 	static const float multiplier1[] = {0.5, 0.75, 1.0, 1.5, 1.5};
@@ -566,16 +616,32 @@ bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength)
 	//will be set during initialization
 	guard->putStack(SlotID(0), hlp);
 
+	//logGlobal->traceStream() << boost::format ("Adding stack of %d %s. Map monster strenght %d, zone monster strength %d, base monster value %d")
+	//	% amount % VLC->creh->creatures[creId]->namePl % mapMonsterStrength % zoneMonsterStrength % strength;
+
 	placeObject(gen, guard, pos);
+
+	if (clearSurroundingTiles)
+	{
+		//do not spawn anything near monster
+		gen->foreach_neighbour (pos, [gen](int3 pos)
+		{
+			if (gen->isPossible(pos))
+				gen->setOccupied(pos, ETileType::FREE);
+		});
+	}
+
 	return true;
 }
 
 bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
 {
+	CTreasurePileInfo info;
+
 	std::map<int3, CGObjectInstance *> treasures;
 	std::set<int3> boundary;
 	int3 guardPos (-1,-1,-1);
-	int3 nextTreasurePos = pos;
+	info.nextTreasurePos = pos;
 
 	//default values
 	int maxValue = 5000;
@@ -601,9 +667,8 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
 	CGObjectInstance * object = nullptr;
 	while (currentValue < minValue)
 	{
-		//TODO: this works only for 1-tile objects
-		//make sure our shape is consistent
-		treasures[nextTreasurePos] = nullptr;
+		treasures[info.nextTreasurePos] = nullptr;
+
 		for (auto treasurePos : treasures)
 		{
 			gen->foreach_neighbour (treasurePos.first, [gen, &boundary](int3 pos)
@@ -616,6 +681,7 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
 			//leaving only boundary around objects
 			vstd::erase_if_present (boundary, treasurePos.first);
 		}
+
 		for (auto tile : boundary)
 		{
 			//we can't extend boundary anymore
@@ -625,22 +691,46 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
 
 		int remaining = maxValue - currentValue;
 
-		auto oi = getRandomObject(gen, remaining);
+		ObjectInfo oi = getRandomObject(gen, info, remaining);
 		object = oi.generateObject();
 		if (!object)
+		{
+			vstd::erase_if_present(treasures, info.nextTreasurePos);
 			break;
+		}
+		else
+		{
+			//remove from possible objects
+			auto oiptr = std::find(possibleObjects.begin(), possibleObjects.end(), oi);
+			assert (oiptr != possibleObjects.end());
+			oiptr->maxPerZone--;
+			//TODO
+
+			//update treasure pile area
+			int3 visitablePos = info.nextTreasurePos;
+
+			//TODO: actually we need to check is object is either !blockVisit or removable after visit - this means object below can be accessed
+			if (oi.templ.isVisitableFromTop())
+				info.visitableFromTopPositions.insert(visitablePos); //can be accessed from any direction
+			else
+				info.visitableFromBottomPositions.insert(visitablePos); //can be accessed only from bottom or side
+
+			for (auto blockedOffset : oi.templ.getBlockedOffsets())
+			{
+				int3 blockPos = info.nextTreasurePos + blockedOffset + oi.templ.getVisitableOffset(); //object will be moved to align vistable pos to treasure pos
+				info.occupiedPositions.insert(blockPos);
+				info.blockedPositions.insert(blockPos);
+			}
+			info.occupiedPositions.insert(visitablePos);
+		}
 
 		currentValue += oi.value;
 		
-		treasures[nextTreasurePos] = object;
+		treasures[info.nextTreasurePos] = object;
 
 		//now find place for next object
 		int3 placeFound(-1,-1,-1);
 
-		//FIXME: find out why teh following code causes crashes
-		//std::vector<int3> boundaryVec(boundary.begin(), boundary.end());
-		//RandomGeneratorUtil::randomShuffle(boundaryVec, gen->rand);
-		//for (auto tile : boundaryVec)
 		for (auto tile : boundary)
 		{
 			if (gen->isPossible(tile)) //we can place new treasure only on possible tile
@@ -659,25 +749,50 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
 			}
 		}
 		if (placeFound.valid())
-			nextTreasurePos = placeFound;
+			info.nextTreasurePos = placeFound;
 	}
+
 	if (treasures.size())
 	{
-		//find object closest to zone center, then con nect it to the middle of the zone
-		int3 zoneCenter = getPos();
+		//find object closest to zone center, then connect it to the middle of the zone
+		int3 closestFreeTile (-1,-1,-1);
+		if (info.visitableFromBottomPositions.size()) //get random treasure tile, starting from objects accessible only from bottom
+			closestFreeTile = findClosestTile (freePaths, *RandomGeneratorUtil::nextItem(info.visitableFromBottomPositions, gen->rand));
+		else
+			closestFreeTile = findClosestTile (freePaths, *RandomGeneratorUtil::nextItem(info.visitableFromTopPositions, gen->rand));
+
 		int3 closestTile = int3(-1,-1,-1);
 		float minDistance = 1e10;
-		for (auto treasure : treasures)
+		for (auto visitablePos : info.visitableFromBottomPositions) //objects that are not visitable from top must be accessible from bottom or side
 		{
-			if (zoneCenter.dist2d(treasure.first) < minDistance)
+			if (closestFreeTile.dist2d(visitablePos) < minDistance)
 			{
-				closestTile = treasure.first;
-				minDistance = zoneCenter.dist2d(treasure.first);
+				closestTile = visitablePos + int3 (0, 1, 0); //start below object (y+1), possibly even outside the map (?)
+				minDistance = closestFreeTile.dist2d(visitablePos);
+			}
+		}
+		if (!closestTile.valid())
+		{
+			for (auto visitablePos : info.visitableFromTopPositions) //all objects are accessible from any direction
+			{
+				if (closestFreeTile.dist2d(visitablePos) < minDistance)
+				{
+					closestTile = visitablePos;
+					minDistance = closestFreeTile.dist2d(visitablePos);
+				}
 			}
 		}
 		assert (closestTile.valid());
-		if (!crunchPath (gen, closestTile, getPos(), id)) //make sure pile is connected to the middle of zone
+
+		for (auto tile : info.occupiedPositions)
 		{
+			if (gen->map->isInTheMap(tile)) //pile boundary may reach map border
+				gen->setOccupied(tile, ETileType::BLOCKED); //so that crunch path doesn't cut through objects
+		}
+
+		if (!crunchPath (gen, closestTile, closestFreeTile, id))
+		{
+			//we can't connect this pile, just block it off and start over
 			for (auto treasure : treasures)
 			{
 				if (gen->isPossible(treasure.first))
@@ -686,6 +801,25 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
 			return true;
 		}
 
+		//update boundary around our objects, including knowledge about objects visitable from bottom
+
+		boundary.clear();
+		for (auto tile : info.visitableFromBottomPositions)
+		{
+			gen->foreach_neighbour (tile, [tile, &boundary](int3 pos)
+			{
+				if (pos.y >= tile.y) //don't block these objects from above
+					boundary.insert(pos);
+			});
+		}
+		for (auto tile : info.visitableFromTopPositions)
+		{
+			gen->foreach_neighbour (tile, [&boundary](int3 pos)
+			{
+				boundary.insert(pos);
+			});
+		}
+
 		for (auto tile : boundary) //guard must be standing there
 		{
 			if (gen->isFree(tile)) //this tile could be already blocked, don't place a monster here
@@ -699,15 +833,22 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
 		{
 			for (auto treasure : treasures)
 			{
-				placeObject(gen, treasure.second, treasure.first - treasure.second->getVisitableOffset());
+				int3 visitableOffset = treasure.second->getVisitableOffset();
+				placeObject(gen, treasure.second, treasure.first + visitableOffset);
 			}
-			if (addMonster(gen, guardPos, currentValue))
+			if (addMonster(gen, guardPos, currentValue, false))
 			{//block only if the object is guarded
 				for (auto tile : boundary)
 				{
 					if (gen->isPossible(tile))
 						gen->setOccupied (tile, ETileType::BLOCKED);
 				}
+				//do not spawn anything near monster
+				gen->foreach_neighbour (guardPos, [gen](int3 pos)
+				{
+					if (gen->isPossible(pos))
+						gen->setOccupied(pos, ETileType::FREE);
+				});
 			}
 		}
 		else //we couldn't make a connection to this location, block it
@@ -746,8 +887,15 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen)
 				town->builtBuildings.insert(BuildingID::FORT);
 			town->builtBuildings.insert(BuildingID::DEFAULT);
 
-			if (!totalTowns) //first town in zone goes in the middle
-				placeObject(gen, town, getPos() + town->getVisitableOffset());
+			if (!totalTowns) 
+			{
+				//first town in zone sets the facton of entire zone
+				town->subID = townType;
+				//register MAIN town of zone
+				gen->registerZone(town->subID);
+				//first town in zone goes in the middle
+				placeAndGuardObject(gen, town, getPos() + town->getVisitableOffset(), 0);
+			}
 			else
 				addRequiredObject (town);
 			totalTowns++;
@@ -776,9 +924,12 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen)
 			town->tempOwner = player;
 			town->builtBuildings.insert(BuildingID::FORT);
 			town->builtBuildings.insert(BuildingID::DEFAULT);
-			placeObject(gen, town, getPos() + town->getVisitableOffset()); //towns are big objects and should be centered around visitable position
+			//towns are big objects and should be centered around visitable position
+			placeAndGuardObject(gen, town, getPos() + town->getVisitableOffset(), 0); //generate no guards, but free path to entrance
 
 			totalTowns++;
+			//register MAIN town of zone only
+			gen->registerZone (town->subID);
 
 			logGlobal->traceStream() << "Fill player info " << player_id;
 
@@ -819,7 +970,23 @@ void CRmgTemplateZone::initTerrainType (CMapGenerator* gen)
 	else
 		terrainType = *RandomGeneratorUtil::nextItem(terrainTypes, gen->rand);
 
-	//paint zone with matching terrain
+	//TODO: allow new types of terrain?
+	if (pos.z)
+	{
+		if (terrainType != ETerrainType::LAVA)
+			terrainType = ETerrainType::SUBTERRANEAN;
+	}
+	else
+	{
+		if (terrainType == ETerrainType::SUBTERRANEAN)
+			terrainType = ETerrainType::DIRT;
+	}
+
+	paintZoneTerrain (gen, terrainType);
+}
+
+void CRmgTemplateZone::paintZoneTerrain (CMapGenerator* gen, ETerrainType terrainType)
+{
 	std::vector<int3> tiles;
 	for (auto tile : tileinfo)
 	{
@@ -893,8 +1060,8 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
 		}
 		logGlobal->traceStream() << "Place found";
 
-		placeObject(gen, obj.first, pos);
-		guardObject (gen, obj.first, obj.second);
+		placeObject (gen, obj.first, pos);
+		guardObject (gen, obj.first, obj.second, (obj.first->ID == Obj::MONOLITH_TWO_WAY));
 	}
 	return true;
 }
@@ -916,7 +1083,40 @@ void CRmgTemplateZone::createTreasures(CMapGenerator* gen)
 }
 
 void CRmgTemplateZone::createObstacles(CMapGenerator* gen)
-{
+{ 
+	if (pos.z) //underground
+	{
+		std::vector<int3> rockTiles;
+
+		for (auto tile : tileinfo)
+		{	
+			if (gen->shouldBeBlocked(tile))
+			{
+				bool placeRock = true;
+				gen->foreach_neighbour (tile, [gen, &placeRock](int3 &pos)
+				{
+					if (!(gen->shouldBeBlocked(pos) || gen->isPossible(pos)))
+						placeRock = false;
+				});
+				if (placeRock)
+				{
+					rockTiles.push_back(tile);
+				}
+			}
+		}
+		gen->editManager->getTerrainSelection().setSelection(rockTiles);
+		gen->editManager->drawTerrain(ETerrainType::ROCK, &gen->rand);
+		//for (auto tile : rockTiles)
+		//{
+		//	gen->setOccupied (tile, ETileType::USED);
+		//	gen->foreach_neighbour (tile, [gen](int3 &pos)
+		//	{
+		//		if (!gen->isUsed(pos))
+		//			gen->setOccupied (pos, ETileType::BLOCKED);
+		//	});
+		//}
+	}
+
 	//get all possible obstacles for this terrain
 	for (auto primaryID : VLC->objtypeh->knownObjects()) 
 	{ 
@@ -940,7 +1140,7 @@ void CRmgTemplateZone::createObstacles(CMapGenerator* gen)
 	auto tryToPlaceObstacleHere = [this, gen](int3& tile)-> bool
 	{
 		auto temp = *RandomGeneratorUtil::nextItem(possibleObstacles, gen->rand);
-		int3 obstaclePos = tile + temp.getBlockMapOffset();
+		int3 obstaclePos = tile - temp.getBlockMapOffset();
 		if (canObstacleBePlacedHere(gen, temp, obstaclePos)) //can be placed here
 		{
 			auto obj = VLC->objtypeh->getHandlerFor(temp.id, temp.subid)->create(temp);
@@ -966,9 +1166,12 @@ void CRmgTemplateZone::createObstacles(CMapGenerator* gen)
 
 bool CRmgTemplateZone::fill(CMapGenerator* gen)
 {
-	addAllPossibleObjects (gen);
 	initTownType(gen);
 	initTerrainType(gen);
+
+	freePaths.insert(pos); //zone center should be always clear to allow other tiles to connect
+
+	addAllPossibleObjects (gen);
 	placeMines(gen);
 	createRequiredObjects(gen);
 	fractalize(gen); //after required objects are created and linked with their own paths
@@ -1017,19 +1220,45 @@ bool CRmgTemplateZone::findPlaceForTreasurePile(CMapGenerator* gen, si32 min_dis
 
 bool CRmgTemplateZone::canObstacleBePlacedHere(CMapGenerator* gen, ObjectTemplate &temp, int3 &pos)
 {
+	if (!gen->map->isInTheMap(pos)) //blockmap may fit in the map, but botom-right corner does not
+		return false;
+
 	auto tilesBlockedByObject = temp.getBlockedOffsets();
 
-	bool allTilesAvailable = true;
 	for (auto blockingTile : tilesBlockedByObject)
 	{
 		int3 t = pos + blockingTile;
 		if (!gen->map->isInTheMap(t) || !(gen->isPossible(t) || gen->shouldBeBlocked(t)))
 		{
-			allTilesAvailable = false; //if at least one tile is not possible, object can't be placed here
-			break;
+			return false; //if at least one tile is not possible, object can't be placed here
 		}
 	}
-	return allTilesAvailable;
+	return true;
+}
+
+bool CRmgTemplateZone::isAccessibleFromAnywhere (CMapGenerator* gen, ObjectTemplate &appearance,  int3 &tile, const std::set<int3> &tilesBlockedByObject) const
+{
+	bool accessible = false;
+	for (int x = -1; x < 2; x++)
+	{
+		for (int y = -1; y <2; y++)
+		{
+			if (x && y) //check only if object is visitable from another tile
+			{
+				int3 offset = appearance.getVisitableOffset() + int3(x, y, 0);
+				if (!vstd::contains(tilesBlockedByObject, offset))
+				{
+					int3 nearbyPos = tile + offset;
+					if (gen->map->isInTheMap(nearbyPos))
+					{
+						if (appearance.isVisitableFrom(x, y) && !gen->isBlocked(nearbyPos))
+							accessible = true;
+					}
+				}
+			}
+		};
+	}
+	return accessible;
 }
 
 bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos)
@@ -1057,25 +1286,7 @@ bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance*
 	for (auto tile : tileinfo)
 	{
 		//object must be accessible from at least one surounding tile
-		bool accessible = false;
-		for (int x = -1; x < 2; x++)
-			for (int y = -1; y <2; y++)
-		{
-			if (x && y) //check only if object is visitable from another tile
-			{
-				int3 offset = obj->getVisitableOffset() + int3(x, y, 0);
-				if (!vstd::contains(tilesBlockedByObject, offset))
-				{
-					int3 nearbyPos = tile + offset;
-					if (gen->map->isInTheMap(nearbyPos))
-					{
-						if (obj->appearance.isVisitableFrom(x, y) && !gen->isBlocked(nearbyPos))
-							accessible = true;
-					}
-				}
-			}
-		};
-		if (!accessible)
+		if (!isAccessibleFromAnywhere(gen, obj->appearance, tile, tilesBlockedByObject))
 			continue;
 
 		auto ti = gen->getTile(tile);
@@ -1111,7 +1322,7 @@ bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance*
 void CRmgTemplateZone::checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos)
 {
 	if (!gen->map->isInTheMap(pos))
-		throw rmgException(boost::to_string(boost::format("Position of object %d at %s is outside the map") % object->id % object->pos()));
+		throw rmgException(boost::to_string(boost::format("Position of object %d at %s is outside the map") % object->id % pos));
 	object->pos = pos;
 
 	if (object->isVisitable() && !gen->map->isInTheMap(object->visitablePos()))
@@ -1124,9 +1335,10 @@ void CRmgTemplateZone::checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance*
 
 	if (object->appearance.id == Obj::NO_OBJ)
 	{
-		auto templates = VLC->objtypeh->getHandlerFor(object->ID, object->subID)->getTemplates(gen->map->getTile(pos).terType);
+		auto terrainType = gen->map->getTile(pos).terType;
+		auto templates = VLC->objtypeh->getHandlerFor(object->ID, object->subID)->getTemplates(terrainType);
 		if (templates.empty())
-			throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s") %object->ID %object->subID %pos));
+			throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s (terrain %d)") %object->ID %object->subID %pos %terrainType));
 	
 		object->appearance = templates.front();
 	}
@@ -1160,6 +1372,12 @@ void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object,
 	}
 }
 
+void CRmgTemplateZone::placeAndGuardObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos, si32 str, bool zoneGuard)
+{
+	placeObject(gen, object, pos);
+	guardObject(gen, object, str, zoneGuard);
+}
+
 std::vector<int3> CRmgTemplateZone::getAccessibleOffsets (CMapGenerator* gen, CGObjectInstance* object)
 {
 	//get all tiles from which this object can be accessed
@@ -1186,7 +1404,7 @@ std::vector<int3> CRmgTemplateZone::getAccessibleOffsets (CMapGenerator* gen, CG
 	return tiles;
 }
 
-bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str)
+bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str, bool zoneGuard)
 {
 	logGlobal->traceStream() << boost::format("Guard object at %s") % object->pos();
 
@@ -1197,7 +1415,7 @@ bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object,
 	for (auto tile : tiles)
 	{
 		//crunching path may fail if center of teh zone is dirrectly over wide object
-		if (crunchPath (gen, tile, getPos(), id)) //make sure object is accessible before surrounding it with blocked tiles
+		if (crunchPath (gen, tile, findClosestTile(freePaths, tile), id)) //make sure object is accessible before surrounding it with blocked tiles
 		{
 			guardTile = tile;
 			break;
@@ -1209,7 +1427,7 @@ bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object,
 		return false;
 	}
 
-	if (addMonster (gen, guardTile, str)) //do not place obstacles around unguarded object
+	if (addMonster (gen, guardTile, str, false, zoneGuard)) //do not place obstacles around unguarded object
 	{
 		for (auto pos : tiles)
 		{
@@ -1222,14 +1440,17 @@ bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object,
 	else //allow no guard or other object in front of this object
 	{
 		for (auto tile : tiles)
-			gen->setOccupied (tile, ETileType::FREE);
+			if (gen->isPossible(pos))
+				gen->setOccupied (tile, ETileType::FREE);
 	}
 
 	return true;
 }
 
-ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, ui32 value)
+ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileInfo &info, ui32 value)
 {
+	//int objectsVisitableFromBottom = 0; //for debug
+
 	std::vector<std::pair<ui32, ObjectInfo>> tresholds;
 	ui32 total = 0;
 
@@ -1238,19 +1459,106 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, ui32 value)
 	//roulette wheel
 	for (auto oi : possibleObjects)
 	{
-		if (oi.value >= minValue && oi.value <= value)
+		if (oi.value >= minValue && oi.value <= value && oi.maxPerZone > 0)
 		{
-			//TODO: check place for non-removable object
-			//problem: we need at least template for the object that does not yet exist
+			int3 newVisitableOffset = oi.templ.getVisitableOffset(); //visitablePos assumes object will be shifter by visitableOffset
+			int3 newVisitablePos = info.nextTreasurePos;
+
+			if (!oi.templ.isVisitableFromTop())
+			{
+				//objectsVisitableFromBottom++;
+				//there must be free tiles under object
+				auto blockedOffsets = oi.templ.getBlockedOffsets();
+				if (!isAccessibleFromAnywhere(gen, oi.templ, newVisitablePos, blockedOffsets))
+					continue;
+			}
+
+			//NOTE: y coordinate grows downwards
+			if (info.visitableFromBottomPositions.size() + info.visitableFromTopPositions.size()) //do not try to match first object in zone
+			{
+				bool fitsHere = false;
+
+				if (oi.templ.isVisitableFromTop()) //new can be accessed from any direction
+				{
+					for (auto tile : info.visitableFromTopPositions)
+					{
+						int3 actualTile = tile + newVisitableOffset;
+						if (newVisitablePos.areNeighbours(actualTile)) //we access other removable object from any position
+						{
+							fitsHere = true;
+							break;
+						}
+					}
+					for (auto tile : info.visitableFromBottomPositions)
+					{
+						int3 actualTile = tile + newVisitableOffset;
+						if (newVisitablePos.areNeighbours(actualTile) && newVisitablePos.y >= actualTile.y) //we access existing static object from side or bottom only
+						{
+							fitsHere = true;
+							break;
+						}
+					}
+				}
+				else //if new object is not visitable from top, it must be accessible from below or side
+				{
+					for (auto tile : info.visitableFromTopPositions)
+					{
+						int3 actualTile = tile + newVisitableOffset;
+						if (newVisitablePos.areNeighbours(actualTile) && newVisitablePos.y <= actualTile.y) //we access existing removable object from top or side only
+						{
+							fitsHere = true;
+							break;
+						}
+					}
+					for (auto tile : info.visitableFromBottomPositions)
+					{
+						int3 actualTile = tile + newVisitableOffset;
+						if (newVisitablePos.areNeighbours(actualTile) && newVisitablePos.y == actualTile.y) //we access other static object from side only
+						{
+							fitsHere = true;
+							break;
+						}
+					}
+				}
+				if (!fitsHere)
+					continue;
+			}
+
+			//now check blockmap, including our already reserved pile area
+
+			bool fitsBlockmap = true;
+
+
+			std::set<int3> blockedOffsets = oi.templ.getBlockedOffsets();
+			blockedOffsets.insert (newVisitableOffset);
+			for (auto blockingTile : blockedOffsets)
+			{
+				int3 t = info.nextTreasurePos + newVisitableOffset + blockingTile;
+				if (!gen->map->isInTheMap(t) || vstd::contains(info.occupiedPositions, t))
+				{
+					fitsBlockmap = false; //if at least one tile is not possible, object can't be placed here
+					break;
+				}
+				if (!(gen->isPossible(t) || gen->isBlocked(t))) //blocked tiles of object may cover blocked tiles, but not used or free tiles
+				{
+					fitsBlockmap = false;
+					break;
+				}
+			}
+			if (!fitsBlockmap)
+				continue;
+
 			total += oi.probability;
 			tresholds.push_back (std::make_pair (total, oi));
 		}
 	}
 
-	//TODO: generate pandora box with gold if the value is very high
+	//logGlobal->infoStream() << boost::format ("Number of objects visitable  from bottom: %d") % objectsVisitableFromBottom;
+
+	//Generate pandora Box with gold if the value is extremely high
+	ObjectInfo oi;
 	if (tresholds.empty())
 	{
-		ObjectInfo oi;
 		if (minValue > 20000) //we don't have object valuable enough
 		{
 			oi.generateObject = [minValue]() -> CGObjectInstance *
@@ -1261,6 +1569,7 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, ui32 value)
 				obj->resources[Res::GOLD] = minValue;
 				return obj;
 			};
+			oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType);
 			oi.value = minValue;
 			oi.probability = 0;
 		}
@@ -1270,6 +1579,7 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, ui32 value)
 			{
 				return nullptr;
 			};
+			oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); //TODO: null template or something? should be never used, but hell knows
 			oi.value = 0;
 			oi.probability = 0;
 		}
@@ -1288,120 +1598,78 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, ui32 value)
 
 void CRmgTemplateZone::addAllPossibleObjects (CMapGenerator* gen)
 {
-	//TODO: move typical objects to config
-
 	ObjectInfo oi;
+	oi.maxPerMap = std::numeric_limits<ui32>().max();
 
-	static const Res::ERes preciousRes[] = {Res::ERes::CRYSTAL, Res::ERes::GEMS, Res::ERes::MERCURY, Res::ERes::SULFUR};
-	for (int i = 0; i < 4; i++)
-	{
-		oi.generateObject = [i, gen]() -> CGObjectInstance *
-		{
-			auto obj = new CGResource();
-			obj->ID = Obj::RESOURCE;
-			obj->subID = static_cast<si32>(preciousRes[i]);
-			obj->amount = 0;
-			return obj;
-		};
-		oi.value = 1400;
-		oi.probability = 300;
-		possibleObjects.push_back (oi);
+	for (auto primaryID : VLC->objtypeh->knownObjects()) 
+	{ 
+		for (auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID)) 
+		{ 
+			auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID); 
+			if (!handler->isStaticObject() && handler->getRMGInfo().value)
+			{
+				for (auto temp : handler->getTemplates())
+				{
+					if (temp.canBePlacedAt(terrainType))
+					{
+						oi.generateObject = [gen, temp]() -> CGObjectInstance *
+						{
+							return VLC->objtypeh->getHandlerFor(temp.id, temp.subid)->create(temp);
+						};
+						oi.value = handler->getRMGInfo().value;
+						oi.probability = handler->getRMGInfo().rarity;
+						oi.templ = temp;
+						oi.maxPerZone = handler->getRMGInfo().zoneLimit;
+						possibleObjects.push_back (oi);
+					}
+				}
+			}
+		} 
 	}
 
-	static const Res::ERes woodOre[] = {Res::ERes::WOOD, Res::ERes::ORE};
-	for (int i = 0; i < 2; i++)
-	{
-		oi.generateObject = [i, gen]() -> CGObjectInstance *
-		{
-			auto obj = new CGResource();
-			obj->ID = Obj::RESOURCE;
-			obj->subID = static_cast<si32>(woodOre[i]);
-			obj->amount = 0;
-			return obj;
-		};
-		oi.value = 1400;
-		oi.probability = 300;
-		possibleObjects.push_back (oi);
-	}
+	//all following objects are unlimited
+	oi.maxPerZone = std::numeric_limits<ui32>().max();
 
-	oi.generateObject = [gen]() -> CGObjectInstance *
-	{
-		auto obj = new CGResource();
-		obj->ID = Obj::RESOURCE;
-		obj->subID = static_cast<si32>(Res::ERes::GOLD);
-		obj->amount = 0;
-		return obj;
-	};
-	oi.value = 750;
-	oi.probability = 300;
-	possibleObjects.push_back (oi);
+	//dwellings
 
-	oi.generateObject = [gen]() -> CGObjectInstance *
-	{
-		auto obj = new CGPickable();
-		obj->ID = Obj::TREASURE_CHEST;
-		obj->subID = 0;
-		return obj;
-	};
-	oi.value = 1500;
-	oi.probability = 1000;
-	possibleObjects.push_back (oi);
+	auto subObjects = VLC->objtypeh->knownSubObjects(Obj::CREATURE_GENERATOR1);
 
-	oi.generateObject = [gen]() -> CGObjectInstance *
-	{
-		auto obj = new CGArtifact();
-		obj->ID = Obj::RANDOM_TREASURE_ART;
-		obj->subID = 0;
-		auto a = new CArtifactInstance();
-		gen->map->addNewArtifactInstance(a);
-		obj->storedArtifact = a;
-		return obj;
-	};
-	oi.value = 2000;
-	oi.probability = 150;
-	possibleObjects.push_back (oi);
+	//don't spawn original "neutral" dwellings that got replaced by Conflux dwellings in AB
+	static int elementalConfluxROE[] = {7, 13, 16, 47};
+	for (int i = 0; i < 4; i++)
+		vstd::erase_if_present(subObjects, elementalConfluxROE[i]);
 
-	oi.generateObject = [gen]() -> CGObjectInstance *
+	for (auto secondaryID : subObjects)
 	{
-		auto obj = new CGArtifact();
-		obj->ID = Obj::RANDOM_MINOR_ART;
-		obj->subID = 0;
-		auto a = new CArtifactInstance();
-		gen->map->addNewArtifactInstance(a);
-		obj->storedArtifact = a;
-		return obj;
-	};
-	oi.value = 5000;
-	oi.probability = 150;
-	possibleObjects.push_back (oi);
+		auto dwellingHandler = dynamic_cast<const CDwellingInstanceConstructor*>(VLC->objtypeh->getHandlerFor(Obj::CREATURE_GENERATOR1, secondaryID).get());
+		auto creatures = dwellingHandler->getProducedCreatures();
+		if (creatures.empty())
+			continue;
 
-		oi.generateObject = [gen]() -> CGObjectInstance *
-	{
-		auto obj = new CGArtifact();
-		obj->ID = Obj::RANDOM_MAJOR_ART;
-		obj->subID = 0;
-		auto a = new CArtifactInstance();
-		gen->map->addNewArtifactInstance(a);
-		obj->storedArtifact = a;
-		return obj;
-	};
-	oi.value = 10000;
-	oi.probability = 150;
-	possibleObjects.push_back (oi);
+		auto cre = creatures.front();
+		if (cre->faction == townType)
+		{
+			oi.value = cre->AIValue * cre->growth * (1 + (float)(gen->getZoneCount(cre->faction)) / gen->getTotalZoneCount() + (float)(gen->getZoneCount(cre->faction) / 2)); //TODO: include town count in formula
+			oi.probability = 40;
 
-	oi.generateObject = [gen]() -> CGObjectInstance *
-	{
-		auto obj = new CGArtifact();
-		obj->ID = Obj::RANDOM_RELIC_ART;
-		obj->subID = 0;
-		auto a = new CArtifactInstance();
-		gen->map->addNewArtifactInstance(a);
-		obj->storedArtifact = a;
-		return obj;
-	};
-	oi.value = 20000;
-	oi.probability = 150;
-	possibleObjects.push_back (oi);
+			for (auto temp : dwellingHandler->getTemplates())
+			{
+				if (temp.canBePlacedAt(terrainType))
+				{
+					oi.generateObject = [gen, temp, secondaryID, dwellingHandler]() -> CGObjectInstance *
+					{
+						auto obj = VLC->objtypeh->getHandlerFor(Obj::CREATURE_GENERATOR1, secondaryID)->create(temp);
+						//dwellingHandler->configureObject(obj, gen->rand);
+						obj->tempOwner = PlayerColor::NEUTRAL;
+						return obj;
+					};
+
+					oi.templ = temp;
+					possibleObjects.push_back (oi);
+				}
+			}
+		}
+	}
 
 	static const int scrollValues[] = {500, 2000, 3000, 4000, 5000};
 
@@ -1428,43 +1696,192 @@ void CRmgTemplateZone::addAllPossibleObjects (CMapGenerator* gen)
 			obj->storedArtifact = a;
 			return obj;
 		};
+		oi.setTemplate (Obj::SPELL_SCROLL, 0, terrainType);
 		oi.value = scrollValues[i];
 		oi.probability = 30;
 		possibleObjects.push_back (oi);
 	}
 
-	//non-removable object for test
-	//oi.generateObject = [gen]() -> CGObjectInstance *
-	//{
-	//	auto obj = new CGMagicWell();
-	//	obj->ID = Obj::MAGIC_WELL;
-	//	obj->subID = 0;
-	//	return obj;
-	//};
-	//oi.value = 250;
-	//oi.probability = 100;
-	//possibleObjects.push_back (oi);
-
-	//oi.generateObject = [gen]() -> CGObjectInstance *
-	//{
-	//	auto obj = new CGObelisk();
-	//	obj->ID = Obj::OBELISK;
-	//	obj->subID = 0;
-	//	return obj;
-	//};
-	//oi.value = 3500;
-	//oi.probability = 200;
-	//possibleObjects.push_back (oi);
-
-	//oi.generateObject = [gen]() -> CGObjectInstance *
-	//{
-	//	auto obj = new CBank();
-	//	obj->ID = Obj::CREATURE_BANK;
-	//	obj->subID = 5; //naga bank
-	//	return obj;
-	//};
-	//oi.value = 3000;
-	//oi.probability = 100;
-	//possibleObjects.push_back (oi);
-	
+	//pandora box with gold
+	for (int i = 1; i < 5; i++)
+	{
+		oi.generateObject = [i]() -> CGObjectInstance *
+		{
+			auto obj = new CGPandoraBox();
+			obj->ID = Obj::PANDORAS_BOX;
+			obj->subID = 0;
+			obj->resources[Res::GOLD] = i * 5000;
+			return obj;
+		};
+		oi.setTemplate (Obj::PANDORAS_BOX, 0, terrainType);
+		oi.value = i * 5000;;
+		oi.probability = 5;
+		possibleObjects.push_back (oi);
+	}
+
+	//pandora box with experience
+	for (int i = 1; i < 5; i++)
+	{
+		oi.generateObject = [i]() -> CGObjectInstance *
+		{
+			auto obj = new CGPandoraBox();
+			obj->ID = Obj::PANDORAS_BOX;
+			obj->subID = 0;
+			obj->gainedExp = i * 5000;
+			return obj;
+		};
+		oi.setTemplate (Obj::PANDORAS_BOX, 0, terrainType);
+		oi.value = i * 6000;;
+		oi.probability = 20;
+		possibleObjects.push_back (oi);
+	}
+
+	//pandora box with creatures
+	static const int tierValues[] = {5000, 7000, 9000, 12000, 16000, 21000, 27000};
+
+	for (auto creature : VLC->creh->creatures)
+	{
+		if (!creature->special && VLC->townh->factions[creature->faction]->nativeTerrain == terrainType)
+		{
+			int actualTier = creature->level > 7 ? 6 : creature->level-1;
+			int creaturesAmount = tierValues[actualTier] / creature->AIValue;
+			if (creaturesAmount <= 5)
+			{
+			}
+			else if (creaturesAmount <= 12)
+			{
+				(creaturesAmount /= 2) *= 2;
+			}
+			else if (creaturesAmount <= 50)
+			{
+				creaturesAmount = boost::math::round((float)creaturesAmount / 5) * 5;
+			}
+			else if (creaturesAmount <= 12)
+			{
+				creaturesAmount = boost::math::round((float)creaturesAmount / 10) * 10;
+			}
+
+			oi.generateObject = [creature, creaturesAmount]() -> CGObjectInstance *
+			{
+				auto obj = new CGPandoraBox();
+				obj->ID = Obj::PANDORAS_BOX;
+				obj->subID = 0;
+				auto stack = new CStackInstance(creature, creaturesAmount);
+				obj->creatures.putStack(SlotID(0), stack);
+				return obj;
+			};
+			oi.setTemplate (Obj::PANDORAS_BOX, 0, terrainType);
+			oi.value = (2 * (creature->AIValue) * creaturesAmount * (1 + (float)(gen->getZoneCount(creature->faction)) / gen->getTotalZoneCount()))/3; //TODO: count number of towns on the map
+			oi.probability = 3;
+			possibleObjects.push_back (oi);
+		}
+	}
+
+	//Pandora with 12 spells of certain level
+	for (int i = 1; i <= GameConstants::SPELL_LEVELS; i++)
+	{
+		oi.generateObject = [i, gen]() -> CGObjectInstance *
+		{
+			auto obj = new CGPandoraBox();
+			obj->ID = Obj::PANDORAS_BOX;
+			obj->subID = 0;
+
+			std::vector <CSpell *> spells;
+			for (auto spell : VLC->spellh->objects)
+			{
+				if (!spell->isSpecialSpell() && spell->level == i)
+					spells.push_back(spell);
+			}
+
+			RandomGeneratorUtil::randomShuffle(spells, gen->rand);
+			for (int j = 0; j < std::min<int>(12, spells.size()); j++)
+			{
+				obj->spells.push_back (spells[j]->id);
+			}
+
+			return obj;
+		};
+		oi.setTemplate (Obj::PANDORAS_BOX, 0, terrainType);
+		oi.value = (i + 1) * 2500; //5000 - 15000
+		oi.probability = 2;
+		possibleObjects.push_back (oi);
+	}
+
+	//Pandora with 15 spells of certain school
+	for (int i = 1; i <= 4; i++)
+	{
+		oi.generateObject = [i, gen]() -> CGObjectInstance *
+		{
+			auto obj = new CGPandoraBox();
+			obj->ID = Obj::PANDORAS_BOX;
+			obj->subID = 0;
+
+			std::vector <CSpell *> spells;
+			for (auto spell : VLC->spellh->objects)
+			{
+				if (!spell->isSpecialSpell())
+				{
+					bool school = false; //TODO: we could have better interface for iterating schools
+					switch (i)
+					{
+						case 1:
+							school = spell->air;
+						case 2:
+							school = spell->earth;
+						case 3:
+							school = spell->fire;
+						case 4:
+							school = spell->water;
+					}
+					if (school)
+						spells.push_back(spell);
+				}
+			}
+
+			RandomGeneratorUtil::randomShuffle(spells, gen->rand);
+			for (int j = 0; j < std::min<int>(15, spells.size()); j++)
+			{
+				obj->spells.push_back (spells[j]->id);
+			}
+
+			return obj;
+		};
+		oi.setTemplate (Obj::PANDORAS_BOX, 0, terrainType);
+		oi.value = 15000;
+		oi.probability = 2;
+		possibleObjects.push_back (oi);
+	}
+
+	// Pandora box with 60 random spells
+
+	oi.generateObject = [gen]() -> CGObjectInstance *
+	{
+		auto obj = new CGPandoraBox();
+		obj->ID = Obj::PANDORAS_BOX;
+		obj->subID = 0;
+
+		std::vector <CSpell *> spells;
+		for (auto spell : VLC->spellh->objects)
+		{
+			if (!spell->isSpecialSpell())
+				spells.push_back(spell);
+		}
+
+		RandomGeneratorUtil::randomShuffle(spells, gen->rand);
+		for (int j = 0; j < std::min<int>(60, spells.size()); j++)
+		{
+			obj->spells.push_back (spells[j]->id);
+		}
+
+		return obj;
+	};
+	oi.setTemplate (Obj::PANDORAS_BOX, 0, terrainType);
+	oi.value = 3000;
+	oi.probability = 2;
+	possibleObjects.push_back (oi);
 }
+
+void ObjectInfo::setTemplate (si32 type, si32 subtype, ETerrainType terrainType)
+{
+	templ = VLC->objtypeh->getHandlerFor(type, subtype)->getTemplates(terrainType).front();
+}

+ 26 - 3
lib/rmg/CRmgTemplateZone.h

@@ -16,6 +16,7 @@
 #include "float3.h"
 #include "../int3.h"
 #include "../ResourceSet.h" //for TResource (?)
+#include "../mapObjects/ObjectTemplate.h"
 
 class CMapGenerator;
 class CTileInfo;
@@ -45,6 +46,7 @@ public:
 	bool shouldBeBlocked() const;
 	bool isPossible() const;
 	bool isFree() const;
+	bool isUsed() const;
 	void setOccupied(ETileType::ETileType value);
 	ETerrainType getTerrainType() const;
 	void setTerrainType(ETerrainType value);
@@ -66,9 +68,25 @@ public:
 
 struct DLL_LINKAGE ObjectInfo
 {
+	ObjectTemplate templ;
 	ui32 value;
 	ui16 probability;
+	ui32 maxPerZone;
+	ui32 maxPerMap;
 	std::function<CGObjectInstance *()> generateObject;
+
+	void setTemplate (si32 type, si32 subtype, ETerrainType terrain);
+
+	bool operator==(const ObjectInfo& oi) const { return (templ == oi.templ); }
+};
+
+struct DLL_LINKAGE CTreasurePileInfo
+{
+	std::set<int3> visitableFromBottomPositions; //can be visited only from bottom or side
+	std::set<int3> visitableFromTopPositions; //they can be visited from any direction
+	std::set<int3> blockedPositions;
+	std::set<int3> occupiedPositions; //blocked + visitable
+	int3 nextTreasurePos;
 };
 
 /// The CRmgTemplateZone describes a zone in a template.
@@ -128,13 +146,15 @@ public:
 
 	void addTile (const int3 &pos);
 	std::set<int3> getTileInfo () const;
+	void discardDistantTiles (CMapGenerator* gen, float distance);
 
 	void addRequiredObject(CGObjectInstance * obj, si32 guardStrength=0);
-	bool addMonster(CMapGenerator* gen, int3 &pos, si32 strength);
+	bool addMonster(CMapGenerator* gen, int3 &pos, si32 strength, bool clearSurroundingTiles = true, bool zoneGuard = false);
 	bool createTreasurePile (CMapGenerator* gen, int3 &pos);
 	bool fill (CMapGenerator* gen);
 	bool placeMines (CMapGenerator* gen);
 	void initTownType (CMapGenerator* gen);
+	void paintZoneTerrain (CMapGenerator* gen, ETerrainType terrainType);
 	void initTerrainType (CMapGenerator* gen);
 	void createBorder(CMapGenerator* gen);
 	void fractalize(CMapGenerator* gen);
@@ -152,7 +172,9 @@ public:
 	std::vector<CTreasureInfo> getTreasureInfo();
 	std::set<int3>* getFreePaths();
 
-	ObjectInfo getRandomObject (CMapGenerator* gen, ui32 value);
+	ObjectInfo getRandomObject (CMapGenerator* gen, CTreasurePileInfo &info, ui32 value);
+
+	void placeAndGuardObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos, si32 str, bool zoneGuard = false);
 
 private:
 	//template info
@@ -189,10 +211,11 @@ private:
 
 	bool pointIsIn(int x, int y);
 	void addAllPossibleObjects (CMapGenerator* gen); //add objects, including zone-specific, to possibleObjects
+	bool isAccessibleFromAnywhere (CMapGenerator* gen, ObjectTemplate &appearance, int3 &tile, const std::set<int3> &tilesBlockedByObject) const;
 	bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos);
 	bool findPlaceForTreasurePile(CMapGenerator* gen, si32 min_dist, int3 &pos);
 	bool canObstacleBePlacedHere(CMapGenerator* gen, ObjectTemplate &temp, int3 &pos);
 	void checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos);
 	void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos);
-	bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str);
+	bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str, bool zoneGuard = false);
 };

+ 68 - 27
lib/rmg/CZonePlacer.cpp

@@ -43,7 +43,8 @@ void CZonePlacer::placeZones(shared_ptr<CMapGenOptions> mapGenOptions, CRandomGe
 	//some relaxation-simmulated annealing algorithm
 
 	const int iterations = 100;
-	float temperature = 1e-2;;
+	float temperatureConstant = 1e-2;
+	float currentTemperature = 2; //geater temperature - stronger gravity, weaker pushing away
 	const float temperatureModifier = 0.99;
 
 	logGlobal->infoStream() << "Starting zone placement";
@@ -52,8 +53,7 @@ void CZonePlacer::placeZones(shared_ptr<CMapGenOptions> mapGenOptions, CRandomGe
 	int height = mapGenOptions->getHeight();
 
 	auto zones = gen->getZones();
-
-	//TODO: consider underground zones
+	bool underground = mapGenOptions->getHasTwoLevels();
 
 	/*
 		let's assume we try to fit N circular zones with radius = size on a map
@@ -62,13 +62,37 @@ void CZonePlacer::placeZones(shared_ptr<CMapGenOptions> mapGenOptions, CRandomGe
 
 		prescaler = sqrt((WH)/(sum(n^2)*pi))
 	*/
+	std::vector<std::pair<TRmgTemplateZoneId, CRmgTemplateZone*>> zonesVector (zones.begin(), zones.end());
+	assert (zonesVector.size());
+	
+	RandomGeneratorUtil::randomShuffle(zonesVector, *rand);
+	TRmgTemplateZoneId firstZone = zones.begin()->first; //we want lowest ID here
+	bool undergroundFlag = false;
+
 	float totalSize = 0;
-	for (auto zone : zones)
+	for (auto zone : zonesVector)
 	{
+		//even distribution for surface / underground zones. Surface zones always have priority.
+		int level = 0;
+		if (underground) //only then consider underground zones
+		{
+			if (zone.first == firstZone)
+			{
+				level = 0;
+			}
+			else
+			{
+				level = undergroundFlag;
+				undergroundFlag = !undergroundFlag; //toggle underground on/off
+			}
+		}
+
 		totalSize += (zone.second->getSize() * zone.second->getSize());
-		zone.second->setCenter (float3(rand->nextDouble(0.2,0.8), rand->nextDouble(0.2,0.8), 0)); //start away from borders
+		zone.second->setCenter (float3(rand->nextDouble(0.2, 0.8), rand->nextDouble(0.2, 0.8), level)); //start away from borders
 	}
 	//prescale zones
+	if (underground) //map is twice as big, so zones occupy only half of normal space
+		totalSize /= 2;
 	float prescaler = sqrt ((width * height) / (totalSize * 3.14f)); 
 	float mapSize = sqrt (width * height);
 	for (auto zone : zones)
@@ -95,63 +119,66 @@ void CZonePlacer::placeZones(shared_ptr<CMapGenOptions> mapGenOptions, CRandomGe
 			for (auto con : zone.second->getConnections())
 			{
 				auto otherZone = zones[con];
-				float distance = pos.dist2d (otherZone->getCenter());
+				float3 otherZoneCenter = otherZone->getCenter();
+				float distance = pos.dist2d (otherZoneCenter);
 				float minDistance = (zone.second->getSize() + otherZone->getSize())/mapSize; //scale down to (0,1) coordinates
 				if (distance > minDistance)
 				{
-					forceVector += (otherZone->getCenter() - pos) / getDistance(distance); //positive value
+					//WARNING: compiler used to 'optimize' that line so it never actually worked
+					forceVector += (((otherZoneCenter - pos) / getDistance(distance)) * currentTemperature); //positive value
 				}
 			}
 			//separate overlaping zones
 			for (auto otherZone : zones)
 			{
-				if (zone == otherZone)
+				float3 otherZoneCenter = otherZone.second->getCenter();
+				//zones on different levels don't push away
+				if (zone == otherZone || pos.z != otherZoneCenter.z)
 					continue;
 
-				float distance = pos.dist2d (otherZone.second->getCenter());
+				float distance = pos.dist2d (otherZoneCenter);
 				float minDistance = (zone.second->getSize() + otherZone.second->getSize())/mapSize;
 				if (distance < minDistance)
 				{
-					forceVector -= (otherZone.second->getCenter() - pos) / getDistance(distance); //negative value
+					forceVector -= (otherZoneCenter - pos) / getDistance(distance) / currentTemperature; //negative value
 				}
 			}
 
 			//move zones away from boundaries
-			float3 boundary(0,0,pos.z);
 			float size = zone.second->getSize() / mapSize;
-			if (pos.x < size)
+
+			auto pushAwayFromBoundary = [&forceVector, pos, currentTemperature, &getDistance](float x, float y)
 			{
-				boundary = float3 (0, pos.y, pos.z);
+				float3 boundary = float3 (x, y, pos.z);
 				float distance = pos.dist2d(boundary);
-				forceVector -= (boundary - pos) / getDistance(distance); //negative value
+				forceVector -= (boundary - pos) / getDistance(distance) / currentTemperature; //negative value
+			};
+			if (pos.x < size)
+			{
+				pushAwayFromBoundary(0, pos.y);
 			}
 			if (pos.x > 1-size)
 			{
-				boundary = float3 (1, pos.y, pos.z);
-				float distance = pos.dist2d(boundary);
-				forceVector -= (boundary - pos) / getDistance(distance); //negative value
+				pushAwayFromBoundary(1, pos.y);
 			}
 			if (pos.y < size)
 			{
-				boundary = float3 (pos.x, 0, pos.z);
-				float distance = pos.dist2d(boundary);
-				forceVector -= (boundary - pos) / getDistance(distance); //negative value
+				pushAwayFromBoundary(pos.x, 0);
 			}
 			if (pos.y > 1-size)
 			{
-				boundary = float3 (pos.x, 1, pos.z);
-				float distance = pos.dist2d(boundary);
-				forceVector -= (boundary - pos) / getDistance(distance); //negative value
+				pushAwayFromBoundary(pos.x, 1);
 			}
 
-			forces[zone.second] = forceVector;
+			forceVector.z = 0; //operator - doesn't preserve z coordinate :/
+			forces[zone.second] = forceVector * temperatureConstant;
 		}
 		//update positions
 		for (auto zone : forces)
 		{
-			zone.first->setCenter (zone.first->getCenter() + zone.second * temperature);
+			zone.first->setCenter (zone.first->getCenter() + zone.second);
 		}
-		temperature *= temperatureModifier; //decrease temperature (needed?)
+		currentTemperature *= temperatureModifier; //decrease temperature (needed?)
 	}
 	for (auto zone : zones) //finalize zone positions
 	{
@@ -213,7 +240,10 @@ void CZonePlacer::assignZones(shared_ptr<CMapGenOptions> mapGenOptions)
 				int3 pos(i, j, k);
 				for (auto zone : zones)
 				{
-					distances.push_back (std::make_pair(zone.second, metric(pos, zone.second->getPos())));
+					if (zone.second->getPos().z == k)
+						distances.push_back (std::make_pair(zone.second, metric(pos, zone.second->getPos())));
+					else
+						distances.push_back (std::make_pair(zone.second, std::numeric_limits<float>::max()));
 				}
 				boost::sort (distances, compareByDistance);
 				distances.front().first->addTile(pos); //closest tile belongs to zone
@@ -230,7 +260,18 @@ void CZonePlacer::assignZones(shared_ptr<CMapGenOptions> mapGenOptions)
 			total += tile;
 		}
 		int size = tiles.size();
+		assert (size);
 		zone.second->setPos (int3(total.x/size, total.y/size, total.z/size));
+
+		//TODO: similiar for islands
+		if (zone.second->getPos().z)
+		{
+			zone.second->discardDistantTiles(gen, zone.second->getSize() + 1);
+
+			//make sure that terrain inside zone is not a rock
+			//FIXME: reorder actions?
+			zone.second->paintZoneTerrain (gen, ETerrainType::SUBTERRANEAN);
+		}
 	}
 	logGlobal->infoStream() << "Finished zone colouring";
 }