瀏覽代碼

Large changeset, first part of editing H3 objects via mods feature. Changes:
- loading of all objects (including H3 objects) will be directed by mod handlers
- common base for all handlers accessible from mod system (IHanderBase)
- json format changes: use struct with string ID's instead of vector

- fixed some gcc/clang errors and warnings
- fixed several cases of memory leaks and invalid memory access (mostly related to usage of bonus system and/or identifiers resolution)

Note that right now loading is much slower than before due to excessive json validation (or not fast enough validator)

Ivan Savenko 12 年之前
父節點
當前提交
c6cc6e6301
共有 85 個文件被更改,包括 4664 次插入4391 次删除
  1. 3 2
      AI/VCAI/VCAI.cpp
  2. 2 2
      Global.h
  3. 2 2
      client/CCastleInterface.cpp
  4. 0 3
      client/CMT.cpp
  5. 13 14
      client/CPreGame.cpp
  6. 12 12
      client/GUIClasses.cpp
  7. 1 1
      client/NetPacksClient.cpp
  8. 1 1
      client/battle/CBattleInterface.cpp
  9. 2593 2596
      config/artifacts.json
  10. 14 14
      config/creatures/castle.json
  11. 14 14
      config/creatures/conflux.json
  12. 14 14
      config/creatures/dungeon.json
  13. 14 14
      config/creatures/fortress.json
  14. 14 14
      config/creatures/inferno.json
  15. 14 14
      config/creatures/necropolis.json
  16. 15 15
      config/creatures/neutral.json
  17. 14 14
      config/creatures/rampart.json
  18. 9 9
      config/creatures/special.json
  19. 14 14
      config/creatures/stronghold.json
  20. 14 14
      config/creatures/tower.json
  21. 76 52
      config/creatures/wog.json
  22. 84 83
      config/factions/castle.json
  23. 91 86
      config/factions/conflux.json
  24. 83 81
      config/factions/dungeon.json
  25. 85 83
      config/factions/fortress.json
  26. 84 84
      config/factions/inferno.json
  27. 91 87
      config/factions/necropolis.json
  28. 91 88
      config/factions/rampart.json
  29. 82 80
      config/factions/stronghold.json
  30. 83 81
      config/factions/tower.json
  31. 10 0
      config/gameConfig.json
  32. 18 18
      config/heroClasses.json
  33. 16 16
      config/heroes/castle.json
  34. 16 16
      config/heroes/conflux.json
  35. 16 16
      config/heroes/dungeon.json
  36. 16 16
      config/heroes/fortress.json
  37. 16 16
      config/heroes/inferno.json
  38. 16 16
      config/heroes/necropolis.json
  39. 16 16
      config/heroes/rampart.json
  40. 12 12
      config/heroes/special.json
  41. 16 16
      config/heroes/stronghold.json
  42. 16 16
      config/heroes/tower.json
  43. 1 1
      config/schemas/artifact.json
  44. 1 1
      config/schemas/creature.json
  45. 4 4
      config/schemas/faction.json
  46. 1 1
      config/schemas/hero.json
  47. 1 1
      config/schemas/heroClass.json
  48. 1 1
      lib/BattleState.cpp
  49. 22 36
      lib/CArtHandler.cpp
  50. 11 13
      lib/CArtHandler.h
  51. 2 1
      lib/CBonusTypeHandler.cpp
  52. 1 0
      lib/CBonusTypeHandler.h
  53. 39 38
      lib/CCreatureHandler.cpp
  54. 33 22
      lib/CCreatureHandler.h
  55. 12 1
      lib/CDefObjInfoHandler.cpp
  56. 1 1
      lib/CDefObjInfoHandler.h
  57. 18 16
      lib/CGameState.cpp
  58. 1 6
      lib/CGeneralTextHandler.cpp
  59. 0 1
      lib/CGeneralTextHandler.h
  60. 125 146
      lib/CHeroHandler.cpp
  61. 21 31
      lib/CHeroHandler.h
  62. 1 0
      lib/CMakeLists.txt
  63. 199 46
      lib/CModHandler.cpp
  64. 49 4
      lib/CModHandler.h
  65. 29 24
      lib/CObjectHandler.cpp
  66. 3 2
      lib/CObjectHandler.h
  67. 6 10
      lib/CSpellHandler.cpp
  68. 2 4
      lib/CSpellHandler.h
  69. 104 118
      lib/CTownHandler.cpp
  70. 54 66
      lib/CTownHandler.h
  71. 5 1
      lib/GameConstants.h
  72. 1 1
      lib/HeroBonus.cpp
  73. 2 3
      lib/IGameCallback.cpp
  74. 40 0
      lib/IHandlerBase.h
  75. 4 4
      lib/JsonNode.cpp
  76. 3 1
      lib/ResourceSet.h
  77. 16 0
      lib/StringConstants.h
  78. 9 7
      lib/VCMI_Lib.cpp
  79. 2 2
      lib/VCMI_Lib.h
  80. 7 4
      lib/mapping/CMap.cpp
  81. 1 1
      lib/mapping/CMapEditManager.h
  82. 2 2
      lib/rmg/CMapGenerator.cpp
  83. 14 3
      server/CGameHandler.cpp
  84. 1 1
      server/CQuery.cpp
  85. 4 4
      server/CQuery.h

+ 3 - 2
AI/VCAI/VCAI.cpp

@@ -1490,7 +1490,7 @@ void VCAI::wander(HeroPtr h)
 			}
 		}
 		const ObjectIdRef&dest = dests.front();
-		logAi->debugStream() << "Of all %d destinations, object oid=%d seems nice", dests.size() % dest.id.getNum();
+		logAi->debugStream() << boost::format("Of all %d destinations, object oid=%d seems nice") % dests.size() % dest.id.getNum();
 		if(!goVisitObj(dest, h))
 		{
 			if(!dest)
@@ -1597,6 +1597,7 @@ void VCAI::validateVisitableObjs()
             logAi->errorStream() << helperObjInfo[obj].name << " at " << helperObjInfo[obj].pos << " shouldn't be on list!";
 			return true;
 		}
+		return false;
 	});
 }
 
@@ -2414,7 +2415,7 @@ TResources VCAI::estimateIncome() const
 		//TODO duplikuje newturn
 		if(t->hasBuilt(BuildingID::RESOURCE_SILO)) //there is resource silo
 		{
-			if(t->town->primaryRes == 127) //we'll give wood and ore
+			if(t->town->primaryRes == Res::WOOD_AND_ORE) //we'll give wood and ore
 			{
 				ret[Res::WOOD] ++;
 				ret[Res::ORE] ++;

+ 2 - 2
Global.h

@@ -575,7 +575,7 @@ namespace vstd
 		if(c.size())
 			return c.back();
 		else
-			return NULL;
+			return nullptr;
 	}
 
 	template <typename Container>
@@ -584,7 +584,7 @@ namespace vstd
 		if(c.size())
 			return c.front();
 		else
-			return NULL;
+			return nullptr;
 	}
 }
 using vstd::operator-=;

+ 2 - 2
client/CCastleInterface.cpp

@@ -110,7 +110,7 @@ void CBuildingRect::clickRight(tribool down, bool previousState)
 		if (bid < BuildingID::DWELL_FIRST)
 		{
 			CRClickPopup::createAndPush(CInfoWindow::genText(bld->Name(), bld->Description()),
-			                            new CComponent(CComponent::building, bld->tid, bld->bid));
+			                            new CComponent(CComponent::building, bld->town->faction->index, bld->bid));
 		}
 		else
 		{
@@ -1120,7 +1120,7 @@ void CTownInfo::clickRight(tribool down, bool previousState)
 {
 	if(down && building)
 		CRClickPopup::createAndPush(CInfoWindow::genText(building->Name(), building->Description()),
-		                            new CComponent(CComponent::building, building->tid, building->bid));
+		                            new CComponent(CComponent::building, building->town->faction->index, building->bid));
 
 }
 

+ 0 - 3
client/CMT.cpp

@@ -797,9 +797,6 @@ static void listenForEvents()
 				delete CGI->dobjinfo.get();
 				const_cast<CGameInfo*>(CGI)->dobjinfo = new CDefObjInfoHandler; 
 
-				VLC->dobjinfo = const_cast<CGameInfo*>(CGI)->dobjinfo; // update dobjinfo pointer in VLC (used by modHandler::reload())
-
-				const_cast<CGameInfo*>(CGI)->dobjinfo->load();
 				const_cast<CGameInfo*>(CGI)->modh->reload(); //add info about new creatures to dobjinfo
 			};
 

+ 13 - 14
client/CPreGame.cpp

@@ -1856,7 +1856,6 @@ void RandomMapTab::updateMapInfo()
 		player.team = TeamID(i);
 		player.hasMainTown = true;
 		player.generateHeroAtMainTown = true;
-		player.isFactionRandom = true;
 		mapInfo.mapHeader->players.push_back(player);
 	}
 
@@ -2644,7 +2643,7 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
 		{
 		case PlayerSettings::NONE:   return TOWN_NONE;
 		case PlayerSettings::RANDOM: return TOWN_RANDOM;
-		default: return CGI->townh->towns[settings.castle].clientInfo.icons[true][false] + 2;
+		default: return CGI->townh->factions[settings.castle]->town->clientInfo.icons[true][false] + 2;
 		}
 
 	case HERO:
@@ -2669,9 +2668,9 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
 			case PlayerSettings::GOLD:     return GOLD;
 			case PlayerSettings::RESOURCE:
 				{
-					switch(CGI->townh->towns[settings.castle].primaryRes)
+					switch(CGI->townh->factions[settings.castle]->town->primaryRes)
 					{
-					case 127          : return WOOD_ORE;
+					case Res::WOOD_AND_ORE : return WOOD_ORE;
 					case Res::WOOD    : return WOOD;
 					case Res::MERCURY : return MERCURY;
 					case Res::ORE     : return ORE;
@@ -2729,7 +2728,7 @@ std::string OptionsTab::CPlayerSettingsHelper::getName()
 			{
 			case PlayerSettings::NONE   : return CGI->generaltexth->allTexts[523];
 			case PlayerSettings::RANDOM : return CGI->generaltexth->allTexts[522];
-			default : return CGI->townh->factions[settings.castle].name;
+			default : return CGI->townh->factions[settings.castle]->name;
 			}
 		}
 	case HERO:
@@ -2777,13 +2776,13 @@ std::string OptionsTab::CPlayerSettingsHelper::getSubtitle()
 			case PlayerSettings::GOLD:     return CGI->generaltexth->allTexts[87]; //500-1000
 			case PlayerSettings::RESOURCE:
 				{
-					switch(CGI->townh->towns[settings.castle].primaryRes)
+					switch(CGI->townh->factions[settings.castle]->town->primaryRes)
 					{
 					case Res::MERCURY: return CGI->generaltexth->allTexts[694];
 					case Res::SULFUR:  return CGI->generaltexth->allTexts[695];
 					case Res::CRYSTAL: return CGI->generaltexth->allTexts[692];
 					case Res::GEMS:    return CGI->generaltexth->allTexts[693];
-					case 127:          return CGI->generaltexth->allTexts[89]; //At the start of the game, 5-10 wood and 5-10 ore are added to your Kingdom's resource pool
+					case Res::WOOD_AND_ORE: return CGI->generaltexth->allTexts[89]; //At the start of the game, 5-10 wood and 5-10 ore are added to your Kingdom's resource pool
 					}
 				}
 			}
@@ -2807,13 +2806,13 @@ std::string OptionsTab::CPlayerSettingsHelper::getDescription()
 			case PlayerSettings::GOLD:     return CGI->generaltexth->allTexts[92]; //At the start of the game, 500-1000 gold is added to your Kingdom's resource pool
 			case PlayerSettings::RESOURCE:
 				{
-					switch(CGI->townh->towns[settings.castle].primaryRes)
+					switch(CGI->townh->factions[settings.castle]->town->primaryRes)
 					{
 					case Res::MERCURY: return CGI->generaltexth->allTexts[690];
 					case Res::SULFUR:  return CGI->generaltexth->allTexts[691];
 					case Res::CRYSTAL: return CGI->generaltexth->allTexts[688];
 					case Res::GEMS:    return CGI->generaltexth->allTexts[689];
-					case 127:          return CGI->generaltexth->allTexts[93]; //At the start of the game, 5-10 wood and 5-10 ore are added to your Kingdom's resource pool
+					case Res::WOOD_AND_ORE: return CGI->generaltexth->allTexts[93]; //At the start of the game, 5-10 wood and 5-10 ore are added to your Kingdom's resource pool
 					}
 				}
 			}
@@ -2872,10 +2871,10 @@ void OptionsTab::CPregameTooltipBox::genTownWindow()
 	new CLabel(pos.w / 2 + 8, 122, FONT_MEDIUM, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[79]);
 
 	std::vector<CComponent *> components;
-	const CTown & town = CGI->townh->towns[settings.castle];
+	const CTown * town = CGI->townh->factions[settings.castle]->town;
 
-	for (size_t i=0; i< town.creatures.size(); i++)
-		components.push_back(new CComponent(CComponent::creature, town.creatures[i].front(), 0, CComponent::tiny));
+	for (size_t i=0; i< town->creatures.size(); i++)
+		components.push_back(new CComponent(CComponent::creature, town->creatures[i].front(), 0, CComponent::tiny));
 
 	new CComponentBox(components, Rect(10, 140, pos.w - 20, 140));
 }
@@ -3450,8 +3449,8 @@ void CBonusSelection::updateBonusSelection()
 					picName = graphics->ERMUtoPicture[faction][buildID];
 					picNumber = -1;
 
-					if (vstd::contains(CGI->townh->towns[faction].buildings, buildID))
-						desc = CGI->townh->towns[faction].buildings.find(buildID)->second->Name();
+					if (vstd::contains(CGI->townh->factions[faction]->town->buildings, buildID))
+						desc = CGI->townh->factions[faction]->town->buildings.find(buildID)->second->Name();
 				}
 				break;
 			case CScenarioTravel::STravelBonus::ARTIFACT:

+ 12 - 12
client/GUIClasses.cpp

@@ -177,7 +177,7 @@ void CTownTooltip::init(const InfoAboutTown &town)
 
 		if(town.details->customRes)//silo is built
 		{
-			if (town.tType->primaryRes == 127 )// wood & ore
+			if (town.tType->primaryRes == Res::WOOD_AND_ORE )// wood & ore
 			{
 				new CAnimImage("SMALRES", Res::WOOD, 0, 7, 75);
 				new CAnimImage("SMALRES", Res::ORE , 0, 7, 88);
@@ -921,7 +921,7 @@ const std::vector<std::string> CComponent::getFileName()
 	case spell:      return gen(spellsArr);
 	case morale:     return gen(moraleArr);
 	case luck:       return gen(luckArr);
-	case building:   return std::vector<std::string>(4, CGI->townh->towns[subtype].clientInfo.buildingsIcons);
+	case building:   return std::vector<std::string>(4, CGI->townh->factions[subtype]->town->clientInfo.buildingsIcons);
 	case hero:       return gen(heroArr);
 	case flag:       return gen(flagArr);
 	}
@@ -964,7 +964,7 @@ std::string CComponent::getDescription()
 	case spell:      return CGI->spellh->spells[subtype]->descriptions[val];
 	case morale:     return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)];
 	case luck:       return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)];
-	case building:   return CGI->townh->towns[subtype].buildings[BuildingID(val)]->Description();
+	case building:   return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Description();
 	case hero:       return CGI->heroh->heroes[subtype]->name;
 	case flag:       return "";
 	}
@@ -996,7 +996,7 @@ std::string CComponent::getSubtitleInternal()
 	case spell:      return CGI->spellh->spells[subtype]->name;
 	case morale:     return "";
 	case luck:       return "";
-	case building:   return CGI->townh->towns[subtype].buildings[BuildingID(val)]->Name();
+	case building:   return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Name();
 	case hero:       return CGI->heroh->heroes[subtype]->name;
 	case flag:       return CGI->generaltexth->capColors[subtype];
 	}
@@ -1317,12 +1317,12 @@ CCreaturePic::CCreaturePic(int x, int y, const CCreature *cre, bool Big, bool An
 
 	TFaction faction = cre->faction;
 
-	assert(vstd::contains(CGI->townh->factions, cre->faction));
+	assert(CGI->townh->factions.size() > faction);
 
 	if(Big)
-		bg = new CPicture(CGI->townh->factions[faction].creatureBg130);
+		bg = new CPicture(CGI->townh->factions[faction]->creatureBg130);
 	else
-		bg = new CPicture(CGI->townh->factions[faction].creatureBg120);
+		bg = new CPicture(CGI->townh->factions[faction]->creatureBg120);
 	bg->needRefresh = true;
 	anim = new CCreatureAnim(0, 0, cre->animDefName, Rect());
 	anim->clipRect(cre->isDoubleWide()?170:150, 155, bg->pos.w, bg->pos.h);
@@ -2568,14 +2568,14 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstan
 		switch (mode)
 		{
 		break; case EMarketMode::CREATURE_RESOURCE:
-			title = CGI->townh->towns[ETownType::STRONGHOLD].buildings[BuildingID::FREELANCERS_GUILD]->Name();
+			title = CGI->townh->factions[ETownType::STRONGHOLD]->town->buildings[BuildingID::FREELANCERS_GUILD]->Name();
 
 		break; case EMarketMode::RESOURCE_ARTIFACT:
-			title = CGI->townh->towns[market->o->subID].buildings[BuildingID::ARTIFACT_MERCHANT]->Name();
+			title = CGI->townh->factions[market->o->subID]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->Name();
 			sliderNeeded = false;
 
 		break; case EMarketMode::ARTIFACT_RESOURCE:
-			title = CGI->townh->towns[market->o->subID].buildings[BuildingID::ARTIFACT_MERCHANT]->Name();
+			title = CGI->townh->factions[market->o->subID]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->Name();
 			sliderNeeded = false;
 
 		break; default:
@@ -5239,7 +5239,7 @@ CPuzzleWindow::CPuzzleWindow(const int3 &GrailPos, double discoveredRatio):
 
 	int faction = LOCPLINT->cb->getStartInfo()->playerInfos.find(LOCPLINT->playerID)->second.castle;
 
-	auto & puzzleMap = CGI->townh->factions[faction].puzzleMap;
+	auto & puzzleMap = CGI->townh->factions[faction]->puzzleMap;
 
 	for(int g=0; g<puzzleMap.size(); ++g)
 	{
@@ -5468,7 +5468,7 @@ CUniversityWindow::CUniversityWindow(const CGHeroInstance * _hero, const IMarket
 	CIntObject * titlePic = nullptr;
 
 	if (market->o->ID == Obj::TOWN)
-		titlePic = new CAnimImage(CGI->townh->towns[ETownType::CONFLUX].clientInfo.buildingsIcons, BuildingID::MAGIC_UNIVERSITY);
+		titlePic = new CAnimImage(CGI->townh->factions[ETownType::CONFLUX]->town->clientInfo.buildingsIcons, BuildingID::MAGIC_UNIVERSITY);
 	else
 		titlePic = new CPicture("UNIVBLDG");
 

+ 1 - 1
client/NetPacksClient.cpp

@@ -762,7 +762,7 @@ void SystemMessage::applyCl( CClient *cl )
 	std::ostringstream str;
 	str << "System message: " << text;
 
-    logNetwork->debugStream() << str.str();
+    logNetwork->errorStream() << str.str(); // usually used to receive error messages from server
 	if(LOCPLINT)
 		LOCPLINT->cingconsole->print(str.str());
 }

+ 1 - 1
client/battle/CBattleInterface.cpp

@@ -3570,7 +3570,7 @@ std::string CBattleInterface::SiegeHelper::getSiegeName(ui16 what, ui16 additInf
 		return prefix + "BACK.BMP";
 	case 1: //background wall
 		{
-			switch(town->town->typeID)
+			switch(town->town->faction->index)
 			{
 			case 5: case 4: case 1: case 6:
 				return prefix + "TPW1.BMP";

+ 2593 - 2596
config/artifacts.json

@@ -1,2646 +1,2643 @@
 {
-	"artifacts" :
+	"spellBook":
 	{
-		"spellBook":
-		{
-			"id" : 0,
-			"type" : ["HERO"]
-		},
-		"spellScroll":
-		{
-			"id" : 1,
-			"type" : ["HERO"]
-		},
-		"grail":
-		{
-			"id" : 2,
-			"type" : ["HERO"]
-		},
-		"catapult":
-		{
-			"id" : 3,
-			"type" : ["HERO"]
-		},
-		"ballista":
-		{
-			"id" : 4,
-			"type" : ["HERO"]
-		},
-		"ammoCart":
-		{
-			"id" : 5,
-			"type" : ["HERO"]
-		},
-		"firstAidTent":
-		{
-			"id" : 6,
-			"type" : ["HERO"]
-		},
-		"centaurAxe":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 7,
-			"type" : ["HERO"]
-		},
-		"blackshardOfTheDeadKnight":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 8,
-			"type" : ["HERO"]
-		},
-		"greaterGnollsFlail":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 9,
-			"type" : ["HERO"]
-		},
-		"ogresClubOfHavoc":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 5,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 10,
-			"type" : ["HERO"]
-		},
-		"swordOfHellfire":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 11,
-			"type" : ["HERO"]
-		},
-		"titansGladius":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 12,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : -3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 12,
-			"type" : ["HERO"]
-		},
-		"shieldOfTheDwarvenLords":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 13,
-			"type" : ["HERO"]
-		},
-		"shieldOfTheYawningDead":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 14,
-			"type" : ["HERO"]
-		},
-		"bucklerOfTheGnollKing":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 15,
-			"type" : ["HERO"]
-		},
-		"targOfTheRampagingOgre":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 5,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 16,
-			"type" : ["HERO"]
-		},
-		"shieldOfTheDamned":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 17,
-			"type" : ["HERO"]
-		},
-		"sentinelsShield":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 12,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : 0,
-					"type" : "PRIMARY_SKILL",
-					"val" : -3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 18,
-			"type" : ["HERO"]
-		},
-		"helmOfTheAlabasterUnicorn":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 19,
-			"type" : ["HERO"]
-		},
-		"skullHelmet":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 20,
-			"type" : ["HERO"]
-		},
-		"helmOfChaos":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 21,
-			"type" : ["HERO"]
-		},
-		"crownOfTheSupremeMagi":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 22,
-			"type" : ["HERO"]
-		},
-		"hellstormHelmet":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 5,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 23,
-			"type" : ["HERO"]
-		},
-		"thunderHelmet":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 10,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : -2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 24,
-			"type" : ["HERO"]
-		},
-		"breastplateOfPetrifiedWood":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 25,
-			"type" : ["HERO"]
-		},
-		"ribCage":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 26,
-			"type" : ["HERO"]
-		},
-		"scalesOfTheGreaterBasilisk":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 27,
-			"type" : ["HERO"]
-		},
-		"tunicOfTheCyclopsKing":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 28,
-			"type" : ["HERO"]
-		},
-		"breastplateOfBrimstone":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 5,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 29,
-			"type" : ["HERO"]
-		},
-		"titansCuirass":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 10,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : -2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 30,
-			"type" : ["HERO"]
-		},
-		"armorOfWonder":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 31,
-			"type" : ["HERO"]
-		},
-		"sandalsOfTheSaint":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 32,
-			"type" : ["HERO"]
-		},
-		"celestialNecklaceOfBliss":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 33,
-			"type" : ["HERO"]
-		},
-		"lionsShieldOfCourage":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 34,
-			"type" : ["HERO"]
-		},
-		"swordOfJudgement":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 5,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 5,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 5,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 5,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 35,
-			"type" : ["HERO"]
-		},
-		"helmOfHeavenlyEnlightenment":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 36,
-			"type" : ["HERO"]
-		},
-		"quietEyeOfTheDragon":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 37,
-			"type" : ["HERO"]
-		},
-		"redDragonFlameTongue":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 38,
-			"type" : ["HERO"]
-		},
-		"dragonScaleShield":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 39,
-			"type" : ["HERO"]
-		},
-		"dragonScaleArmor":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 40,
-			"type" : ["HERO"]
-		},
-		"dragonboneGreaves":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 41,
-			"type" : ["HERO"]
-		},
-		"dragonWingTabard":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 42,
-			"type" : ["HERO"]
-		},
-		"necklaceOfDragonteeth":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 43,
-			"type" : ["HERO"]
-		},
-		"crownOfDragontooth":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 44,
-			"type" : ["HERO"]
-		},
-		"stillEyeOfTheDragon":
-		{
-			"bonuses" : [
-				{
-					"type" : "MORALE",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "LUCK",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 45,
-			"type" : ["HERO"]
-		},
-		"cloverOfFortune":
-		{
-			"bonuses" : [
-				{
-					"type" : "LUCK",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 46,
-			"type" : ["HERO"]
-		},
-		"cardsOfProphecy":
-		{
-			"bonuses" : [
-				{
-					"type" : "LUCK",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 47,
-			"type" : ["HERO"]
-		},
-		"ladybirdOfLuck":
-		{
-			"bonuses" : [
-				{
-					"type" : "LUCK",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 48,
-			"type" : ["HERO"]
-		},
-		"badgeOfCourage":
-		{
-			"bonuses" : [
-				{
-					"type" : "MORALE",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "MIND_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 49,
-			"type" : ["HERO"]
-		},
-		"crestOfValor":
-		{
-			"bonuses" : [
-				{
-					"type" : "MORALE",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 50,
-			"type" : ["HERO"]
-		},
-		"glyphOfGallantry":
-		{
-			"bonuses" : [
-				{
-					"type" : "MORALE",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 51,
-			"type" : ["HERO"]
-		},
-		"speculum":
-		{
-			"bonuses" : [
-				{
-					"type" : "SIGHT_RADIOUS",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 52,
-			"type" : ["HERO"]
-		},
-		"spyglass":
-		{
-			"bonuses" : [
-				{
-					"type" : "SIGHT_RADIOUS",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 53,
-			"type" : ["HERO"]
-		},
-		"amuletOfTheUndertaker":
-		{
-			"bonuses" : [
-				{
-					"subtype" : 12,
-					"type" : "SECONDARY_SKILL_PREMY",
-					"val" : 5,
-					"valueType" : "ADDITIVE_VALUE"
-				}
-			],
-			"id" : 54,
-			"type" : ["HERO"]
-		},
-		"vampiresCowl":
-		{
-			"bonuses" : [
-				{
-					"subtype" : 12,
-					"type" : "SECONDARY_SKILL_PREMY",
-					"val" : 10,
-					"valueType" : "ADDITIVE_VALUE"
-				}
-			],
-			"id" : 55,
-			"type" : ["HERO"]
-		},
-		"deadMansBoots":
-		{
-			"bonuses" : [
-				{
-					"subtype" : 12,
-					"type" : "SECONDARY_SKILL_PREMY",
-					"val" : 15,
-					"valueType" : "ADDITIVE_VALUE"
-				}
-			],
-			"id" : 56,
-			"type" : ["HERO"]
-		},
-		"garnitureOfInterference":
-		{
-			"bonuses" : [
-				{
-					"subtype" : 0,
-					"type" : "MAGIC_RESISTANCE",
-					"val" : 5,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 57,
-			"type" : ["HERO"]
-		},
-		"surcoatOfCounterpoise":
-		{
-			"bonuses" : [
-				{
-					"subtype" : 0,
-					"type" : "MAGIC_RESISTANCE",
-					"val" : 10,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 58,
-			"type" : ["HERO"]
-		},
-		"bootsOfPolarity":
-		{
-			"bonuses" : [
-				{
-					"subtype" : 0,
-					"type" : "MAGIC_RESISTANCE",
-					"val" : 15,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 59,
-			"type" : ["HERO"]
-		},
-		"bowOfElvenCherrywood":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "skill.archery",
-					"type" : "SECONDARY_SKILL_PREMY",
-					"val" : 5,
-					"valueType" : "ADDITIVE_VALUE"
-				}
-			],
-			"id" : 60,
-			"type" : ["HERO"]
-		},
-		"bowstringOfTheUnicornsMane":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "skill.archery",
-					"type" : "SECONDARY_SKILL_PREMY",
-					"val" : 10,
-					"valueType" : "ADDITIVE_VALUE"
-				}
-			],
-			"id" : 61,
-			"type" : ["HERO"]
-		},
-		"angelFeatherArrows":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "skill.archery",
-					"type" : "SECONDARY_SKILL_PREMY",
-					"val" : 15,
-					"valueType" : "ADDITIVE_VALUE"
-				}
-			],
-			"id" : 62,
-			"type" : ["HERO"]
-		},
-		"birdOfPerception":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "skill.eagleEye",
-					"type" : "SECONDARY_SKILL_PREMY",
-					"val" : 5,
-					"valueType" : "ADDITIVE_VALUE"
-				}
-			],
-			"id" : 63,
-			"type" : ["HERO"]
-		},
-		"stoicWatchman":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "skill.eagleEye",
-					"type" : "SECONDARY_SKILL_PREMY",
-					"val" : 10,
-					"valueType" : "ADDITIVE_VALUE"
-				}
-			],
-			"id" : 64,
-			"type" : ["HERO"]
-		},
-		"emblemOfCognizance":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "skill.eagleEye",
-					"type" : "SECONDARY_SKILL_PREMY",
-					"val" : 15,
-					"valueType" : "ADDITIVE_VALUE"
-				}
-			],
-			"id" : 65,
-			"type" : ["HERO"]
-		},
-		"statesmansMedal":
-		{
-			"bonuses" : [
-				{
-					"type" : "SURRENDER_DISCOUNT",
-					"val" : 10,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 66,
-			"type" : ["HERO"]
-		},
-		"diplomatsRing":
-		{
-			"bonuses" : [
-				{
-					"type" : "SURRENDER_DISCOUNT",
-					"val" : 10,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 67,
-			"type" : ["HERO"]
-		},
-		"ambassadorsSash":
-		{
-			"bonuses" : [
-				{
-					"type" : "SURRENDER_DISCOUNT",
-					"val" : 10,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 68,
-			"type" : ["HERO"]
-		},
-		"ringOfTheWayfarer":
-		{
-			"bonuses" : [
-				{
-					"type" : "STACKS_SPEED",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 69,
-			"type" : ["HERO"]
-		},
-		"equestriansGloves":
-		{
-			"bonuses" : [
-				{
-					"type" : "LAND_MOVEMENT",
-					"val" : 300,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 70,
-			"type" : ["HERO"]
-		},
-		"necklaceOfOceanGuidance":
-		{
-			"bonuses" : [
-				{
-					"type" : "SEA_MOVEMENT",
-					"val" : 1000,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 71,
-			"type" : ["HERO"]
-		},
-		"angelWings":
-		{
-			"bonuses" : [
-				{
-					"subtype" : 1,
-					"type" : "FLYING_MOVEMENT",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 72,
-			"type" : ["HERO"]
-		},
-		"charmOfMana":
-		{
-			"bonuses" : [
-				{
-					"type" : "MANA_REGENERATION",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 73,
-			"type" : ["HERO"]
-		},
-		"talismanOfMana":
-		{
-			"bonuses" : [
-				{
-					"type" : "MANA_REGENERATION",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 74,
-			"type" : ["HERO"]
-		},
-		"mysticOrbOfMana":
-		{
-			"bonuses" : [
-				{
-					"type" : "MANA_REGENERATION",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 75,
-			"type" : ["HERO"]
-		},
-		"collarOfConjuring":
-		{
-			"bonuses" : [
-				{
-					"type" : "SPELL_DURATION",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 76,
-			"type" : ["HERO"]
-		},
-		"ringOfConjuring":
-		{
-			"bonuses" : [
-				{
-					"type" : "SPELL_DURATION",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 77,
-			"type" : ["HERO"]
-		},
-		"capeOfConjuring":
-		{
-			"bonuses" : [
-				{
-					"type" : "SPELL_DURATION",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 78,
-			"type" : ["HERO"]
-		},
-		"orbOfTheFirmament":
-		{
-			"bonuses" : [
-				{
-					"type" : "AIR_SPELL_DMG_PREMY",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 79,
-			"type" : ["HERO"]
-		},
-		"orbOfSilt":
-		{
-			"bonuses" : [
-				{
-					"type" : "EARTH_SPELL_DMG_PREMY",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 80,
-			"type" : ["HERO"]
-		},
-		"orbOfTempestuousFire":
-		{
-			"bonuses" : [
-				{
-					"type" : "FIRE_SPELL_DMG_PREMY",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 81,
-			"type" : ["HERO"]
-		},
-		"orbOfDrivingRain":
-		{
-			"bonuses" : [
-				{
-					"type" : "WATER_SPELL_DMG_PREMY",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 82,
-			"type" : ["HERO"]
-		},
-		"recantersCloak":
-		{
-			"id" : 83,
-			"type" : ["HERO"],
-			"bonuses": [
-				{
-					"type" : "BLOCK_MAGIC_ABOVE",
-					"val" : 2,
-					"valueType" : "INDEPENDENT_MIN",
-					"propagator": "BATTLE_WIDE"
-				}
-			]
-		},
-		"spiritOfOppression":
-		{
-			"bonuses" : [
-				{
-					"type" : "BLOCK_MORALE",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 84,
-			"type" : ["HERO"]
-		},
-		"hourglassOfTheEvilHour":
-		{
-			"bonuses" : [
-				{
-					"type" : "BLOCK_LUCK",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 85,
-			"type" : ["HERO"]
-		},
-		"tomeOfFireMagic":
-		{
-			"bonuses" : [
-				{
-					"type" : "FIRE_SPELLS",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 86,
-			"type" : ["HERO"]
-		},
-		"tomeOfAirMagic":
-		{
-			"bonuses" : [
-				{
-					"type" : "AIR_SPELLS",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 87,
-			"type" : ["HERO"]
-		},
-		"tomeOfWaterMagic":
-		{
-			"bonuses" : [
-				{
-					"type" : "WATER_SPELLS",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 88,
-			"type" : ["HERO"]
-		},
-		"tomeOfEarthMagic":
-		{
-			"bonuses" : [
-				{
-					"type" : "EARTH_SPELLS",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 89,
-			"type" : ["HERO"]
-		},
-		"bootsOfLevitation":
-		{
-			"bonuses" : [
-				{
-					"subtype" : 1,
-					"type" : "WATER_WALKING",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 90,
-			"type" : ["HERO"]
-		},
-		"goldenBow":
-		{
-			"bonuses" : [
-				{
-					"limiters" : ["SHOOTER_ONLY"],
-					"subtype" : 0,
-					"type" : "NO_DISTANCE_PENALTY",
-					"val" : 0,
-					"valueType" : "ADDITIVE_VALUE"
-				},
-				{
-					"limiters" : ["SHOOTER_ONLY"],
-					"subtype" : 0,
-					"type" : "NO_WALL_PENALTY",
-					"val" : 0,
-					"valueType" : "ADDITIVE_VALUE"
-				}
-			],
-			"id" : 91,
-			"type" : ["HERO"]
-		},
-		"sphereOfPermanence":
-		{
-			"bonuses" : [
-				{
-					"subtype" : 35,
-					"type" : "SPELL_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 92,
-			"type" : ["HERO"]
-		},
-		"orbOfVulnerability":
-		{
-			"bonuses" : [
-				{
-					"type" : "NEGATE_ALL_NATURAL_IMMUNITIES",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 93,
-			"type" : ["HERO"]
-		},
-		"ringOfVitality":
-		{
-			"bonuses" : [
-				{
-					"type" : "STACK_HEALTH",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 94,
-			"type" : ["HERO"]
-		},
-		"ringOfLife":
-		{
-			"bonuses" : [
-				{
-					"type" : "STACK_HEALTH",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 95,
-			"type" : ["HERO"]
-		},
-		"vialOfLifeblood":
-		{
-			"bonuses" : [
-				{
-					"type" : "STACK_HEALTH",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 96,
-			"type" : ["HERO"]
-		},
-		"necklaceOfSwiftness":
-		{
-			"bonuses" : [
-				{
-					"type" : "STACKS_SPEED",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 97,
-			"type" : ["HERO"]
-		},
-		"bootsOfSpeed":
-		{
-			"bonuses" : [
-				{
-					"type" : "LAND_MOVEMENT",
-					"val" : 600,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 98,
-			"type" : ["HERO"]
-		},
-		"capeOfVelocity":
-		{
-			"bonuses" : [
-				{
-					"type" : "STACKS_SPEED",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 99,
-			"type" : ["HERO"]
-		},
-		"pendantOfDispassion":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "spell.berserk",
-					"type" : "SPELL_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 100,
-			"type" : ["HERO"]
-		},
-		"pendantOfSecondSight":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "spell.blind",
-					"type" : "SPELL_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 101,
-			"type" : ["HERO"]
-		},
-		"pendantOfHoliness":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "spell.curse",
-					"type" : "SPELL_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 102,
-			"type" : ["HERO"]
-		},
-		"pendantOfLife":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "spell.deathRipple",
-					"type" : "SPELL_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 103,
-			"type" : ["HERO"]
-		},
-		"pendantOfDeath":
-		{
-			"bonuses" : [
-				{
-					"limiters" : ["IS_UNDEAD"],
-					"subtype" : "spell.destroyUndead",
-					"type" : "SPELL_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 104,
-			"type" : ["HERO"]
-		},
-		"pendantOfFreeWill":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "spell.hypnotize",
-					"type" : "SPELL_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 105,
-			"type" : ["HERO"]
-		},
-		"pendantOfNegativity":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "spell.lightningBolt",
-					"type" : "SPELL_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "spell.chainLightning",
-					"type" : "SPELL_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 106,
-			"type" : ["HERO"]
-		},
-		"pendantOfTotalRecall":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "spell.forgetfulness",
-					"type" : "SPELL_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 107,
-			"type" : ["HERO"]
-		},
-		"pendantOfCourage":
-		{
-			"bonuses" : [
-				{
-					"type" : "MORALE",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "LUCK",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 108,
-			"type" : ["HERO"]
-		},
-		"everflowingCrystalCloak":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "resource.crystal",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 109,
-			"type" : ["HERO"]
-		},
-		"ringOfInfiniteGems":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "resource.gems",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 110,
-			"type" : ["HERO"]
-		},
-		"everpouringVialOfMercury":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "resource.mercury",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 111,
-			"type" : ["HERO"]
-		},
-		"inexhaustibleCartOfOre":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "resource.ore",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 112,
-			"type" : ["HERO"]
-		},
-		"eversmokingRingOfSulfur":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "resource.sulfur",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 113,
-			"type" : ["HERO"]
-		},
-		"inexhaustibleCartOfLumber":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "resource.wood",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 114,
-			"type" : ["HERO"]
-		},
-		"endlessSackOfGold":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "resource.gold",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 1000,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 115,
-			"type" : ["HERO"]
-		},
-		"endlessBagOfGold":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "resource.gold",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 750,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 116,
-			"type" : ["HERO"]
-		},
-		"endlessPurseOfGold":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "resource.gold",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 500,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 117,
-			"type" : ["HERO"]
-		},
-		"legsOfLegion":
-		{
-			"id" : 118,
-			"type" : ["HERO"],
-			"bonuses" : [
-				{
-					"type" : "CREATURE_GROWTH",
-					"subtype" : 2,
-					"val" : 5,
-					"propagator": "VISITED_TOWN_AND_VISITOR"
-				}
-			]
-		},
-		"loinsOfLegion":
-		{
-			"id" : 119,
-			"type" : ["HERO"],
-			"bonuses" : [
-				{
-					"type" : "CREATURE_GROWTH",
-					"subtype" : 3,
-					"val" : 4,
-					"propagator": "VISITED_TOWN_AND_VISITOR"
-				}
-			]
-		},
-		"torsoOfLegion":
-		{
-			"id" : 120,
-			"type" : ["HERO"],
-			"bonuses" : [
-				{
-					"type" : "CREATURE_GROWTH",
-					"subtype" : 4,
-					"val" : 3,
-					"propagator": "VISITED_TOWN_AND_VISITOR"
-				}
-			]
-		},
-		"armsOfLegion":
-		{
-			"id" : 121,
-			"type" : ["HERO"],
-			"bonuses" : [
-				{
-					"type" : "CREATURE_GROWTH",
-					"subtype" : 5,
-					"val" : 2,
-					"propagator": "VISITED_TOWN_AND_VISITOR"
-				}
-			]
-		},
-		"headOfLegion":
-		{
-			"id" : 122,
-			"type" : ["HERO"],
-			"bonuses" : [
-				{
-					"type" : "CREATURE_GROWTH",
-					"subtype" : 6,
-					"val" : 1,
-					"propagator": "VISITED_TOWN_AND_VISITOR"
-				}
-			]
-		},
-		"seaCaptainsHat":
-		{
-			"bonuses" : [
-				{
-					"type" : "WHIRLPOOL_PROTECTION",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "SEA_MOVEMENT",
-					"val" : 500,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "spell.summonBoat",
-					"type" : "SPELL",
-					"val" : 3,
-					"valueType" : "INDEPENDENT_MAX"
-				},
-				{
-					"subtype" : "spell.scuttleBoat",
-					"type" : "SPELL",
-					"val" : 3,
-					"valueType" : "INDEPENDENT_MAX"
-				}
-			],
-			"id" : 123,
-			"type" : ["HERO"]
-		},
-		"spellbindersHat":
-		{
-			"bonuses" : [
-				{
-					"subtype" : 5,
-					"type" : "SPELLS_OF_LEVEL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 124,
-			"type" : ["HERO"]
-		},
-		"shacklesOfWar":
-		{
-			"id" : 125,
-			"type" : ["HERO"],
-			"bonuses" : [
-				{
-					"type" : "BATTLE_NO_FLEEING",
-					"propagator": "BATTLE_WIDE"
-				}
-			]
-		},
-		"orbOfInhibition":
-		{
-			"id" : 126,
-			"type" : ["HERO"],
-			"bonuses" : [
-				{
-					"type" : "BLOCK_ALL_MAGIC",
-					"propagator": "BATTLE_WIDE"
-				}
-			]
-		},
-		"vialOfDragonBlood":
-		{
-			"bonuses" : [
-				{
-					"limiters" : ["DRAGON_NATURE"],
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 5,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"limiters" : ["DRAGON_NATURE"],
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 5,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 127,
-			"type" : ["HERO"]
-		},
-		"armageddonsBlade":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "spell.armageddon",
-					"type" : "SPELL",
-					"val" : 3,
-					"valueType" : "INDEPENDENT_MAX"
-				},
-				{
-					"subtype" : "spell.armageddon",
-					"type" : "SPELL_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 128,
-			"type" : ["HERO"]
-		},
-		"angelicAlliance":
-		{
-			"bonuses" : [
-				{
-					"type" : "NONEVIL_ALIGNMENT_MIX",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "spell.prayer",
-					"type" : "OPENING_BATTLE_SPELL",
-					"val" : 10,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 129,
-			"type" : ["HERO"],
-			"components":
-			[
-				"armorOfWonder",
-				"sandalsOfTheSaint",
-				"celestialNecklaceOfBliss",
-				"lionsShieldOfCourage",
-				"swordOfJudgement",
-				"helmOfHeavenlyEnlightenment"
-			]
-		},
-		"cloakOfTheUndeadKing":
-		{
-			"bonuses" : [
-				{
-					"type" : "IMPROVED_NECROMANCY", //TODO: more flexible?
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 130,
-			"type" : ["HERO"],
-			"components":
-			[
-				"amuletOfTheUndertaker",
-				"vampiresCowl",
-				"deadMansBoots"
-			]
-		},
-		"elixirOfLife":
+		"index" : 0,
+		"type" : ["HERO"]
+	},
+	"spellScroll":
+	{
+		"index" : 1,
+		"type" : ["HERO"]
+	},
+	"grail":
+	{
+		"index" : 2,
+		"type" : ["HERO"]
+	},
+	"catapult":
+	{
+		"index" : 3,
+		"type" : ["HERO"]
+	},
+	"ballista":
+	{
+		"index" : 4,
+		"type" : ["HERO"]
+	},
+	"ammoCart":
+	{
+		"index" : 5,
+		"type" : ["HERO"]
+	},
+	"firstAidTent":
+	{
+		"index" : 6,
+		"type" : ["HERO"]
+	},
+	"centaurAxe":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 7,
+		"type" : ["HERO"]
+	},
+	"blackshardOfTheDeadKnight":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 8,
+		"type" : ["HERO"]
+	},
+	"greaterGnollsFlail":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 9,
+		"type" : ["HERO"]
+	},
+	"ogresClubOfHavoc":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 5,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 10,
+		"type" : ["HERO"]
+	},
+	"swordOfHellfire":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 6,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 11,
+		"type" : ["HERO"]
+	},
+	"titansGladius":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 12,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : -3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 12,
+		"type" : ["HERO"]
+	},
+	"shieldOfTheDwarvenLords":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 13,
+		"type" : ["HERO"]
+	},
+	"shieldOfTheYawningDead":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 14,
+		"type" : ["HERO"]
+	},
+	"bucklerOfTheGnollKing":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 15,
+		"type" : ["HERO"]
+	},
+	"targOfTheRampagingOgre":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 5,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 16,
+		"type" : ["HERO"]
+	},
+	"shieldOfTheDamned":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 6,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 17,
+		"type" : ["HERO"]
+	},
+	"sentinelsShield":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 12,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : 0,
+				"type" : "PRIMARY_SKILL",
+				"val" : -3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 18,
+		"type" : ["HERO"]
+	},
+	"helmOfTheAlabasterUnicorn":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 19,
+		"type" : ["HERO"]
+	},
+	"skullHelmet":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 20,
+		"type" : ["HERO"]
+	},
+	"helmOfChaos":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 21,
+		"type" : ["HERO"]
+	},
+	"crownOfTheSupremeMagi":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 22,
+		"type" : ["HERO"]
+	},
+	"hellstormHelmet":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 5,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 23,
+		"type" : ["HERO"]
+	},
+	"thunderHelmet":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 10,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : -2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 24,
+		"type" : ["HERO"]
+	},
+	"breastplateOfPetrifiedWood":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 25,
+		"type" : ["HERO"]
+	},
+	"ribCage":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 26,
+		"type" : ["HERO"]
+	},
+	"scalesOfTheGreaterBasilisk":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 27,
+		"type" : ["HERO"]
+	},
+	"tunicOfTheCyclopsKing":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 28,
+		"type" : ["HERO"]
+	},
+	"breastplateOfBrimstone":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 5,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 29,
+		"type" : ["HERO"]
+	},
+	"titansCuirass":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 10,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : -2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 30,
+		"type" : ["HERO"]
+	},
+	"armorOfWonder":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 31,
+		"type" : ["HERO"]
+	},
+	"sandalsOfTheSaint":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 32,
+		"type" : ["HERO"]
+	},
+	"celestialNecklaceOfBliss":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 33,
+		"type" : ["HERO"]
+	},
+	"lionsShieldOfCourage":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 34,
+		"type" : ["HERO"]
+	},
+	"swordOfJudgement":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 5,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 5,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 5,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 5,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 35,
+		"type" : ["HERO"]
+	},
+	"helmOfHeavenlyEnlightenment":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 6,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 6,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 6,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 6,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 36,
+		"type" : ["HERO"]
+	},
+	"quietEyeOfTheDragon":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 37,
+		"type" : ["HERO"]
+	},
+	"redDragonFlameTongue":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 38,
+		"type" : ["HERO"]
+	},
+	"dragonScaleShield":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 39,
+		"type" : ["HERO"]
+	},
+	"dragonScaleArmor":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 40,
+		"type" : ["HERO"]
+	},
+	"dragonboneGreaves":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 41,
+		"type" : ["HERO"]
+	},
+	"dragonWingTabard":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 42,
+		"type" : ["HERO"]
+	},
+	"necklaceOfDragonteeth":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 43,
+		"type" : ["HERO"]
+	},
+	"crownOfDragontooth":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 44,
+		"type" : ["HERO"]
+	},
+	"stillEyeOfTheDragon":
+	{
+		"bonuses" : [
+			{
+				"type" : "MORALE",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "LUCK",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 45,
+		"type" : ["HERO"]
+	},
+	"cloverOfFortune":
+	{
+		"bonuses" : [
+			{
+				"type" : "LUCK",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 46,
+		"type" : ["HERO"]
+	},
+	"cardsOfProphecy":
+	{
+		"bonuses" : [
+			{
+				"type" : "LUCK",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 47,
+		"type" : ["HERO"]
+	},
+	"ladybirdOfLuck":
+	{
+		"bonuses" : [
+			{
+				"type" : "LUCK",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 48,
+		"type" : ["HERO"]
+	},
+	"badgeOfCourage":
+	{
+		"bonuses" : [
+			{
+				"type" : "MORALE",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "MIND_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 49,
+		"type" : ["HERO"]
+	},
+	"crestOfValor":
+	{
+		"bonuses" : [
+			{
+				"type" : "MORALE",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 50,
+		"type" : ["HERO"]
+	},
+	"glyphOfGallantry":
+	{
+		"bonuses" : [
+			{
+				"type" : "MORALE",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 51,
+		"type" : ["HERO"]
+	},
+	"speculum":
+	{
+		"bonuses" : [
+			{
+				"type" : "SIGHT_RADIOUS",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 52,
+		"type" : ["HERO"]
+	},
+	"spyglass":
+	{
+		"bonuses" : [
+			{
+				"type" : "SIGHT_RADIOUS",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 53,
+		"type" : ["HERO"]
+	},
+	"amuletOfTheUndertaker":
+	{
+		"bonuses" : [
+			{
+				"subtype" : 12,
+				"type" : "SECONDARY_SKILL_PREMY",
+				"val" : 5,
+				"valueType" : "ADDITIVE_VALUE"
+			}
+		],
+		"index" : 54,
+		"type" : ["HERO"]
+	},
+	"vampiresCowl":
+	{
+		"bonuses" : [
+			{
+				"subtype" : 12,
+				"type" : "SECONDARY_SKILL_PREMY",
+				"val" : 10,
+				"valueType" : "ADDITIVE_VALUE"
+			}
+		],
+		"index" : 55,
+		"type" : ["HERO"]
+	},
+	"deadMansBoots":
+	{
+		"bonuses" : [
+			{
+				"subtype" : 12,
+				"type" : "SECONDARY_SKILL_PREMY",
+				"val" : 15,
+				"valueType" : "ADDITIVE_VALUE"
+			}
+		],
+		"index" : 56,
+		"type" : ["HERO"]
+	},
+	"garnitureOfInterference":
+	{
+		"bonuses" : [
+			{
+				"subtype" : 0,
+				"type" : "MAGIC_RESISTANCE",
+				"val" : 5,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 57,
+		"type" : ["HERO"]
+	},
+	"surcoatOfCounterpoise":
+	{
+		"bonuses" : [
+			{
+				"subtype" : 0,
+				"type" : "MAGIC_RESISTANCE",
+				"val" : 10,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 58,
+		"type" : ["HERO"]
+	},
+	"bootsOfPolarity":
+	{
+		"bonuses" : [
+			{
+				"subtype" : 0,
+				"type" : "MAGIC_RESISTANCE",
+				"val" : 15,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 59,
+		"type" : ["HERO"]
+	},
+	"bowOfElvenCherrywood":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "skill.archery",
+				"type" : "SECONDARY_SKILL_PREMY",
+				"val" : 5,
+				"valueType" : "ADDITIVE_VALUE"
+			}
+		],
+		"index" : 60,
+		"type" : ["HERO"]
+	},
+	"bowstringOfTheUnicornsMane":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "skill.archery",
+				"type" : "SECONDARY_SKILL_PREMY",
+				"val" : 10,
+				"valueType" : "ADDITIVE_VALUE"
+			}
+		],
+		"index" : 61,
+		"type" : ["HERO"]
+	},
+	"angelFeatherArrows":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "skill.archery",
+				"type" : "SECONDARY_SKILL_PREMY",
+				"val" : 15,
+				"valueType" : "ADDITIVE_VALUE"
+			}
+		],
+		"index" : 62,
+		"type" : ["HERO"]
+	},
+	"birdOfPerception":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "skill.eagleEye",
+				"type" : "SECONDARY_SKILL_PREMY",
+				"val" : 5,
+				"valueType" : "ADDITIVE_VALUE"
+			}
+		],
+		"index" : 63,
+		"type" : ["HERO"]
+	},
+	"stoicWatchman":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "skill.eagleEye",
+				"type" : "SECONDARY_SKILL_PREMY",
+				"val" : 10,
+				"valueType" : "ADDITIVE_VALUE"
+			}
+		],
+		"index" : 64,
+		"type" : ["HERO"]
+	},
+	"emblemOfCognizance":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "skill.eagleEye",
+				"type" : "SECONDARY_SKILL_PREMY",
+				"val" : 15,
+				"valueType" : "ADDITIVE_VALUE"
+			}
+		],
+		"index" : 65,
+		"type" : ["HERO"]
+	},
+	"statesmansMedal":
+	{
+		"bonuses" : [
+			{
+				"type" : "SURRENDER_DISCOUNT",
+				"val" : 10,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 66,
+		"type" : ["HERO"]
+	},
+	"diplomatsRing":
+	{
+		"bonuses" : [
+			{
+				"type" : "SURRENDER_DISCOUNT",
+				"val" : 10,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 67,
+		"type" : ["HERO"]
+	},
+	"ambassadorsSash":
+	{
+		"bonuses" : [
+			{
+				"type" : "SURRENDER_DISCOUNT",
+				"val" : 10,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 68,
+		"type" : ["HERO"]
+	},
+	"ringOfTheWayfarer":
+	{
+		"bonuses" : [
+			{
+				"type" : "STACKS_SPEED",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 69,
+		"type" : ["HERO"]
+	},
+	"equestriansGloves":
+	{
+		"bonuses" : [
+			{
+				"type" : "LAND_MOVEMENT",
+				"val" : 300,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 70,
+		"type" : ["HERO"]
+	},
+	"necklaceOfOceanGuidance":
+	{
+		"bonuses" : [
+			{
+				"type" : "SEA_MOVEMENT",
+				"val" : 1000,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 71,
+		"type" : ["HERO"]
+	},
+	"angelWings":
+	{
+		"bonuses" : [
+			{
+				"subtype" : 1,
+				"type" : "FLYING_MOVEMENT",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 72,
+		"type" : ["HERO"]
+	},
+	"charmOfMana":
+	{
+		"bonuses" : [
+			{
+				"type" : "MANA_REGENERATION",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 73,
+		"type" : ["HERO"]
+	},
+	"talismanOfMana":
+	{
+		"bonuses" : [
+			{
+				"type" : "MANA_REGENERATION",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 74,
+		"type" : ["HERO"]
+	},
+	"mysticOrbOfMana":
+	{
+		"bonuses" : [
+			{
+				"type" : "MANA_REGENERATION",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 75,
+		"type" : ["HERO"]
+	},
+	"collarOfConjuring":
+	{
+		"bonuses" : [
+			{
+				"type" : "SPELL_DURATION",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 76,
+		"type" : ["HERO"]
+	},
+	"ringOfConjuring":
+	{
+		"bonuses" : [
+			{
+				"type" : "SPELL_DURATION",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 77,
+		"type" : ["HERO"]
+	},
+	"capeOfConjuring":
+	{
+		"bonuses" : [
+			{
+				"type" : "SPELL_DURATION",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 78,
+		"type" : ["HERO"]
+	},
+	"orbOfTheFirmament":
+	{
+		"bonuses" : [
+			{
+				"type" : "AIR_SPELL_DMG_PREMY",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 79,
+		"type" : ["HERO"]
+	},
+	"orbOfSilt":
+	{
+		"bonuses" : [
+			{
+				"type" : "EARTH_SPELL_DMG_PREMY",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 80,
+		"type" : ["HERO"]
+	},
+	"orbOfTempestuousFire":
+	{
+		"bonuses" : [
+			{
+				"type" : "FIRE_SPELL_DMG_PREMY",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 81,
+		"type" : ["HERO"]
+	},
+	"orbOfDrivingRain":
+	{
+		"bonuses" : [
+			{
+				"type" : "WATER_SPELL_DMG_PREMY",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 82,
+		"type" : ["HERO"]
+	},
+	"recantersCloak":
+	{
+		"index" : 83,
+		"type" : ["HERO"],
+		"bonuses": [
+			{
+				"type" : "BLOCK_MAGIC_ABOVE",
+				"val" : 2,
+				"valueType" : "INDEPENDENT_MIN",
+				"propagator": "BATTLE_WIDE"
+			}
+		]
+	},
+	"spiritOfOppression":
+	{
+		"bonuses" : [
+			{
+				"type" : "BLOCK_MORALE",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 84,
+		"type" : ["HERO"]
+	},
+	"hourglassOfTheEvilHour":
+	{
+		"bonuses" : [
+			{
+				"type" : "BLOCK_LUCK",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 85,
+		"type" : ["HERO"]
+	},
+	"tomeOfFireMagic":
+	{
+		"bonuses" : [
+			{
+				"type" : "FIRE_SPELLS",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 86,
+		"type" : ["HERO"]
+	},
+	"tomeOfAirMagic":
+	{
+		"bonuses" : [
+			{
+				"type" : "AIR_SPELLS",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 87,
+		"type" : ["HERO"]
+	},
+	"tomeOfWaterMagic":
+	{
+		"bonuses" : [
+			{
+				"type" : "WATER_SPELLS",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 88,
+		"type" : ["HERO"]
+	},
+	"tomeOfEarthMagic":
+	{
+		"bonuses" : [
+			{
+				"type" : "EARTH_SPELLS",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 89,
+		"type" : ["HERO"]
+	},
+	"bootsOfLevitation":
+	{
+		"bonuses" : [
+			{
+				"subtype" : 1,
+				"type" : "WATER_WALKING",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 90,
+		"type" : ["HERO"]
+	},
+	"goldenBow":
+	{
+		"bonuses" : [
+			{
+				"limiters" : ["SHOOTER_ONLY"],
+				"subtype" : 0,
+				"type" : "NO_DISTANCE_PENALTY",
+				"val" : 0,
+				"valueType" : "ADDITIVE_VALUE"
+			},
+			{
+				"limiters" : ["SHOOTER_ONLY"],
+				"subtype" : 0,
+				"type" : "NO_WALL_PENALTY",
+				"val" : 0,
+				"valueType" : "ADDITIVE_VALUE"
+			}
+		],
+		"index" : 91,
+		"type" : ["HERO"]
+	},
+	"sphereOfPermanence":
+	{
+		"bonuses" : [
+			{
+				"subtype" : 35,
+				"type" : "SPELL_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 92,
+		"type" : ["HERO"]
+	},
+	"orbOfVulnerability":
+	{
+		"bonuses" : [
+			{
+				"type" : "NEGATE_ALL_NATURAL_IMMUNITIES",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 93,
+		"type" : ["HERO"]
+	},
+	"ringOfVitality":
+	{
+		"bonuses" : [
+			{
+				"type" : "STACK_HEALTH",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 94,
+		"type" : ["HERO"]
+	},
+	"ringOfLife":
+	{
+		"bonuses" : [
+			{
+				"type" : "STACK_HEALTH",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 95,
+		"type" : ["HERO"]
+	},
+	"vialOfLifeblood":
+	{
+		"bonuses" : [
+			{
+				"type" : "STACK_HEALTH",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 96,
+		"type" : ["HERO"]
+	},
+	"necklaceOfSwiftness":
+	{
+		"bonuses" : [
+			{
+				"type" : "STACKS_SPEED",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 97,
+		"type" : ["HERO"]
+	},
+	"bootsOfSpeed":
+	{
+		"bonuses" : [
+			{
+				"type" : "LAND_MOVEMENT",
+				"val" : 600,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 98,
+		"type" : ["HERO"]
+	},
+	"capeOfVelocity":
+	{
+		"bonuses" : [
+			{
+				"type" : "STACKS_SPEED",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 99,
+		"type" : ["HERO"]
+	},
+	"pendantOfDispassion":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "spell.berserk",
+				"type" : "SPELL_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 100,
+		"type" : ["HERO"]
+	},
+	"pendantOfSecondSight":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "spell.blind",
+				"type" : "SPELL_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 101,
+		"type" : ["HERO"]
+	},
+	"pendantOfHoliness":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "spell.curse",
+				"type" : "SPELL_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 102,
+		"type" : ["HERO"]
+	},
+	"pendantOfLife":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "spell.deathRipple",
+				"type" : "SPELL_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 103,
+		"type" : ["HERO"]
+	},
+	"pendantOfDeath":
+	{
+		"bonuses" : [
+			{
+				"limiters" : ["IS_UNDEAD"],
+				"subtype" : "spell.destroyUndead",
+				"type" : "SPELL_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 104,
+		"type" : ["HERO"]
+	},
+	"pendantOfFreeWill":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "spell.hypnotize",
+				"type" : "SPELL_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 105,
+		"type" : ["HERO"]
+	},
+	"pendantOfNegativity":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "spell.lightningBolt",
+				"type" : "SPELL_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "spell.chainLightning",
+				"type" : "SPELL_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 106,
+		"type" : ["HERO"]
+	},
+	"pendantOfTotalRecall":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "spell.forgetfulness",
+				"type" : "SPELL_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 107,
+		"type" : ["HERO"]
+	},
+	"pendantOfCourage":
+	{
+		"bonuses" : [
+			{
+				"type" : "MORALE",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "LUCK",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 108,
+		"type" : ["HERO"]
+	},
+	"everflowingCrystalCloak":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "resource.crystal",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 109,
+		"type" : ["HERO"]
+	},
+	"ringOfInfiniteGems":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "resource.gems",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 110,
+		"type" : ["HERO"]
+	},
+	"everpouringVialOfMercury":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "resource.mercury",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 111,
+		"type" : ["HERO"]
+	},
+	"inexhaustibleCartOfOre":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "resource.ore",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 112,
+		"type" : ["HERO"]
+	},
+	"eversmokingRingOfSulfur":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "resource.sulfur",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 113,
+		"type" : ["HERO"]
+	},
+	"inexhaustibleCartOfLumber":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "resource.wood",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 114,
+		"type" : ["HERO"]
+	},
+	"endlessSackOfGold":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "resource.gold",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 1000,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 115,
+		"type" : ["HERO"]
+	},
+	"endlessBagOfGold":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "resource.gold",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 750,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 116,
+		"type" : ["HERO"]
+	},
+	"endlessPurseOfGold":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "resource.gold",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 500,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 117,
+		"type" : ["HERO"]
+	},
+	"legsOfLegion":
+	{
+		"index" : 118,
+		"type" : ["HERO"],
+		"bonuses" : [
+			{
+				"type" : "CREATURE_GROWTH",
+				"subtype" : 2,
+				"val" : 5,
+				"propagator": "VISITED_TOWN_AND_VISITOR"
+			}
+		]
+	},
+	"loinsOfLegion":
+	{
+		"index" : 119,
+		"type" : ["HERO"],
+		"bonuses" : [
+			{
+				"type" : "CREATURE_GROWTH",
+				"subtype" : 3,
+				"val" : 4,
+				"propagator": "VISITED_TOWN_AND_VISITOR"
+			}
+		]
+	},
+	"torsoOfLegion":
+	{
+		"index" : 120,
+		"type" : ["HERO"],
+		"bonuses" : [
+			{
+				"type" : "CREATURE_GROWTH",
+				"subtype" : 4,
+				"val" : 3,
+				"propagator": "VISITED_TOWN_AND_VISITOR"
+			}
+		]
+	},
+	"armsOfLegion":
+	{
+		"index" : 121,
+		"type" : ["HERO"],
+		"bonuses" : [
+			{
+				"type" : "CREATURE_GROWTH",
+				"subtype" : 5,
+				"val" : 2,
+				"propagator": "VISITED_TOWN_AND_VISITOR"
+			}
+		]
+	},
+	"headOfLegion":
+	{
+		"index" : 122,
+		"type" : ["HERO"],
+		"bonuses" : [
+			{
+				"type" : "CREATURE_GROWTH",
+				"subtype" : 6,
+				"val" : 1,
+				"propagator": "VISITED_TOWN_AND_VISITOR"
+			}
+		]
+	},
+	"seaCaptainsHat":
+	{
+		"bonuses" : [
+			{
+				"type" : "WHIRLPOOL_PROTECTION",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "SEA_MOVEMENT",
+				"val" : 500,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "spell.summonBoat",
+				"type" : "SPELL",
+				"val" : 3,
+				"valueType" : "INDEPENDENT_MAX"
+			},
+			{
+				"subtype" : "spell.scuttleBoat",
+				"type" : "SPELL",
+				"val" : 3,
+				"valueType" : "INDEPENDENT_MAX"
+			}
+		],
+		"index" : 123,
+		"type" : ["HERO"]
+	},
+	"spellbindersHat":
+	{
+		"bonuses" : [
+			{
+				"subtype" : 5,
+				"type" : "SPELLS_OF_LEVEL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 124,
+		"type" : ["HERO"]
+	},
+	"shacklesOfWar":
+	{
+		"index" : 125,
+		"type" : ["HERO"],
+		"bonuses" : [
+			{
+				"type" : "BATTLE_NO_FLEEING",
+				"propagator": "BATTLE_WIDE"
+			}
+		]
+	},
+	"orbOfInhibition":
+	{
+		"index" : 126,
+		"type" : ["HERO"],
+		"bonuses" : [
+			{
+				"type" : "BLOCK_ALL_MAGIC",
+				"propagator": "BATTLE_WIDE"
+			}
+		]
+	},
+	"vialOfDragonBlood":
+	{
+		"bonuses" : [
+			{
+				"limiters" : ["DRAGON_NATURE"],
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 5,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"limiters" : ["DRAGON_NATURE"],
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 5,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 127,
+		"type" : ["HERO"]
+	},
+	"armageddonsBlade":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "spell.armageddon",
+				"type" : "SPELL",
+				"val" : 3,
+				"valueType" : "INDEPENDENT_MAX"
+			},
+			{
+				"subtype" : "spell.armageddon",
+				"type" : "SPELL_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 6,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 128,
+		"type" : ["HERO"]
+	},
+	"angelicAlliance":
+	{
+		"bonuses" : [
+			{
+				"type" : "NONEVIL_ALIGNMENT_MIX",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "spell.prayer",
+				"type" : "OPENING_BATTLE_SPELL",
+				"val" : 10,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 129,
+		"type" : ["HERO"],
+		"components":
+		[
+			"armorOfWonder",
+			"sandalsOfTheSaint",
+			"celestialNecklaceOfBliss",
+			"lionsShieldOfCourage",
+			"swordOfJudgement",
+			"helmOfHeavenlyEnlightenment"
+		]
+	},
+	"cloakOfTheUndeadKing":
+	{
+		"bonuses" : [
+			{
+				"type" : "IMPROVED_NECROMANCY", //TODO: more flexible?
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 130,
+		"type" : ["HERO"],
+		"components":
+		[
+			"amuletOfTheUndertaker",
+			"vampiresCowl",
+			"deadMansBoots"
+		]
+	},
+	"elixirOfLife":
+	{
+		"bonuses" : [
+			{
+				"type" : "STACK_HEALTH",
+				"val" : 25,
+				"valueType" : "PERCENT_TO_BASE"
+			},
+			{
+				"type" : "HP_REGENERATION",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 131,
+		"type" : ["HERO"],
+		"components":
+		[
+			"ringOfVitality",
+			"ringOfLife",
+			"vialOfLifeblood"
+		]
+	},
+	"armorOfTheDamned":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "spell.slow",
+				"type" : "OPENING_BATTLE_SPELL",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "spell.curse",
+				"type" : "OPENING_BATTLE_SPELL",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "spell.weakness",
+				"type" : "OPENING_BATTLE_SPELL",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "spell.misfortune",
+				"type" : "OPENING_BATTLE_SPELL",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 132,
+		"type" : ["HERO"],
+		"components":
+		[
+			"blackshardOfTheDeadKnight",
+			"shieldOfTheYawningDead",
+			"skullHelmet",
+			"ribCage"
+		]
+	},
+	"statueOfLegion":
+	{
+		"index" : 133,
+		"type" : ["HERO"],
+		"components":
+		[
+			"legsOfLegion",
+			"loinsOfLegion",
+			"torsoOfLegion",
+			"armsOfLegion",
+			"headOfLegion"
+		],
+		"bonuses" : [
+			{
+				"type" : "CREATURE_GROWTH_PERCENT",
+				"val" : 50,
+				"propagator": "PLAYER_PROPAGATOR"
+			}
+		]
+	},
+	"powerOfTheDragonFather":
+	{
+		"index" : 134,
+		"type" : ["HERO"],
+		"bonuses" : [
+			{
+				"type" : "LEVEL_SPELL_IMMUNITY",
+				"val" : 4,
+				"valueType" : "INDEPENDENT_MAX"
+			},
+			{
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 6,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.defence",
+				"type" : "PRIMARY_SKILL",
+				"val" : 6,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.spellpower",
+				"type" : "PRIMARY_SKILL",
+				"val" : 6,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "primSkill.knowledge",
+				"type" : "PRIMARY_SKILL",
+				"val" : 6,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"components":
+		[
+			"quietEyeOfTheDragon",
+			"redDragonFlameTongue",
+			"dragonScaleShield",
+			"dragonScaleArmor",
+			"dragonboneGreaves",
+			"dragonWingTabard",
+			"necklaceOfDragonteeth",
+			"crownOfDragontooth",
+			"stillEyeOfTheDragon"
+		]
+	},
+	"titansThunder":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "spell.titanBolt",
+				"type" : "SPELL",
+				"val" : 3,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 135,
+		"type" : ["HERO"],
+		"components":
+		[
+			"titansGladius",
+			"sentinelsShield",
+			"thunderHelmet",
+			"titansCuirass"
+		]
+	},
+	"admiralsHat":
+	{
+		"bonuses" : [
+			{
+				"type" : "FREE_SHIP_BOARDING",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 136,
+		"type" : ["HERO"],
+		"components":
+		[
+			"necklaceOfOceanGuidance",
+			"seaCaptainsHat"
+		]
+	},
+	"bowOfTheSharpshooter":
+	{
+		"bonuses" : [
+			{
+				"limiters" : ["SHOOTER_ONLY"],
+				"subtype" : 0,
+				"type" : "NO_DISTANCE_PENALTY",
+				"val" : 0,
+				"valueType" : "ADDITIVE_VALUE"
+			},
+			{
+				"limiters" : ["SHOOTER_ONLY"],
+				"subtype" : 0,
+				"type" : "NO_WALL_PENALTY",
+				"val" : 0,
+				"valueType" : "ADDITIVE_VALUE"
+			},
+			{
+				"limiters" : ["SHOOTER_ONLY"],
+				"subtype" : 0,
+				"type" : "FREE_SHOOTING",
+				"val" : 0,
+				"valueType" : "ADDITIVE_VALUE"
+			}
+		],
+		"index" : 137,
+		"type" : ["HERO"],
+		"components":
+		[
+			"bowOfElvenCherrywood",
+			"bowstringOfTheUnicornsMane",
+			"angelFeatherArrows"
+		]
+	},
+	"wizardsWell":
+	{
+		"bonuses" : [
+			{
+				"type" : "FULL_MANA_REGENERATION",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 138,
+		"type" : ["HERO"],
+		"components":
+		[
+			"charmOfMana",
+			"talismanOfMana",
+			"mysticOrbOfMana"
+		]
+	},
+	"ringOfTheMagi":
+	{
+		"bonuses" : [
+			{
+				"type" : "SPELL_DURATION",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 139,
+		"type" : ["HERO"],
+		"components":
+		[
+			"collarOfConjuring",
+			"ringOfConjuring",
+			"capeOfConjuring"
+		]
+	},
+	"cornucopia":
+	{
+		"bonuses" : [
+			{
+				"subtype" : "resource.crystal",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "resource.gems",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "resource.mercury",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "resource.sulfur",
+				"type" : "GENERATE_RESOURCE",
+				"val" : 4,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 140,
+		"type" : ["HERO"],
+		"components":
+		[
+			"everflowingCrystalCloak",
+			"ringOfInfiniteGems",
+			"everpouringVialOfMercury",
+			"eversmokingRingOfSulfur"
+		]
+	},
+	"magicWand":
+	{
+		"bonuses" : [
+			{
+				"type" : "CASTS",
+				"val" : 10,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "spell.implosion",
+				"type" : "SPELLCASTER",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "spell.fireball",
+				"type" : "SPELLCASTER",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "RANDOM_SPELLCASTER",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : "creature.vampireLord",
+				"type" : "DAEMON_SUMMONING",
+				"val" : 10,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"addInfo" : 2,
+				"subtype" : "spell.lightningBolt",
+				"type" : "ENCHANTER",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : 1,
+				"type" : "REBIRTH",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "MANA_DRAIN",
+				"val" : 10,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "HEALER",
+				"val" : 25,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 141,
+		"type" : ["CREATURE"]
+	},
+	"goldTowerArrow":
+	{
+		"bonuses" : [
+			{
+				"type" : "NO_DISTANCE_PENALTY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "ADDITIONAL_ATTACK",
+				"val" : 2,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : 22,
+				"type" : "SPELL_LIKE_ATTACK",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "CATAPULT",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "ACID_BREATH",
+				"val" : 20,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"subtype" : 0,
+				"type" : "SHOTS",
+				"val" : 200,
+				"valueType" : "PERCENT_TO_BASE"
+			},
+			{
+				"addInfo" : 1,
+				"subtype" : "spell.age",
+				"type" : "SPELL_BEFORE_ATTACK",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"addInfo" : 1,
+				"subtype" : "spell.berserk",
+				"type" : "SPELL_AFTER_ATTACK",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"addInfo" : 1,
+				"subtype" : "spell.poison",
+				"type" : "SPELL_AFTER_ATTACK",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"addInfo" : 1,
+				"subtype" : "spell.disruptingRay",
+				"type" : "SPELL_AFTER_ATTACK",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 142,
+		"type" : ["CREATURE"]
+	},
+	"monstersPower":
+	{
+		"bonuses" : [
+			{
+				"type" : "STACK_HEALTH",
+				"val" : 100,
+				"valueType" : "PERCENT_TO_BASE"
+			},
+			{
+				"subtype" : 2,
+				"type" : "CREATURE_DAMAGE",
+				"val" : 100,
+				"valueType" : "PERCENT_TO_ALL"
+			},
+			{
+				"type" : "HP_REGENERATION",
+				"val" : 50,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "NO_RETALIATION",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "RETURN_AFTER_STRIKE",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "ATTACKS_ALL_ADJACENT",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "SPELL_RESISTANCE_AURA",
+				"val" : 100,
+				"valueType" : "BASE_NUMBER"
+			},
+			{
+				"type" : "DIRECT_DAMAGE_IMMUNITY",
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 143,
+		"type" : ["CREATURE"]
+	},
+	"art144":
+	{
+		"index" : 144,
+		"type" : ["HERO"]
+	},
+	"art145":
+	{
+		"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":
 		{
-			"bonuses" : [
-				{
-					"type" : "STACK_HEALTH",
-					"val" : 25,
-					"valueType" : "PERCENT_TO_BASE"
-				},
-				{
-					"type" : "HP_REGENERATION",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 131,
-			"type" : ["HERO"],
-			"components":
+			"bonusesPerLevel":
 			[
-				"ringOfVitality",
-				"ringOfLife",
-				"vialOfLifeblood"
-			]
-		},
-		"armorOfTheDamned":
-		{
-			"bonuses" : [
-				{
-					"subtype" : "spell.slow",
-					"type" : "OPENING_BATTLE_SPELL",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "spell.curse",
-					"type" : "OPENING_BATTLE_SPELL",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "spell.weakness",
-					"type" : "OPENING_BATTLE_SPELL",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				},
 				{
-					"subtype" : "spell.misfortune",
-					"type" : "OPENING_BATTLE_SPELL",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
+					"level": 6,
+					"bonus": 
+					{
+						"type" : "PRIMARY_SKILL",
+						"subtype" : "primSkill.attack",
+						"val" : 1
+					}
 				}
-			],
-			"id" : 132,
-			"type" : ["HERO"],
-			"components":
-			[
-				"blackshardOfTheDeadKnight",
-				"shieldOfTheYawningDead",
-				"skullHelmet",
-				"ribCage"
 			]
-		},
-		"statueOfLegion":
+		}
+	},
+	"mithrilMail":
+	{
+		"bonuses" : [
+			{
+				"type" : "STACK_HEALTH",
+				"val" : 12,
+				"valueType" : "PERCENT_TO_ALL"
+			}
+		],
+		"index" : 147,
+		"type" : ["COMMANDER"],
+		"growing":
 		{
-			"id" : 133,
-			"type" : ["HERO"],
-			"components":
+			"bonusesPerLevel":
 			[
-				"legsOfLegion",
-				"loinsOfLegion",
-				"torsoOfLegion",
-				"armsOfLegion",
-				"headOfLegion"
-			],
-			"bonuses" : [
 				{
-					"type" : "CREATURE_GROWTH_PERCENT",
-					"val" : 50,
-					"propagator": "PLAYER_PROPAGATOR"
+					"level": 1,
+					"bonus": 
+					{
+						"type" : "STACK_HEALTH",
+						"val" : 1
+					}
 				}
 			]
-		},
-		"powerOfTheDragonFather":
+		}
+	},
+	"swordOfSharpness":
+	{
+		"bonuses" : [
+			{
+				"subtype" : 0,
+				"type" : "CREATURE_DAMAGE",
+				"val" : 12,
+				"valueType" : "PERCENT_TO_ALL"
+			}
+		],
+		"index" : 148,
+		"type" : ["COMMANDER"],
+		"growing":
 		{
-			"id" : 134,
-			"type" : ["HERO"],
-			"bonuses" : [
-				{
-					"type" : "LEVEL_SPELL_IMMUNITY",
-					"val" : 4,
-					"valueType" : "INDEPENDENT_MAX"
-				},
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.defence",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.spellpower",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "primSkill.knowledge",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"components":
+			"bonusesPerLevel":
 			[
-				"quietEyeOfTheDragon",
-				"redDragonFlameTongue",
-				"dragonScaleShield",
-				"dragonScaleArmor",
-				"dragonboneGreaves",
-				"dragonWingTabard",
-				"necklaceOfDragonteeth",
-				"crownOfDragontooth",
-				"stillEyeOfTheDragon"
-			]
-		},
-		"titansThunder":
-		{
-			"bonuses" : [
 				{
-					"subtype" : "spell.titanBolt",
-					"type" : "SPELL",
-					"val" : 3,
-					"valueType" : "BASE_NUMBER"
+					"level": 1,
+					"bonus": 
+					{
+						"type" : "CREATURE_DAMAGE",
+						"val" : 1
+					}
 				}
-			],
-			"id" : 135,
-			"type" : ["HERO"],
-			"components":
-			[
-				"titansGladius",
-				"sentinelsShield",
-				"thunderHelmet",
-				"titansCuirass"
 			]
-		},
-		"admiralsHat":
+		}
+	},
+	"helmOfImmortality": //TODO: implement
+	{
+		"index" : 149,
+		"type" : ["COMMANDER"]
+	},
+	"pendantOfSorcery":
+	{
+		"bonuses" : [
+			{
+				"type" : "CASTS",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 150,
+		"type" : ["COMMANDER"],
+		"growing":
 		{
-			"bonuses" : [
-				{
-					"type" : "FREE_SHIP_BOARDING",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 136,
-			"type" : ["HERO"],
-			"components":
+			"bonusesPerLevel":
 			[
-				"necklaceOfOceanGuidance",
-				"seaCaptainsHat"
-			]
-		},
-		"bowOfTheSharpshooter":
-		{
-			"bonuses" : [
-				{
-					"limiters" : ["SHOOTER_ONLY"],
-					"subtype" : 0,
-					"type" : "NO_DISTANCE_PENALTY",
-					"val" : 0,
-					"valueType" : "ADDITIVE_VALUE"
-				},
 				{
-					"limiters" : ["SHOOTER_ONLY"],
-					"subtype" : 0,
-					"type" : "NO_WALL_PENALTY",
-					"val" : 0,
-					"valueType" : "ADDITIVE_VALUE"
-				},
-				{
-					"limiters" : ["SHOOTER_ONLY"],
-					"subtype" : 0,
-					"type" : "FREE_SHOOTING",
-					"val" : 0,
-					"valueType" : "ADDITIVE_VALUE"
+					"level": 10,
+					"bonus": 
+					{
+						"type" : "CREATURE_ENCHANT_POWER",
+						"val" : 1
+					}
 				}
-			],
-			"id" : 137,
-			"type" : ["HERO"],
-			"components":
-			[
-				"bowOfElvenCherrywood",
-				"bowstringOfTheUnicornsMane",
-				"angelFeatherArrows"
 			]
-		},
-		"wizardsWell":
+		}
+	},
+	"bootsOfHaste":
+	{
+		"bonuses" : [
+			{
+				"type" : "STACKS_SPEED",
+				"val" : 1,
+				"valueType" : "BASE_NUMBER"
+			}
+		],
+		"index" : 151,
+		"type" : ["COMMANDER"],
+		"growing":
 		{
-			"bonuses" : [
-				{
-					"type" : "FULL_MANA_REGENERATION",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 138,
-			"type" : ["HERO"],
-			"components":
+			"bonusesPerLevel":
 			[
-				"charmOfMana",
-				"talismanOfMana",
-				"mysticOrbOfMana"
-			]
-		},
-		"ringOfTheMagi":
-		{
-			"bonuses" : [
 				{
-					"type" : "SPELL_DURATION",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
+					"level": 10,
+					"bonus": 
+					{
+						"type" : "STACKS_SPEED",
+						"val" : 1
+					}
 				}
-			],
-			"id" : 139,
-			"type" : ["HERO"],
-			"components":
-			[
-				"collarOfConjuring",
-				"ringOfConjuring",
-				"capeOfConjuring"
 			]
-		},
-		"cornucopia":
+		}
+	},
+	"bowOfSeeking":
+	{
+		"index" : 152,
+		"type" : ["COMMANDER"],
+		"growing":
 		{
-			"bonuses" : [
-				{
-					"subtype" : "resource.crystal",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "resource.gems",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "resource.mercury",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "resource.sulfur",
-					"type" : "GENERATE_RESOURCE",
-					"val" : 4,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 140,
-			"type" : ["HERO"],
-			"components":
+			"thresholdBonuses":
 			[
-				"everflowingCrystalCloak",
-				"ringOfInfiniteGems",
-				"everpouringVialOfMercury",
-				"eversmokingRingOfSulfur"
-			]
-		},
-		"magicWand":
-		{
-			"bonuses" : [
-				{
-					"type" : "CASTS",
-					"val" : 10,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "spell.implosion",
-					"type" : "SPELLCASTER",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : "spell.fireball",
-					"type" : "SPELLCASTER",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "RANDOM_SPELLCASTER",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
 				{
-					"subtype" : "creature.vampireLord",
-					"type" : "DAEMON_SUMMONING",
-					"val" : 10,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"addInfo" : 2,
-					"subtype" : "spell.lightningBolt",
-					"type" : "ENCHANTER",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : 1,
-					"type" : "REBIRTH",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "MANA_DRAIN",
-					"val" : 10,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "HEALER",
-					"val" : 25,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 141,
-			"type" : ["CREATURE"]
-		},
-		"goldTowerArrow":
-		{
-			"bonuses" : [
-				{
-					"type" : "NO_DISTANCE_PENALTY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "ADDITIONAL_ATTACK",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : 22,
-					"type" : "SPELL_LIKE_ATTACK",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "CATAPULT",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "ACID_BREATH",
-					"val" : 20,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"subtype" : 0,
-					"type" : "SHOTS",
-					"val" : 200,
-					"valueType" : "PERCENT_TO_BASE"
-				},
-				{
-					"addInfo" : 1,
-					"subtype" : "spell.age",
-					"type" : "SPELL_BEFORE_ATTACK",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"addInfo" : 1,
-					"subtype" : "spell.berserk",
-					"type" : "SPELL_AFTER_ATTACK",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"addInfo" : 1,
-					"subtype" : "spell.poison",
-					"type" : "SPELL_AFTER_ATTACK",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"addInfo" : 1,
-					"subtype" : "spell.disruptingRay",
-					"type" : "SPELL_AFTER_ATTACK",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 142,
-			"type" : ["CREATURE"]
-		},
-		"monstersPower":
-		{
-			"bonuses" : [
-				{
-					"type" : "STACK_HEALTH",
-					"val" : 100,
-					"valueType" : "PERCENT_TO_BASE"
-				},
-				{
-					"subtype" : 2,
-					"type" : "CREATURE_DAMAGE",
-					"val" : 100,
-					"valueType" : "PERCENT_TO_ALL"
-				},
-				{
-					"type" : "HP_REGENERATION",
-					"val" : 50,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "NO_RETALIATION",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "RETURN_AFTER_STRIKE",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "ATTACKS_ALL_ADJACENT",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "SPELL_RESISTANCE_AURA",
-					"val" : 100,
-					"valueType" : "BASE_NUMBER"
-				},
-				{
-					"type" : "DIRECT_DAMAGE_IMMUNITY",
-					"val" : 0,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 143,
-			"type" : ["CREATURE"]
-		},
-		"art144":
-		{
-			"id" : 144,
-			"type" : ["HERO"]
-		},
-		"art145":
-		{
-			"id" : 145,
-			"type" : ["HERO"]
-		},
-		"axeOfSmashing": //TODO: move growing bonuses to this config, someday
-		{
-			"bonuses" : [
-				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 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"
-				}
-			],
-			"id" : 147,
-			"type" : ["COMMANDER"],
-			"growing":
-			{
-				"bonusesPerLevel":
-				[
+					"level": 5,
+					"bonus":
 					{
-						"level": 1,
-						"bonus": 
-						{
-							"type" : "STACK_HEALTH",
-							"val" : 1
-						}
+						"type" : "SHOOTER"
 					}
-				]
-			}
-		},
-		"swordOfSharpness":
-		{
-			"bonuses" : [
+				},
 				{
-					"subtype" : 0,
-					"type" : "CREATURE_DAMAGE",
-					"val" : 12,
-					"valueType" : "PERCENT_TO_ALL"
-				}
-			],
-			"id" : 148,
-			"type" : ["COMMANDER"],
-			"growing":
-			{
-				"bonusesPerLevel":
-				[
+					"level": 25,
+					"bonus": 
 					{
-						"level": 1,
-						"bonus": 
-						{
-							"type" : "CREATURE_DAMAGE",
-							"val" : 1
-						}
+						"type" : "NO_WALL_PENALTY"
 					}
-				]
-			}
-		},
-		"helmOfImmortality": //TODO: implement
-		{
-			"id" : 149,
-			"type" : ["COMMANDER"]
-		},
-		"pendantOfSorcery":
-		{
-			"bonuses" : [
+				},
 				{
-					"type" : "CASTS",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 150,
-			"type" : ["COMMANDER"],
-			"growing":
-			{
-				"bonusesPerLevel":
-				[
+					"level": 50,
+					"bonus": 
 					{
-						"level": 10,
-						"bonus": 
-						{
-							"type" : "CREATURE_ENCHANT_POWER",
-							"val" : 1
-						}
+						"type" : "NO_DISTANCE_PENALTY"
 					}
-				]
-			}
-		},
-		"bootsOfHaste":
-		{
-			"bonuses" : [
-				{
-					"type" : "STACKS_SPEED",
-					"val" : 1,
-					"valueType" : "BASE_NUMBER"
 				}
-			],
-			"id" : 151,
-			"type" : ["COMMANDER"],
-			"growing":
-			{
-				"bonusesPerLevel":
-				[
-					{
-						"level": 10,
-						"bonus": 
-						{
-							"type" : "STACKS_SPEED",
-							"val" : 1
-						}
-					}
-				]
-			}
-		},
-		"bowOfSeeking":
-		{
-			"id" : 152,
-			"type" : ["COMMANDER"],
-			"growing":
+			]
+		}
+	},
+	"dragonEyeRing": //TODO: implement
+	{
+		"index" : 153,
+		"type" : ["COMMANDER"],
+	},
+	"hardenedShield":
+	{
+		"bonuses" : [
 			{
-				"thresholdBonuses":
-				[
-					{
-						"level": 5,
-						"bonus":
-						{
-							"type" : "SHOOTER"
-						}
-					},
-					{
-						"level": 25,
-						"bonus": 
-						{
-							"type" : "NO_WALL_PENALTY"
-						}
-					},
-					{
-						"level": 50,
-						"bonus": 
-						{
-							"type" : "NO_DISTANCE_PENALTY"
-						}
-					}
-				]
+				"subtype" : "primSkill.attack",
+				"type" : "PRIMARY_SKILL",
+				"val" : 6,
+				"valueType" : "BASE_NUMBER"
 			}
-		},
-		"dragonEyeRing": //TODO: implement
-		{
-			"id" : 153,
-			"type" : ["COMMANDER"],
-		},
-		"hardenedShield":
+		],
+		"index" : 154,
+		"type" : ["COMMANDER"],
+		"growing":
 		{
-			"bonuses" : [
+			"bonusesPerLevel":
+			[
 				{
-					"subtype" : "primSkill.attack",
-					"type" : "PRIMARY_SKILL",
-					"val" : 6,
-					"valueType" : "BASE_NUMBER"
-				}
-			],
-			"id" : 154,
-			"type" : ["COMMANDER"],
-			"growing":
-			{
-				"bonusesPerLevel":
-				[
+					"level": 6,
+					"bonus": 
 					{
-						"level": 6,
-						"bonus": 
-						{
-							"type" : "PRIMARY_SKILL",
-							"subtype" : "primSkill.defence",
-							"val" : 1
-						}
+						"type" : "PRIMARY_SKILL",
+						"subtype" : "primSkill.defence",
+						"val" : 1
 					}
-				]
-			}
-		},
-		"slavasRingOfPower": //TODO: implement if possible
-		{
-			"id" : 155,
-			"type" : ["COMMANDER"]
-		},
-		"warlordsBanner":
-		{
-			"bonuses" : [
-				{
-					"type" : "STACK_HEALTH",
-					"val" : 2,
-					"valueType" : "BASE_NUMBER"
 				}
-			],
-			"id" : 156,
-			"type" : ["CREATURE"]
-		},
-		"crimsonShieldOfRetribution": //TODO: implement
-		{
-			"id" : 157,
-			"type" : ["HERO"]
-		},
-		"barbarianLordsAxeOfFerocity": //TODO: implement
-		{
-			"id" : 158,
-			"type" : ["HERO"],
-			"components":
-			[
-				"ogresClubOfHavoc",
-				"targOfTheRampagingOgre",
-				"crownOfTheSupremeMagi",
-				"tunicOfTheCyclopsKing"
 			]
-		},
-		"dragonheart":
-		{
-			"id" : 159,
-			"type" : ["HERO"]
-		},
-		"gateKey":
-		{
-			"id" : 160,
-			"type" : ["HERO"]
-		},
-		"art161":
-		{
-			"id" : 161,
-			"type" : ["HERO"]
-		},
-		"art162":
-		{
-			"id" : 162,
-			"type" : ["HERO"]
-		},
-		"art163":
-		{
-			"id" : 163,
-			"type" : ["HERO"]
-		},
-		"art164":
-		{
-			"id" : 164,
-			"type" : ["HERO"]
-		},
-		"art165":
-		{
-			"id" : 165,
-			"type" : ["HERO"]
-		},
-		"art166":
-		{
-			"id" : 166,
-			"type" : ["HERO"]
-		},
-		"art167":
-		{
-			"id" : 167,
-			"type" : ["HERO"]
-		},
-		"art168":
-		{
-			"id" : 168,
-			"type" : ["HERO"]
-		},
-		"art169":
-		{
-			"id" : 169,
-			"type" : ["HERO"]
-		},
-		"art170":
-		{
-			"id" : 170,
-			"type" : ["HERO"]
 		}
+	},
+	"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"]
 	}
 }

+ 14 - 14
config/creatures/castle.json

@@ -1,7 +1,7 @@
 {
 	"pikeman" :
 	{
-		"id": 0,
+		"index": 0,
 		"level": 1,
 		"faction": "castle",
 		"upgrades": ["halberdier"],
@@ -27,7 +27,7 @@
 	},
 	"halberdier" :
 	{
-		"id": 1,
+		"index": 1,
 		"level": 1,
 		"faction": "castle",
 		"abilities":
@@ -52,7 +52,7 @@
 	},
 	"archer" :
 	{
-		"id": 2,
+		"index": 2,
 		"level": 2,
 		"extraNames": [ "lightCrossbowman" ],
 		"faction": "castle",
@@ -77,7 +77,7 @@
 	},
 	"marksman" :
 	{
-		"id": 3,
+		"index": 3,
 		"level": 2,
 		"faction": "castle",
 		"abilities": {
@@ -108,7 +108,7 @@
 	},
 	"griffin" :
 	{
-		"id": 4,
+		"index": 4,
 		"level": 3,
 		"faction": "castle",
 		"abilities":
@@ -136,7 +136,7 @@
 	},
 	"royalGriffin" :
 	{
-		"id": 5,
+		"index": 5,
 		"level": 3,
 		"faction": "castle",
 		"abilities":
@@ -161,7 +161,7 @@
 	},
 	"swordsman" :
 	{
-		"id": 6,
+		"index": 6,
 		"level": 4,
 		"faction": "castle",
 		"upgrades": ["crusader"],
@@ -180,7 +180,7 @@
 	},
 	"crusader" :
 	{
-		"id": 7,
+		"index": 7,
 		"level": 4,
 		"faction": "castle",
 		"abilities":
@@ -206,7 +206,7 @@
 	},
 	"monk" :
 	{
-		"id": 8,
+		"index": 8,
 		"level": 5,
 		"faction": "castle",
 		"upgrades": ["zealot"],
@@ -230,7 +230,7 @@
 	},
 	"zealot" :
 	{
-		"id": 9,
+		"index": 9,
 		"level": 5,
 		"faction": "castle",
 		"graphics" :
@@ -253,7 +253,7 @@
 	},
 	"cavalier" :
 	{
-		"id": 10,
+		"index": 10,
 		"level": 6,
 		"faction": "castle",
 		"upgrades": ["champion"],
@@ -272,7 +272,7 @@
 	},
 	"champion" :
 	{
-		"id": 11,
+		"index": 11,
 		"level": 6,
 		"faction": "castle",
 		"graphics" :
@@ -290,7 +290,7 @@
 	},
 	"angel" :
 	{
-		"id": 12,
+		"index": 12,
 		"level": 7,
 		"faction": "castle",
 		"abilities":
@@ -324,7 +324,7 @@
 	},
 	"archangel" :
 	{
-		"id": 13,
+		"index": 13,
 		"level": 7,
 		"faction": "castle",
 		"abilities":

+ 14 - 14
config/creatures/conflux.json

@@ -1,7 +1,7 @@
 {
 	"airElemental" :
 	{
-		"id": 112,
+		"index": 112,
 		"level": 2,
 		"extraNames": [ "airElementals" ],
 		"faction": "conflux",
@@ -49,7 +49,7 @@
 	},
 	"earthElemental" :
 	{
-		"id": 113,
+		"index": 113,
 		"level": 5,
 		"faction": "conflux",
 		"abilities":
@@ -95,7 +95,7 @@
 	},
 	"fireElemental" :
 	{
-		"id": 114,
+		"index": 114,
 		"level": 4,
 		"faction": "conflux",
 		"abilities":
@@ -141,7 +141,7 @@
 	},
 	"waterElemental" :
 	{
-		"id": 115,
+		"index": 115,
 		"level": 3,
 		"extraNames": [ "waterElementals" ],
 		"faction": "conflux",
@@ -207,7 +207,7 @@
 	},
 	"pixie" :
 	{
-		"id": 118,
+		"index": 118,
 		"level": 1,
 		"extraNames": [ "pixies" ],
 		"faction": "conflux",
@@ -227,7 +227,7 @@
 	},
 	"sprite" :
 	{
-		"id": 119,
+		"index": 119,
 		"level": 1,
 		"faction": "conflux",
 		"graphics" :
@@ -245,7 +245,7 @@
 	},
 	"psychicElemental" :
 	{
-		"id": 120,
+		"index": 120,
 		"level": 6,
 		"faction": "conflux",
 		"abilities":
@@ -272,7 +272,7 @@
 	},
 	"magicElemental" :
 	{
-		"id": 121,
+		"index": 121,
 		"level": 6,
 		"faction": "conflux",
 		"abilities":
@@ -303,7 +303,7 @@
 	},
 	"iceElemental" :
 	{
-		"id": 123,
+		"index": 123,
 		"level": 3,
 		"faction": "conflux",
 		"abilities":
@@ -350,7 +350,7 @@
 	},
 	"magmaElemental" :
 	{
-		"id": 125,
+		"index": 125,
 		"level": 5,
 		"faction": "conflux",
 		"abilities":
@@ -391,7 +391,7 @@
 	},
 	"stormElemental" :
 	{
-		"id": 127,
+		"index": 127,
 		"level": 2,
 		"faction": "conflux",
 		"abilities":
@@ -437,7 +437,7 @@
 	},
 	"energyElemental" :
 	{
-		"id": 129,
+		"index": 129,
 		"level": 4,
 		"faction": "conflux",
 		"abilities":
@@ -478,7 +478,7 @@
 	},
 	"firebird" :
 	{
-		"id": 130,
+		"index": 130,
 		"level": 7,
 		"faction": "conflux",
 		"upgrades": ["phoenix"],
@@ -504,7 +504,7 @@
 	},
 	"phoenix" :
 	{
-		"id": 131,
+		"index": 131,
 		"level": 7,
 		"faction": "conflux",
 		"abilities":

+ 14 - 14
config/creatures/dungeon.json

@@ -1,7 +1,7 @@
 {
 	"troglodyte" :
 	{
-		"id": 70,
+		"index": 70,
 		"level": 1,
 		"faction": "dungeon",
 		"abilities":
@@ -29,7 +29,7 @@
 	},
 	"infernalTroglodyte" :
 	{
-		"id": 71,
+		"index": 71,
 		"level": 1,
 		"faction": "dungeon",
 		"abilities":
@@ -55,7 +55,7 @@
 	},
 	"harpy" :
 	{
-		"id": 72,
+		"index": 72,
 		"level": 2,
 		"faction": "dungeon",
 		"abilities":
@@ -83,7 +83,7 @@
 	},
 	"harpyHag" :
 	{
-		"id": 73,
+		"index": 73,
 		"level": 2,
 		"faction": "dungeon",
 		"abilities":
@@ -113,7 +113,7 @@
 	},
 	"beholder" :
 	{
-		"id": 74,
+		"index": 74,
 		"level": 3,
 		"faction": "dungeon",
 		"upgrades": ["evilEye"],
@@ -137,7 +137,7 @@
 	},
 	"evilEye" :
 	{
-		"id": 75,
+		"index": 75,
 		"level": 3,
 		"faction": "dungeon",
 		"graphics" :
@@ -160,7 +160,7 @@
 	},
 	"medusa" :
 	{
-		"id": 76,
+		"index": 76,
 		"level": 4,
 		"faction": "dungeon",
 		"abilities":
@@ -194,7 +194,7 @@
 	},
 	"medusaQueen" :
 	{
-		"id": 77,
+		"index": 77,
 		"level": 4,
 		"faction": "dungeon",
 		"abilities":
@@ -227,7 +227,7 @@
 	},
 	"minotaur" :
 	{
-		"id": 78,
+		"index": 78,
 		"level": 5,
 		"faction": "dungeon",
 		"abilities": 
@@ -253,7 +253,7 @@
 	},
 	"minotaurKing" :
 	{
-		"id": 79,
+		"index": 79,
 		"level": 5,
 		"faction": "dungeon",
 		"abilities":
@@ -279,7 +279,7 @@
 	},
 	"manticore" :
 	{
-		"id": 80,
+		"index": 80,
 		"level": 6,
 		"faction": "dungeon",
 		"upgrades": ["scorpicore"],
@@ -299,7 +299,7 @@
 	},
 	"scorpicore" :
 	{
-		"id": 81,
+		"index": 81,
 		"level": 6,
 		"faction": "dungeon",
 		"abilities":
@@ -327,7 +327,7 @@
 	},
 	"redDragon" :
 	{
-		"id": 82,
+		"index": 82,
 		"level": 7,
 		"faction": "dungeon",
 		"abilities":
@@ -362,7 +362,7 @@
 	},
 	"blackDragon" :
 	{
-		"id": 83,
+		"index": 83,
 		"level": 7,
 		"faction": "dungeon",
 		"abilities":

+ 14 - 14
config/creatures/fortress.json

@@ -1,7 +1,7 @@
 {
 	"gnoll" :
 	{
-		"id": 98,
+		"index": 98,
 		"level": 1,
 		"faction": "fortress",
 		"upgrades": ["gnollMarauder"],
@@ -20,7 +20,7 @@
 	},
 	"gnollMarauder" :
 	{
-		"id": 99,
+		"index": 99,
 		"level": 1,
 		"faction": "fortress",
 		"graphics" :
@@ -38,7 +38,7 @@
 	},
 	"lizardman" :
 	{
-		"id": 100,
+		"index": 100,
 		"level": 2,
 		"extraNames": [ "primitiveLizardman", ],
 		"faction": "fortress",
@@ -64,7 +64,7 @@
 	},
 	"lizardWarrior" :
 	{
-		"id": 101,
+		"index": 101,
 		"level": 2,
 		"faction": "fortress",
 		"graphics" :
@@ -87,7 +87,7 @@
 	},
 	"gorgon" :
 	{
-		"id": 102,
+		"index": 102,
 		"level": 5,
 		"faction": "fortress",
 		"upgrades": ["mightyGorgon"],
@@ -106,7 +106,7 @@
 	},
 	"mightyGorgon" :
 	{
-		"id": 103,
+		"index": 103,
 		"level": 5,
 		"faction": "fortress",
 		"abilities":
@@ -132,7 +132,7 @@
 	},
 	"serpentFly" :
 	{
-		"id": 104,
+		"index": 104,
 		"level": 3,
 		"extraNames": [ "dragonFly" ],
 		"faction": "fortress",
@@ -162,7 +162,7 @@
 	},
 	"fireDragonFly" : // dragonFly is correct in-game, incorrect in HOTRAITS
 	{
-		"id": 105,
+		"index": 105,
 		"level": 3,
 		"faction": "fortress",
 		"abilities":
@@ -196,7 +196,7 @@
 	},
 	"basilisk" :
 	{
-		"id": 106,
+		"index": 106,
 		"level": 4,
 		"faction": "fortress",
 		"abilities":
@@ -224,7 +224,7 @@
 	},
 	"greaterBasilisk" :
 	{
-		"id": 107,
+		"index": 107,
 		"level": 4,
 		"faction": "fortress",
 		"abilities":
@@ -251,7 +251,7 @@
 	},
 	"wyvern" :
 	{
-		"id": 108,
+		"index": 108,
 		"level": 6,
 		"faction": "fortress",
 		"upgrades": ["wyvernMonarch"],
@@ -270,7 +270,7 @@
 	},
 	"wyvernMonarch" :
 	{
-		"id": 109,
+		"index": 109,
 		"level": 6,
 		"faction": "fortress",
 		"abilities":
@@ -297,7 +297,7 @@
 	},
 	"hydra" :
 	{
-		"id": 110,
+		"index": 110,
 		"level": 7,
 		"faction": "fortress",
 		"abilities":
@@ -327,7 +327,7 @@
 	},
 	"chaosHydra" :
 	{
-		"id": 111,
+		"index": 111,
 		"level": 7,
 		"faction": "fortress",
 		"abilities":

+ 14 - 14
config/creatures/inferno.json

@@ -1,7 +1,7 @@
 {
 	"imp" :
 	{
-		"id": 42,
+		"index": 42,
 		"level": 1,
 		"faction": "inferno",
 		"upgrades": ["familiar"],
@@ -20,7 +20,7 @@
 	},
 	"familiar" :
 	{
-		"id": 43,
+		"index": 43,
 		"level": 1,
 		"faction": "inferno",
 		"abilities":
@@ -46,7 +46,7 @@
 	},
 	"gog" :
 	{
-		"id": 44,
+		"index": 44,
 		"level": 2,
 		"faction": "inferno",
 		"upgrades": ["magog"],
@@ -71,7 +71,7 @@
 	},
 	"magog" :
 	{
-		"id": 45,
+		"index": 45,
 		"level": 2,
 		"faction": "inferno",
 		"abilities":
@@ -102,7 +102,7 @@
 	},
 	"hellHound" :
 	{
-		"id": 46,
+		"index": 46,
 		"level": 3,
 		"faction": "inferno",
 		"upgrades": ["cerberus"],
@@ -125,7 +125,7 @@
 	},
 	"cerberus" :
 	{
-		"id": 47,
+		"index": 47,
 		"level": 3,
 		"faction": "inferno",
 		"abilities":
@@ -155,7 +155,7 @@
 	},
 	"demon" :
 	{
-		"id": 48,
+		"index": 48,
 		"level": 4,
 		"faction": "inferno",
 		"upgrades": ["hornedDemon"],
@@ -174,7 +174,7 @@
 	},
 	"hornedDemon" :
 	{
-		"id": 49,
+		"index": 49,
 		"level": 4,
 		"faction": "inferno",
 		"graphics" :
@@ -192,7 +192,7 @@
 	},
 	"pitFiend" :
 	{
-		"id": 50,
+		"index": 50,
 		"level": 5,
 		"faction": "inferno",
 		"upgrades": ["pitLord"],
@@ -211,7 +211,7 @@
 	},
 	"pitLord" :
 	{
-		"id": 51,
+		"index": 51,
 		"level": 5,
 		"faction": "inferno",
 		"abilities":
@@ -243,7 +243,7 @@
 	},
 	"efreet" :
 	{
-		"id": 52,
+		"index": 52,
 		"level": 6,
 		"faction": "inferno", 
 		"abilities":
@@ -285,7 +285,7 @@
 	},
 	"efreetSultan" :
 	{
-		"id": 53,
+		"index": 53,
 		"level": 6,
 		"faction": "inferno",
 		"abilities":
@@ -332,7 +332,7 @@
 	},
 	"devil" :
 	{
-		"id": 54,
+		"index": 54,
 		"level": 7,
 		"faction": "inferno",
 		"abilities":
@@ -383,7 +383,7 @@
 	},
 	"archDevil" :
 	{
-		"id": 55,
+		"index": 55,
 		"level": 7,
 		"faction": "inferno",
 		"abilities" :

+ 14 - 14
config/creatures/necropolis.json

@@ -1,7 +1,7 @@
 {
 	"skeleton" :
 	{
-		"id": 56,
+		"index": 56,
 		"level": 1,
 		"faction": "necropolis",
 		"upgrades": ["skeletonWarrior"],
@@ -20,7 +20,7 @@
 	},
 	"skeletonWarrior" :
 	{
-		"id": 57,
+		"index": 57,
 		"level": 1,
 		"faction": "necropolis",
 		"graphics" :
@@ -38,7 +38,7 @@
 	},
 	"walkingDead" :
 	{
-		"id": 58,
+		"index": 58,
 		"level": 2,
 		"extraNames": [ "zombie" ], //FIXME: zombie is a name of upgrade but not in HOTRAITS
 		"faction" : "necropolis",
@@ -58,7 +58,7 @@
 	},
 	"zombieLord" : //FIXME: zombie is a correct in-name but not in HOTRAITS.TXT
 	{
-		"id": 59,
+		"index": 59,
 		"level": 2,
 		"faction": "necropolis",
 		"graphics" :
@@ -76,7 +76,7 @@
 	},
 	"wight" :
 	{
-		"id": 60,
+		"index": 60,
 		"level": 3,
 		"faction": "necropolis",
 		"abilities":
@@ -104,7 +104,7 @@
 	},
 	"wraith" :
 	{
-		"id": 61,
+		"index": 61,
 		"level": 3,
 		"faction": "necropolis",
 		"abilities":
@@ -135,7 +135,7 @@
 	},
 	"vampire" :
 	{
-		"id": 62,
+		"index": 62,
 		"level": 4,
 		"faction": "necropolis",
 		"abilities":
@@ -164,7 +164,7 @@
 	},
 	"vampireLord" :
 	{
-		"id": 63,
+		"index": 63,
 		"level": 4,
 		"faction": "necropolis",
 		"abilities":
@@ -198,7 +198,7 @@
 	},
 	"lich" :
 	{
-		"id": 64,
+		"index": 64,
 		"level": 5,
 		"faction": "necropolis",
 		"abilities":
@@ -230,7 +230,7 @@
 	},
 	"powerLich" :
 	{
-		"id": 65,
+		"index": 65,
 		"level": 5,
 		"faction": "necropolis",
 		"abilities":
@@ -261,7 +261,7 @@
 	},
 	"blackKnight" :
 	{
-		"id": 66,
+		"index": 66,
 		"level": 6,
 		"faction": "necropolis",
 		"abilities":
@@ -289,7 +289,7 @@
 	},
 	"dreadKnight" :
 	{
-		"id": 67,
+		"index": 67,
 		"level": 6,
 		"faction": "necropolis",
 		"abilities":
@@ -321,7 +321,7 @@
 	},
 	"boneDragon" :
 	{
-		"id": 68,
+		"index": 68,
 		"level": 7,
 		"faction": "necropolis",
 		"abilities" :
@@ -347,7 +347,7 @@
 	},
 	"ghostDragon" :
 	{
-		"id": 69,
+		"index": 69,
 		"level": 7,
 		"faction": "necropolis",
 		"abilities":

+ 15 - 15
config/creatures/neutral.json

@@ -2,7 +2,7 @@
 {
 	"goldGolem" :
 	{
-		"id": 116,
+		"index": 116,
 		"level": 4,
 		"faction": "neutral",
 		"abilities":
@@ -33,7 +33,7 @@
 	},
 	"diamondGolem" :
 	{
-		"id": 117,
+		"index": 117,
 		"level": 5,
 		"faction": "neutral",
 		"abilities":
@@ -65,7 +65,7 @@
 	"azureDragon" :
 	{
 		"special" : true,
-		"id": 132,
+		"index": 132,
 		"level": 10,
 		"faction": "neutral",
 		"abilities":
@@ -108,7 +108,7 @@
 	"crystalDragon" :
 	{
 		"special" : true,
-		"id": 133,
+		"index": 133,
 		"level": 10,
 		"faction": "neutral",
 		"abilities":
@@ -135,7 +135,7 @@
 	"fairieDragon" :
 	{
 		"special" : true,
-		"id": 134,
+		"index": 134,
 		"level": 8,
 		"faction": "neutral",
 		"abilities":
@@ -233,7 +233,7 @@
 	"rustDragon" :
 	{
 		"special" : true,
-		"id": 135,
+		"index": 135,
 		"level": 10,
 		"faction": "neutral",
 		"abilities":
@@ -271,7 +271,7 @@
 	"enchanter" :
 	{
 		"special" : true,
-		"id": 136,
+		"index": 136,
 		"level": 6,
 		"extraNames": [ "enchanters" ],
 		"faction": "neutral",
@@ -351,7 +351,7 @@
 	"sharpshooter" :
 	{
 		"special" : true,
-		"id": 137,
+		"index": 137,
 		"level": 4,
 		"extraNames": [ "sharpshooters" ],
 		"faction": "neutral",
@@ -386,7 +386,7 @@
 	},
 	"halfling" :
 	{
-		"id": 138,
+		"index": 138,
 		"level": 1,
 		"faction": "neutral",
 		"graphics" :
@@ -409,7 +409,7 @@
 	},
 	"peasant" :
 	{
-		"id": 139,
+		"index": 139,
 		"level": 1,
 		"faction": "neutral",
 		"graphics" :
@@ -427,7 +427,7 @@
 	},
 	"boar" :
 	{
-		"id": 140,
+		"index": 140,
 		"level": 2,
 		"faction": "neutral",
 		"doubleWide" : true,
@@ -446,7 +446,7 @@
 	},
 	"mummy" :
 	{
-		"id": 141,
+		"index": 141,
 		"level": 3,
 		"faction": "neutral",
 		"abilities":
@@ -471,7 +471,7 @@
 	},
 	"nomad" :
 	{
-		"id": 142,
+		"index": 142,
 		"level": 3,
 		"faction": "neutral",
 		"doubleWide" : true,
@@ -490,7 +490,7 @@
 	},
 	"rogue" :
 	{
-		"id": 143,
+		"index": 143,
 		"level": 2,
 		"faction": "neutral",
 		"graphics" :
@@ -508,7 +508,7 @@
 	},
 	"troll" :
 	{
-		"id": 144,
+		"index": 144,
 		"level": 5,
 		"faction": "neutral",
 		"abilities":

+ 14 - 14
config/creatures/rampart.json

@@ -1,7 +1,7 @@
 {
 	"centaur" :
 	{
-		"id": 14,
+		"index": 14,
 		"level": 1,
 		"faction": "rampart",
 		"upgrades": ["centaurCaptain"],
@@ -23,7 +23,7 @@
 	},
 	"centaurCaptain" :
 	{
-		"id": 15,
+		"index": 15,
 		"level": 1,
 		"faction": "rampart",
 		"graphics" :
@@ -42,7 +42,7 @@
 	},
 	"dwarf" :
 	{
-		"id": 16,
+		"index": 16,
 		"level": 2,
 		"faction": "rampart",
 		"abilities":
@@ -69,7 +69,7 @@
 	},
 	"battleDwarf" :
 	{
-		"id": 17,
+		"index": 17,
 		"level": 2,
 		"faction": "rampart",
 		"abilities":
@@ -95,7 +95,7 @@
 	},
 	"woodElf" :
 	{
-		"id": 18,
+		"index": 18,
 		"level": 3,
 		"faction": "rampart",
 		"upgrades": ["grandElf"],
@@ -119,7 +119,7 @@
 	},
 	"grandElf" :
 	{
-		"id": 19,
+		"index": 19,
 		"level": 3,
 		"faction": "rampart",
 		"abilities": 
@@ -151,7 +151,7 @@
 	},
 	"pegasus" :
 	{
-		"id": 20,
+		"index": 20,
 		"level": 4,
 		"faction": "rampart",
 		"abilities":
@@ -179,7 +179,7 @@
 	},
 	"silverPegasus" :
 	{
-		"id": 21,
+		"index": 21,
 		"level": 4,
 		"faction": "rampart",
 		"abilities":
@@ -205,7 +205,7 @@
 	},
 	"dendroidGuard" :
 	{
-		"id": 22,
+		"index": 22,
 		"level": 5,
 		"faction": "rampart",
 		"abilities":
@@ -233,7 +233,7 @@
 	},
 	"dendroidSoldier" :
 	{
-		"id": 23,
+		"index": 23,
 		"level": 5,
 		"faction": "rampart",
 		"abilities":
@@ -260,7 +260,7 @@
 	},
 	"unicorn" :
 	{
-		"id": 24,
+		"index": 24,
 		"level": 6,
 		"faction": "rampart",
 		"abilities":
@@ -293,7 +293,7 @@
 	},
 	"warUnicorn" :
 	{
-		"id": 25,
+		"index": 25,
 		"level": 6,
 		"faction": "rampart",
 		"abilities":
@@ -326,7 +326,7 @@
 	},
 	"greenDragon" :
 	{
-		"id": 26,
+		"index": 26,
 		"level": 7,
 		"faction": "rampart",
 		"abilities":
@@ -361,7 +361,7 @@
 	},
 	"goldDragon" :
 	{
-		"id": 27,
+		"index": 27,
 		"level": 7,
 		"faction": "rampart",
 		"abilities":

+ 9 - 9
config/creatures/special.json

@@ -6,34 +6,34 @@
 		"faction": "neutral",
 		"disabled" : true,
 		"graphics" : null,
-		"id" : 122
+		"index" : 122
 	},
 	"unused124" :
 	{
 		"faction": "neutral",
 		"disabled" : true,
 		"graphics" : null,
-		"id" : 124
+		"index" : 124
 	},
 	"unused126" :
 	{
 		"faction": "neutral",
 		"disabled" : true,
 		"graphics" : null,
-		"id" : 126
+		"index" : 126
 	},
 	"unused128" :
 	{
 		"faction": "neutral",
 		"disabled" : true,
 		"graphics" : null,
-		"id" : 128
+		"index" : 128
 	},
 
 	"catapult" :
 	{
 		"special" : true,
-		"id": 145,
+		"index": 145,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -54,7 +54,7 @@
 	"ballista" :
 	{
 		"special" : true,
-		"id": 146,
+		"index": 146,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -75,7 +75,7 @@
 	"firstAidTent" :
 	{
 		"special" : true,
-		"id": 147,
+		"index": 147,
 		"level": 0,
 		"faction": "neutral",
 		"abilities": { "heals" : { "type" : "HEALER" } },
@@ -92,7 +92,7 @@
 	"ammoCart" :
 	{
 		"special" : true,
-		"id": 148,
+		"index": 148,
 		"level": 0,
 		"faction": "neutral",
 		"abilities": { "inactive" : { "type" : "NOT_ACTIVE" } },
@@ -109,7 +109,7 @@
 	"arrowTower" :
 	{
 		"special" : true,
-		"id": 149,
+		"index": 149,
 		"level": 0,
 		"faction": "neutral",
 		"abilities": { "shooter" : { "type" : "SHOOTER" } },

+ 14 - 14
config/creatures/stronghold.json

@@ -1,7 +1,7 @@
 {
 	"goblin" :
 	{
-		"id": 84,
+		"index": 84,
 		"level": 1,
 		"extraNames": [ "goblins" ],
 		"faction": "stronghold",
@@ -21,7 +21,7 @@
 	},
 	"hobgoblin" :
 	{
-		"id": 85,
+		"index": 85,
 		"level": 1,
 		"faction": "stronghold",
 		"hasDoubleWeek": true,
@@ -40,7 +40,7 @@
 	},
 	"goblinWolfRider" :
 	{
-		"id": 86,
+		"index": 86,
 		"level": 2,
 		"faction": "stronghold",
 		"upgrades": ["hobgoblinWolfRider"],
@@ -60,7 +60,7 @@
 	},
 	"hobgoblinWolfRider" :
 	{
-		"id": 87,
+		"index": 87,
 		"level": 2,
 		"faction": "stronghold",
 		"abilities":
@@ -86,7 +86,7 @@
 	},
 	"orc" :
 	{
-		"id": 88,
+		"index": 88,
 		"level": 3,
 		"faction": "stronghold",
 		"upgrades": ["orcChieftain"],
@@ -110,7 +110,7 @@
 	},
 	"orcChieftain" :
 	{
-		"id": 89,
+		"index": 89,
 		"level": 3,
 		"faction": "stronghold",
 		"graphics" :
@@ -133,7 +133,7 @@
 	},
 	"ogre" :
 	{
-		"id": 90,
+		"index": 90,
 		"level": 4,
 		"faction": "stronghold",
 		"upgrades": ["ogreMage"],
@@ -152,7 +152,7 @@
 	},
 	"ogreMage" :
 	{
-		"id": 91,
+		"index": 91,
 		"level": 4,
 		"faction": "stronghold",
 		"abilities":
@@ -190,7 +190,7 @@
 	},
 	"roc" :
 	{
-		"id": 92,
+		"index": 92,
 		"level": 5,
 		"faction": "stronghold",
 		"upgrades": ["thunderbird"],
@@ -209,7 +209,7 @@
 	},
 	"thunderbird" :
 	{
-		"id": 93,
+		"index": 93,
 		"level": 5,
 		"faction": "stronghold",
 		"abilities":
@@ -242,7 +242,7 @@
 	},
 	"cyclop" :
 	{
-		"id": 94,
+		"index": 94,
 		"level": 6,
 		"faction": "stronghold",
 		"upgrades": ["cyclopKing"],
@@ -266,7 +266,7 @@
 	},
 	"cyclopKing" :
 	{
-		"id": 95,
+		"index": 95,
 		"level": 6,
 		"faction": "stronghold",
 		"graphics" :
@@ -289,7 +289,7 @@
 	},
 	"behemoth" :
 	{
-		"id": 96,
+		"index": 96,
 		"level": 7,
 		"faction": "stronghold",
 		"abilities":
@@ -316,7 +316,7 @@
 	},
 	"ancientBehemoth" :
 	{
-		"id": 97,
+		"index": 97,
 		"level": 7,
 		"faction": "stronghold",
 		"abilities":

+ 14 - 14
config/creatures/tower.json

@@ -1,7 +1,7 @@
 {
 	"gremlin" :
 	{
-		"id": 28,
+		"index": 28,
 		"level": 1,
 		"extraNames": [ "apprenticeGremlin" ],
 		"faction": "tower",
@@ -23,7 +23,7 @@
 	},
 	"masterGremlin" :
 	{
-		"id": 29,
+		"index": 29,
 		"level": 1,
 		"faction": "tower",
 		"graphics" :
@@ -46,7 +46,7 @@
 	},
 	"stoneGargoyle" :
 	{
-		"id": 30,
+		"index": 30,
 		"level": 2,
 		"faction": "tower",
 		"abilities":
@@ -72,7 +72,7 @@
 	},
 	"obsidianGargoyle" :
 	{
-		"id": 31,
+		"index": 31,
 		"level": 2,
 		"faction": "tower",
 		"abilities":
@@ -97,7 +97,7 @@
 	},
 	"ironGolem" : //FIXME correct ID is stoneGolem, unchangeable due to HOTRAITS.TXT
 	{
-		"id": 32,
+		"index": 32,
 		"level": 3,
 		"faction": "tower",
 		"abilities":
@@ -129,7 +129,7 @@
 	},
 	"stoneGolem" : //FIXME correct ID is ironGolem, unchangeable due to HOTRAITS.TXT
 	{
-		"id": 33,
+		"index": 33,
 		"level": 3,
 		"faction": "tower",
 		"abilities" :
@@ -160,7 +160,7 @@
 	},
 	"mage" :
 	{
-		"id": 34,
+		"index": 34,
 		"level": 4,
 		"faction": "tower",
 		"abilities": 
@@ -192,7 +192,7 @@
 	},
 	"archMage" :
 	{
-		"id": 35,
+		"index": 35,
 		"level": 4,
 		"faction": "tower",
 		"abilities": 
@@ -223,7 +223,7 @@
 	},
 	"genie" :
 	{
-		"id": 36,
+		"index": 36,
 		"level": 5,
 		"faction": "tower",
 		"abilities":
@@ -257,7 +257,7 @@
 	},
 	"masterGenie" :
 	{
-		"id": 37,
+		"index": 37,
 		"level": 5,
 		"faction": "tower",
 		"abilities":
@@ -306,7 +306,7 @@
 	},
 	"naga" :
 	{
-		"id": 38,
+		"index": 38,
 		"level": 6,
 		"faction": "tower",
 		"abilities" :
@@ -332,7 +332,7 @@
 	},
 	"nagaQueen" :
 	{
-		"id": 39,
+		"index": 39,
 		"level": 6,
 		"faction": "tower",
 		"abilities" :
@@ -357,7 +357,7 @@
 	},
 	"giant" :
 	{
-		"id": 40,
+		"index": 40,
 		"level": 7,
 		"faction": "tower",
 		"abilities" :
@@ -383,7 +383,7 @@
 	},
 	"titan" :
 	{
-		"id": 41,
+		"index": 41,
 		"level": 7,
 		"faction": "tower",
 		"abilities" :

+ 76 - 52
config/creatures/wog.json

@@ -1,7 +1,7 @@
 {
 	"supremeArchangel" :
 	{
-		"id": 150,
+		"index": 150,
 		"level": 8,
 		"faction": "castle",
 		"graphics" :
@@ -19,7 +19,7 @@
 	},
 	"diamondDragon" :
 	{
-		"id": 151,
+		"index": 151,
 		"level": 8,
 		"faction": "rampart",
 		"abilities":
@@ -44,7 +44,7 @@
 	},
 	"lordofThunder" :
 	{
-		"id": 152,
+		"index": 152,
 		"level": 8,
 		"faction": "tower",
 		"graphics" :
@@ -67,7 +67,7 @@
 	},
 	"hellBaron" :
 	{
-		"id": 153,
+		"index": 153,
 		"level": 8,
 		"faction": "inferno",
 		"abilities":
@@ -96,7 +96,7 @@
 	},
 	"bloodDragon" :
 	{
-		"id": 154,
+		"index": 154,
 		"level": 8,
 		"faction": "necropolis",
 		"abilities":
@@ -126,7 +126,7 @@
 	},
 	"darknessDragon" :
 	{
-		"id": 155,
+		"index": 155,
 		"level": 8,
 		"faction": "dungeon",
 		"abilities":
@@ -151,7 +151,7 @@
 	},
 	"ghostBehemoth" :
 	{
-		"id": 156,
+		"index": 156,
 		"level": 8,
 		"faction": "stronghold",
 		"graphics" :
@@ -169,7 +169,7 @@
 	},
 	"hellHydra" :
 	{
-		"id": 157,
+		"index": 157,
 		"level": 8,
 		"faction": "fortress",
 		"abilities" : 
@@ -191,7 +191,7 @@
 	},
 	"sacredPhoenix" :
 	{
-		"id": 158,
+		"index": 158,
 		"level": 8,
 		"faction": "conflux",
 		"graphics" :
@@ -209,7 +209,7 @@
 	},
 	"ghost" :
 	{
-		"id": 159,
+		"index": 159,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -228,7 +228,7 @@
 	"godWar" :
 	{
 		"disabled" : true,
-		"id": 160,
+		"index": 160,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -239,7 +239,7 @@
 	"godPeace" :
 	{
 		"disabled" : true,
-		"id": 161,
+		"index": 161,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -250,7 +250,7 @@
 	"godMana" :
 	{
 		"disabled" : true,
-		"id": 162,
+		"index": 162,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -261,7 +261,7 @@
 	"godLore" :
 	{
 		"disabled" : true,
-		"id": 163,
+		"index": 163,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -271,7 +271,7 @@
 	},
 	"minotaurKing2" :// WTF is this? Same ID as Minotaur King from Dungeon
 	{
-		"id": 164,
+		"index": 164,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -289,7 +289,7 @@
 	},
 	"mineralElemental" :
 	{
-		"id": 165,
+		"index": 165,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -307,7 +307,7 @@
 	},
 	"electricityElemental" :
 	{
-		"id": 166,
+		"index": 166,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -325,7 +325,7 @@
 	},
 	"ancientBasilisk" :
 	{
-		"id": 167,
+		"index": 167,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -343,7 +343,7 @@
 	},
 	"gorynych" :
 	{
-		"id": 168,
+		"index": 168,
 		"level": 0,
 		"faction": "neutral",
 		"abilities":
@@ -368,7 +368,7 @@
 	},
 	"warZealot" :
 	{
-		"id": 169,
+		"index": 169,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -391,7 +391,7 @@
 	},
 	"myriad" :
 	{
-		"id": 170,
+		"index": 170,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -414,7 +414,7 @@
 	},
 	"medusaMatriarch" :
 	{
-		"id": 171,
+		"index": 171,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -437,7 +437,7 @@
 	},
 	"nightmare" :
 	{
-		"id": 172,
+		"index": 172,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -455,7 +455,7 @@
 	},
 	"santaGremlin" :
 	{
-		"id": 173,
+		"index": 173,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -478,14 +478,38 @@
 	"paladin1" :
 	{
 		"special" : true,
-		"id": 174,
+		"index": 174,
 		"level": 0,
 		"faction": "neutral",
-		"abilities": [ [ "MAGIC_RESISTANCE", 5, 0, 0 ],
-						[ "CASTS", 1, 0, 0 ] ,
-						[ "CREATURE_ENCHANT_POWER", 1, 0, 0 ] ,
-						[ "CREATURE_SPELL_POWER", 100, 0, 0 ] ,
-						[ "SPELLCASTER", 3, "spell.cure", 0 ] ], //expert cure
+		"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",
@@ -506,7 +530,7 @@
 	"hierophant1" :
 	{
 		"special" : true,
-		"id": 175,
+		"index": 175,
 		"level": 0,
 		"faction": "neutral",
 		"abilities":
@@ -559,7 +583,7 @@
 	"templeGuardian1" :
 	{
 		"special" : true,
-		"id": 176,
+		"index": 176,
 		"level": 0,
 		"faction": "neutral",
 		"abilities":
@@ -612,7 +636,7 @@
 	"succubus1" :
 	{
 		"special" : true,
-		"id": 177,
+		"index": 177,
 		"level": 0,
 		"faction": "neutral",
 		"abilities":
@@ -664,7 +688,7 @@
 	"soulEater1" :
 	{
 		"special" : true,
-		"id": 178,
+		"index": 178,
 		"level": 0,
 		"faction": "neutral",
 		"abilities":
@@ -716,7 +740,7 @@
 	"brute1" :
 	{
 		"special" : true,
-		"id": 179,
+		"index": 179,
 		"level": 0,
 		"faction": "neutral",
 		"abilities":
@@ -768,7 +792,7 @@
 	"ogreLeader1" :
 	{
 		"special" : true,
-		"id": 180,
+		"index": 180,
 		"level": 0,
 		"faction": "neutral",
 		"abilities":
@@ -820,7 +844,7 @@
 	"shaman1" :
 	{
 		"special" : true,
-		"id": 181,
+		"index": 181,
 		"level": 0,
 		"faction": "neutral",
 		"abilities":
@@ -873,7 +897,7 @@
 	"astralSpirit1" :
 	{
 		"special" : true,
-		"id": 182,
+		"index": 182,
 		"level": 0,
 		"faction": "neutral",
 		"abilities":
@@ -925,7 +949,7 @@
 	"paladin2" :
 	{
 		"special" : true,
-		"id": 183,
+		"index": 183,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -941,7 +965,7 @@
 	{
 		"special" : true,
 		"disabled" : true,
-		"id": 184,
+		"index": 184,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -957,7 +981,7 @@
 	{
 		"special" : true,
 		"disabled" : true,
-		"id": 185,
+		"index": 185,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -973,7 +997,7 @@
 	{
 		"special" : true,
 		"disabled" : true,
-		"id": 186,
+		"index": 186,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -989,7 +1013,7 @@
 	{
 		"special" : true,
 		"disabled" : true,
-		"id": 187,
+		"index": 187,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -1005,7 +1029,7 @@
 	{
 		"special" : true,
 		"disabled" : true,
-		"id": 188,
+		"index": 188,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -1021,7 +1045,7 @@
 	{
 		"special" : true,
 		"disabled" : true,
-		"id": 189,
+		"index": 189,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -1037,7 +1061,7 @@
 	{
 		"special" : true,
 		"disabled" : true,
-		"id": 190,
+		"index": 190,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -1053,7 +1077,7 @@
 	{
 		"special" : true,
 		"disabled" : true,
-		"id": 191,
+		"index": 191,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -1067,7 +1091,7 @@
 	},
 	"sylvanCentaur" :
 	{
-		"id": 192,
+		"index": 192,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -1090,7 +1114,7 @@
 	},
 	"sorceresses" :
 	{
-		"id": 193,
+		"index": 193,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -1113,7 +1137,7 @@
 	},
 	"werewolf" :
 	{
-		"id": 194,
+		"index": 194,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -1123,7 +1147,7 @@
 	},
 	"hellSteed" :
 	{
-		"id": 195,
+		"index": 195,
 		"level": 0,
 		"faction": "neutral",
 		"graphics" :
@@ -1142,7 +1166,7 @@
 	},
 	"dracolich" :
 	{
-		"id": 196,
+		"index": 196,
 		"level": 10,
 		"faction": "neutral",
 		"abilities":

+ 84 - 83
config/factions/castle.json

@@ -74,46 +74,46 @@
 				"capitol" : "AVCCASZ0.DEF"
 			},
 			"structures" :
-			[
-				{ "animation" : "TBCSEXT2.def", "x" : 46,  "y" : 119 },
-				{ "id" : 0,  "animation" : "TBCSMAGE.def", "x" : 707, "y" : 166, "z" : 1, "border" : "TOCSMAG1.bmp", "area" : "TZCSMAG1.bmp" },
-				{ "id" : 1,  "animation" : "TBCSMAG2.def", "x" : 706, "y" : 135, "z" : 1, "border" : "TOCSMAG2.bmp", "area" : "TZCSMAG2.bmp" },
-				{ "id" : 2,  "animation" : "TBCSMAG3.def", "x" : 704, "y" : 107, "z" : 1, "border" : "TOCSM301.bmp", "area" : "TZCSM301.bmp" },
-				{ "id" : 3,  "animation" : "TBCSMAG4.def", "x" : 704, "y" : 76,  "z" : 1, "border" : "TOCSM401.bmp", "area" : "TZCSM401.bmp" },
-				{ "id" : 5,  "animation" : "TBCSTVRN.def", "x" : 0,   "y" : 230, "z" : 1, "border" : "TOCSTAV1.bmp", "area" : "TZCSTAV1.bmp" },
-				{ "id" : 6,  "animation" : "TBCSDOCK.def", "x" : 478, "y" : 134, "border" : "TOCSDKMS.bmp", "area" : "TZCSDKMS.bmp" },
-				{ "id" : 7,  "animation" : "TBCSCSTL.def", "x" : 595, "y" : 66,  "border" : "TOCSCAS1.bmp", "area" : "TZCSCAS1.bmp" },
-				{ "id" : 8,  "animation" : "TBCSCAS2.def", "x" : 478, "y" : 66,  "border" : "TOCSCAS2.bmp", "area" : "TZCSCAS2.bmp" },
-				{ "id" : 9,  "animation" : "TBCSCAS3.def", "x" : 478, "y" : 37,  "border" : "TOCSCAS3.bmp", "area" : "TZCSCAS3.bmp" },
-				{ "id" : 10, "animation" : "TBCSHALL.def", "x" : 0,   "y" : 209, "border" : "TOCSH101.bmp", "area" : "TZCSH101.bmp" },
-				{ "id" : 11, "animation" : "TBCSHAL2.def", "x" : 0,   "y" : 176, "border" : "TOCSH201.bmp", "area" : "TZCSH201.bmp" },
-				{ "id" : 12, "animation" : "TBCSHAL3.def", "x" : 0,   "y" : 164, "border" : "TOCSH301.bmp", "area" : "TZCSH301.bmp" },
-				{ "id" : 13, "animation" : "TBCSHAL4.def", "x" : 0,   "y" : 154, "border" : "TOCSH401.bmp", "area" : "TZCSH401.bmp" },
-				{ "id" : 14, "animation" : "TBCSMARK.def", "x" : 413, "y" : 264, "border" : "TOCSMRK1.bmp", "area" : "TZCSMRK1.bmp" },
-				{ "id" : 15, "animation" : "TBCSSILO.def", "x" : 488, "y" : 228, "border" : "TOCSMRK2.bmp", "area" : "TZCSMRK2.bmp" },
-				{ "id" : 16, "animation" : "TBCSBLAK.def", "x" : 213, "y" : 251, "border" : "TOCSBLAK.bmp", "area" : "TZCSBLAK.bmp" },
-				{ "id" : 17, "animation" : "TBCSSPEC.def", "x" : 533, "y" : 71,  "border" : "TOCSLT01.bmp", "area" : "TZCSLT01.bmp" },
-				{ "id" : 18, "animation" : "TBCSHRD1.def", "x" : 76,  "y" : 53,  "border" : "TOCSGR1H.bmp", "area" : "TZCSGR1H.bmp", "hidden" : true },
-				{ "id" : 19, "animation" : "TBCSHRD2.def", "x" : 76,  "y" : 35,  "border" : "TOCSGR2H.bmp", "area" : "TZCSGR2H.bmp", "hidden" : true, "builds" : 18 },
-				{ "id" : 20, "animation" : "TBCSBOAT.def", "x" : 478, "y" : 134, "border" : "TOCSDKMN.bmp", "area" : "TZCSDKMN.bmp", "hidden" : true },
-				{ "id" : 21, "animation" : "TBCSEXT0.def", "x" : 384, "y" : 193, "z" : -2, "border" : "TOCSCAVM.bmp", "area" : "TZCSCAVM.bmp" },
-				{ "id" : 22, "animation" : "TBCSEXT1.def", "x" : 0,   "y" : 198, "z" :  1, "border" : "TOCSTAV2.bmp", "area" : "TZCSTAV2.bmp" },
-				{ "id" : 26, "animation" : "TBCSHOLY.def", "x" : 456, "y" : 109, "z" : -1, "border" : "TOCSHOLY.bmp", "area" : "TZCSHOLY.bmp" },
-				{ "id" : 30, "animation" : "TBCSDW_0.def", "x" : 304, "y" : 92,  "border" : "TOCSPIK1.bmp", "area" : "TZCSPIK1.bmp" },
-				{ "id" : 31, "animation" : "TBCSDW_1.def", "x" : 360, "y" : 130, "border" : "TOCSCRS1.bmp", "area" : "TZCSCRS1.bmp" },
-				{ "id" : 32, "animation" : "TBCSDW_2.def", "x" : 76,  "y" : 57,  "border" : "TOCSGR1N.bmp", "area" : "TZCSGR1N.bmp" },
-				{ "id" : 33, "animation" : "TBCSDW_3.def", "x" : 176, "y" : 101, "border" : "TOCSSWD1.bmp", "area" : "TZCSSWD1.bmp" },
-				{ "id" : 34, "animation" : "TBCSDW_4.def", "x" : 563, "y" : 211, "z" : 1,  "border" : "TOCSMON1.bmp", "area" : "TZCSMON1.bmp" },
-				{ "id" : 35, "animation" : "TBCSDW_5.def", "x" : 174, "y" : 190, "z" : -1, "border" : "TOCSC101.bmp", "area" : "TZCSCAV1.bmp" },
-				{ "id" : 36, "animation" : "TBCSDW_6.def", "x" : 303, "y" : 0,   "z" : -1, "border" : "TOCSANG1.bmp", "area" : "TZCSANG1.bmp" },
-				{ "id" : 37, "animation" : "TBCSUP_0.def", "x" : 304, "y" : 65,  "border" : "TOCSPIK2.bmp", "area" : "TZCSPIK2.bmp" },
-				{ "id" : 38, "animation" : "TBCSUP_1.def", "x" : 360, "y" : 115, "border" : "TOCSCRS2.bmp", "area" : "TZCSCRS2.bmp" },
-				{ "id" : 39, "animation" : "TBCSUP_2.def", "x" : 76,  "y" : 35,  "border" : "TOCSGR2N.bmp", "area" : "TZCSGR2N.bmp" },
-				{ "id" : 40, "animation" : "TBCSUP_3.def", "x" : 176, "y" : 85,  "border" : "TOCSSWD2.bmp", "area" : "TZCSSWD2.bmp" },
-				{ "id" : 41, "animation" : "TBCSUP_4.def", "x" : 563, "y" : 173, "z" : 1,  "border" : "TOCSMON2.bmp", "area" : "TZCSMON2.bmp" },
-				{ "id" : 42, "animation" : "TBCSUP_5.def", "x" : 160, "y" : 190, "z" : -1, "border" : "TOCSCAV2.bmp", "area" : "TZCSCAV2.bmp" },
-				{ "id" : 43, "animation" : "TBCSUP_6.def", "x" : 303, "y" : 0,   "z" : -1, "border" : "TOCSANG2.bmp", "area" : "TZCSANG2.bmp" }
-			],
+			{
+				"extraAnimation": { "animation" : "TBCSEXT2.def", "x" : 46,  "y" : 119 },
+				"mageGuild1":     { "id" : 0,  "animation" : "TBCSMAGE.def", "x" : 707, "y" : 166, "z" : 1, "border" : "TOCSMAG1.bmp", "area" : "TZCSMAG1.bmp" },
+				"mageGuild2":     { "id" : 1,  "animation" : "TBCSMAG2.def", "x" : 706, "y" : 135, "z" : 1, "border" : "TOCSMAG2.bmp", "area" : "TZCSMAG2.bmp" },
+				"mageGuild3":     { "id" : 2,  "animation" : "TBCSMAG3.def", "x" : 704, "y" : 107, "z" : 1, "border" : "TOCSM301.bmp", "area" : "TZCSM301.bmp" },
+				"mageGuild4":     { "id" : 3,  "animation" : "TBCSMAG4.def", "x" : 704, "y" : 76,  "z" : 1, "border" : "TOCSM401.bmp", "area" : "TZCSM401.bmp" },
+				"tavern":         { "id" : 5,  "animation" : "TBCSTVRN.def", "x" : 0,   "y" : 230, "z" : 1, "border" : "TOCSTAV1.bmp", "area" : "TZCSTAV1.bmp" },
+				"shipyard":       { "id" : 6,  "animation" : "TBCSDOCK.def", "x" : 478, "y" : 134, "border" : "TOCSDKMS.bmp", "area" : "TZCSDKMS.bmp" },
+				"fort":           { "id" : 7,  "animation" : "TBCSCSTL.def", "x" : 595, "y" : 66,  "border" : "TOCSCAS1.bmp", "area" : "TZCSCAS1.bmp" },
+				"citadel":        { "id" : 8,  "animation" : "TBCSCAS2.def", "x" : 478, "y" : 66,  "border" : "TOCSCAS2.bmp", "area" : "TZCSCAS2.bmp" },
+				"castle":         { "id" : 9,  "animation" : "TBCSCAS3.def", "x" : 478, "y" : 37,  "border" : "TOCSCAS3.bmp", "area" : "TZCSCAS3.bmp" },
+				"villageHall":    { "id" : 10, "animation" : "TBCSHALL.def", "x" : 0,   "y" : 209, "border" : "TOCSH101.bmp", "area" : "TZCSH101.bmp" },
+				"townHall":       { "id" : 11, "animation" : "TBCSHAL2.def", "x" : 0,   "y" : 176, "border" : "TOCSH201.bmp", "area" : "TZCSH201.bmp" },
+				"cityHall":       { "id" : 12, "animation" : "TBCSHAL3.def", "x" : 0,   "y" : 164, "border" : "TOCSH301.bmp", "area" : "TZCSH301.bmp" },
+				"capitol":        { "id" : 13, "animation" : "TBCSHAL4.def", "x" : 0,   "y" : 154, "border" : "TOCSH401.bmp", "area" : "TZCSH401.bmp" },
+				"marketplace":    { "id" : 14, "animation" : "TBCSMARK.def", "x" : 413, "y" : 264, "border" : "TOCSMRK1.bmp", "area" : "TZCSMRK1.bmp" },
+				"resourceSilo":  { "id" : 15, "animation" : "TBCSSILO.def", "x" : 488, "y" : 228, "border" : "TOCSMRK2.bmp", "area" : "TZCSMRK2.bmp" },
+				"blacksmith":     { "id" : 16, "animation" : "TBCSBLAK.def", "x" : 213, "y" : 251, "border" : "TOCSBLAK.bmp", "area" : "TZCSBLAK.bmp" },
+				"special1":       { "id" : 17, "animation" : "TBCSSPEC.def", "x" : 533, "y" : 71,  "border" : "TOCSLT01.bmp", "area" : "TZCSLT01.bmp" },
+				"horde1":         { "id" : 18, "animation" : "TBCSHRD1.def", "x" : 76,  "y" : 53,  "border" : "TOCSGR1H.bmp", "area" : "TZCSGR1H.bmp", "hidden" : true },
+				"horde1Upgr":     { "id" : 19, "animation" : "TBCSHRD2.def", "x" : 76,  "y" : 35,  "border" : "TOCSGR2H.bmp", "area" : "TZCSGR2H.bmp", "hidden" : true, "builds" : 18 },
+				"ship":           { "id" : 20, "animation" : "TBCSBOAT.def", "x" : 478, "y" : 134, "border" : "TOCSDKMN.bmp", "area" : "TZCSDKMN.bmp", "hidden" : true },
+				"special2":       { "id" : 21, "animation" : "TBCSEXT0.def", "x" : 384, "y" : 193, "z" : -2, "border" : "TOCSCAVM.bmp", "area" : "TZCSCAVM.bmp" },
+				"special3":       { "id" : 22, "animation" : "TBCSEXT1.def", "x" : 0,   "y" : 198, "z" :  1, "border" : "TOCSTAV2.bmp", "area" : "TZCSTAV2.bmp" },
+				"grail":          { "id" : 26, "animation" : "TBCSHOLY.def", "x" : 456, "y" : 109, "z" : -1, "border" : "TOCSHOLY.bmp", "area" : "TZCSHOLY.bmp" },
+				"dwellingLvl1":   { "id" : 30, "animation" : "TBCSDW_0.def", "x" : 304, "y" : 92,  "border" : "TOCSPIK1.bmp", "area" : "TZCSPIK1.bmp" },
+				"dwellingLvl2":   { "id" : 31, "animation" : "TBCSDW_1.def", "x" : 360, "y" : 130, "border" : "TOCSCRS1.bmp", "area" : "TZCSCRS1.bmp" },
+				"dwellingLvl3":   { "id" : 32, "animation" : "TBCSDW_2.def", "x" : 76,  "y" : 57,  "border" : "TOCSGR1N.bmp", "area" : "TZCSGR1N.bmp" },
+				"dwellingLvl4":   { "id" : 33, "animation" : "TBCSDW_3.def", "x" : 176, "y" : 101, "border" : "TOCSSWD1.bmp", "area" : "TZCSSWD1.bmp" },
+				"dwellingLvl5":   { "id" : 34, "animation" : "TBCSDW_4.def", "x" : 563, "y" : 211, "z" : 1,  "border" : "TOCSMON1.bmp", "area" : "TZCSMON1.bmp" },
+				"dwellingLvl6":   { "id" : 35, "animation" : "TBCSDW_5.def", "x" : 174, "y" : 190, "z" : -1, "border" : "TOCSC101.bmp", "area" : "TZCSCAV1.bmp" },
+				"dwellingLvl7":   { "id" : 36, "animation" : "TBCSDW_6.def", "x" : 303, "y" : 0,   "z" : -1, "border" : "TOCSANG1.bmp", "area" : "TZCSANG1.bmp" },
+				"dwellingUpLvl1": { "id" : 37, "animation" : "TBCSUP_0.def", "x" : 304, "y" : 65,  "border" : "TOCSPIK2.bmp", "area" : "TZCSPIK2.bmp" },
+				"dwellingUpLvl2": { "id" : 38, "animation" : "TBCSUP_1.def", "x" : 360, "y" : 115, "border" : "TOCSCRS2.bmp", "area" : "TZCSCRS2.bmp" },
+				"dwellingUpLvl3": { "id" : 39, "animation" : "TBCSUP_2.def", "x" : 76,  "y" : 35,  "border" : "TOCSGR2N.bmp", "area" : "TZCSGR2N.bmp" },
+				"dwellingUpLvl4": { "id" : 40, "animation" : "TBCSUP_3.def", "x" : 176, "y" : 85,  "border" : "TOCSSWD2.bmp", "area" : "TZCSSWD2.bmp" },
+				"dwellingUpLvl5": { "id" : 41, "animation" : "TBCSUP_4.def", "x" : 563, "y" : 173, "z" : 1,  "border" : "TOCSMON2.bmp", "area" : "TZCSMON2.bmp" },
+				"dwellingUpLvl6": { "id" : 42, "animation" : "TBCSUP_5.def", "x" : 160, "y" : 190, "z" : -1, "border" : "TOCSCAV2.bmp", "area" : "TZCSCAV2.bmp" },
+				"dwellingUpLvl7": { "id" : 43, "animation" : "TBCSUP_6.def", "x" : 303, "y" : 0,   "z" : -1, "border" : "TOCSANG2.bmp", "area" : "TZCSANG2.bmp" }
+			},
 			"icons" :
 			{
 				"village" : {"normal" : 18, "built" : 19 },
@@ -150,49 +150,50 @@
 			"moatDamage" : 70,
 
 			"buildings" :
-			[
-				{ "id" : 0 },
-				{ "id" : 1,  "upgrades" : 0 },
-				{ "id" : 2,  "upgrades" : 1 },
-				{ "id" : 3,  "upgrades" : 2 },
-				{ "id" : 4,  "upgrades" : 3 },
-				{ "id" : 5 },
-				{ "id" : 6 },
-				{ "id" : 7 },
-				{ "id" : 8,  "upgrades" : 7 },
-				{ "id" : 9,  "upgrades" : 8 },
-				{ "id" : 10, "mode" : "auto" },
-				{ "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
-				{ "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
-				{ "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
-				{ "id" : 14 },
-				{ "id" : 15, "requires" : [ 14 ] },
-				{ "id" : 16 },
-				{ "id" : 17, "requires" : [ 6 ] },
-				{ "id" : 18, "upgrades" : 32 },
-				{ "id" : 19, "upgrades" : 39, "requires" : [ 18 ], "mode" : "auto" },
-				{ "id" : 20, "upgrades" : 6 },
-				{ "id" : 21, "requires" : [ 33 ] },
-				{ "id" : 22, "upgrades" : 5 },
-				{ "id" : 26, "mode" : "grail"},
-				{ "id" : 27, "requires" : [ 11 ], "mode" : "auto" },
-				{ "id" : 28, "requires" : [ 12 ], "mode" : "auto" },
-				{ "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
-				{ "id" : 30, "requires" : [ 7 ] },
-				{ "id" : 31, "requires" : [ 30 ] },
-				{ "id" : 32, "requires" : [ 33 ] },
-				{ "id" : 33, "requires" : [ 16, 30 ] },
-				{ "id" : 34, "requires" : [ 0, 33 ] },
-				{ "id" : 35, "requires" : [ 21 ] },
-				{ "id" : 36, "requires" : [ 34 ] },
-				{ "id" : 37, "upgrades" : 30 },
-				{ "id" : 38, "upgrades" : 31 },
-				{ "id" : 39, "upgrades" : 32 },
-				{ "id" : 40, "upgrades" : 33 },
-				{ "id" : 41, "upgrades" : 34 },
-				{ "id" : 42, "upgrades" : 35 },
-				{ "id" : 43, "upgrades" : 36 }
-			],
+			{
+				"mageGuild1":     { "id" : 0 },
+				"mageGuild2":     { "id" : 1,  "upgrades" : 0 },
+				"mageGuild3":     { "id" : 2,  "upgrades" : 1 },
+				"mageGuild4":     { "id" : 3,  "upgrades" : 2 },
+				"tavern":         { "id" : 5 },
+				"shipyard":       { "id" : 6 },
+				"fort":           { "id" : 7 },
+				"citadel":        { "id" : 8,  "upgrades" : 7 },
+				"castle":         { "id" : 9,  "upgrades" : 8 },
+				"villageHall":    { "id" : 10, "mode" : "auto" },
+				"townHall":       { "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
+				"cityHall":       { "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
+				"capitol":        { "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
+				"marketplace":    { "id" : 14 },
+				"resourceSilo":  { "id" : 15, "requires" : [ 14 ] },
+				"blacksmith":     { "id" : 16 },
+				"special1":       { "id" : 17, "requires" : [ 6 ] },
+				"horde1":         { "id" : 18, "upgrades" : 32 },
+				"horde1Upgr":     { "id" : 19, "upgrades" : 39, "requires" : [ 18 ], "mode" : "auto" },
+				"ship":           { "id" : 20, "upgrades" : 6 },
+				"special2":       { "id" : 21, "requires" : [ 33 ] },
+				"special3":       { "id" : 22, "upgrades" : 5 },
+				"grail":          { "id" : 26, "mode" : "grail"},
+				"dwellingLvl1":   { "id" : 30, "requires" : [ 7 ] },
+				"dwellingLvl2":   { "id" : 31, "requires" : [ 30 ] },
+				"dwellingLvl3":   { "id" : 32, "requires" : [ 33 ] },
+				"dwellingLvl4":   { "id" : 33, "requires" : [ 16, 30 ] },
+				"dwellingLvl5":   { "id" : 34, "requires" : [ 0, 33 ] },
+				"dwellingLvl6":   { "id" : 35, "requires" : [ 21 ] },
+				"dwellingLvl7":   { "id" : 36, "requires" : [ 34 ] },
+				"dwellingUpLvl1": { "id" : 37, "upgrades" : 30 },
+				"dwellingUpLvl2": { "id" : 38, "upgrades" : 31 },
+				"dwellingUpLvl3": { "id" : 39, "upgrades" : 32 },
+				"dwellingUpLvl4": { "id" : 40, "upgrades" : 33 },
+				"dwellingUpLvl5": { "id" : 41, "upgrades" : 34 },
+				"dwellingUpLvl6": { "id" : 42, "upgrades" : 35 },
+				"dwellingUpLvl7": { "id" : 43, "upgrades" : 36 },
+
+				"horde2" : null,
+				"horde2Upgr" : null,
+				"mageGuild5" : null,
+				"special4" : null
+			},
 
 			"siege" :
 			{

+ 91 - 86
config/factions/conflux.json

@@ -74,50 +74,50 @@
 				"capitol" : "AVCHFORZ.DEF"
 			},
 			"structures" :
-			[
-				{ "animation" : "TBELEXT5.def", "x" : 682, "y" : 183,  "z" : -1, },
-				{ "animation" : "TBELEXT1.def", "x" : 23,  "y" : 218 },
-				{ "id" : 0,  "animation" : "TBELMAGE.def", "x" : 206, "y" : 58,  "z" : 4,  "border" : "TOELMAGE.bmp", "area" : "TZELMAGE.bmp" },
-				{ "id" : 1,  "animation" : "TBELMAG2.def", "x" : 206, "y" : 58,  "z" : 4,  "border" : "TOELMAG2.bmp", "area" : "TZELMAG2.bmp" },
-				{ "id" : 2,  "animation" : "TBELMAG3.def", "x" : 206, "y" : 58,  "z" : 4,  "border" : "TOELMAG3.bmp", "area" : "TZELMAG3.bmp" },
-				{ "id" : 3,  "animation" : "TBELMAG4.def", "x" : 206, "y" : 58,  "z" : 4,  "border" : "TOELMAG4.bmp", "area" : "TZELMAG4.bmp" },
-				{ "id" : 4,  "animation" : "TBELMAG5.def", "x" : 206, "y" : 58,  "z" : 4,  "border" : "TOELMAG5.bmp", "area" : "TZELMAG5.bmp" },
-				{ "id" : 5,  "animation" : "TBELTVRN.def", "x" : 553, "y" : 203, "z" : 1,  "border" : "TOELTVRN.bmp", "area" : "TZELTVRN.bmp" },
-				{ "id" : 6,  "animation" : "TBELDOCK.def", "x" : 239, "y" : 215, "z" : 2,  "border" : "TOELDOCK.bmp", "area" : "TZELDOCK.bmp" },
-				{ "id" : 7,  "animation" : "TBELCSTL.def", "x" : 349, "y" : 101, "z" : -1, "border" : "TOELCSTL.bmp", "area" : "TZELCSTL.bmp" },
-				{ "id" : 8,  "animation" : "TBELCAS2.def", "x" : 349, "y" : 101, "z" : -1, "border" : "TOELCAS2.bmp", "area" : "TZELCAS2.bmp" },
-				{ "id" : 9,  "animation" : "TBELCAS3.def", "x" : 349, "y" : 101, "z" : -1, "border" : "TOELCAS3.bmp", "area" : "TZELCAS3.bmp" },
-				{ "id" : 10, "animation" : "TBELHALL.def", "x" : -1,  "y" : 164, "z" : 5,  "border" : "TOELHALL.bmp", "area" : "TZELHALL.bmp" },
-				{ "id" : 11, "animation" : "TBELHAL2.def", "x" : 0,   "y" : 165, "z" : 5,  "border" : "TOELHAL2.bmp", "area" : "TZELHAL2.bmp" },
-				{ "id" : 12, "animation" : "TBELHAL3.def", "x" : 0,   "y" : 165, "z" : 5,  "border" : "TOELHAL3.bmp", "area" : "TZELHAL3.bmp" },
-				{ "id" : 13, "animation" : "TBELHAL4.def", "x" : 0,   "y" : 164, "z" : 5,  "border" : "TOELHAL4.bmp", "area" : "TZELHAL4.bmp" },
-				{ "id" : 14, "animation" : "TBELMARK.def", "x" : 347, "y" : 216, "z" : 4,  "border" : "TOELMARK.bmp", "area" : "TZELMARK.bmp" },
-				{ "id" : 15, "animation" : "TBELSILO.def", "x" : 372, "y" : 171, "z" : 2,  "border" : "TOELSILO.bmp", "area" : "TZELSILO.bmp" },
-				{ "id" : 16, "animation" : "TBELBLAK.def", "x" : 449, "y" : 151, "z" : 1,  "border" : "TOELBLAK.bmp", "area" : "TZELBLAK.bmp" },
-				{ "id" : 17, "animation" : "TBELSPEC.def", "x" : 284, "y" : 246, "z" : 4,  "border" : "TOELSPEC.bmp", "area" : "TZELSPEC.bmp" },
-				{ "id" : 18, "animation" : "TBELHRD1.def", "x" : 689, "y" : 250, "border" : "TOELHRD1.bmp", "area" : "TZELHRD1.bmp", "hidden" : true },
-				{ "id" : 19, "animation" : "TBELHRD2.def", "x" : 689, "y" : 250, "border" : "TOELHRD2.bmp", "area" : "TZELHRD2.bmp", "hidden" : true, "builds" : 18 },
-				{ "id" : 20, "animation" : "TBELBOAT.def", "x" : 239, "y" : 215, "z" : 2,  "border" : "TOELBOAT.bmp", "area" : "TZELBOAT.bmp", "hidden" : true },
-				{ "id" : 21, "animation" : "TBELEXT6.def", "x" : 104, "y" : 170, "z" : 3,  "border" : "TOELEXT6.bmp", "area" : "TZELEXT6.bmp" },
-				{ "id" : 26, "animation" : "TBELHOLY.def", "x" : 307, "y" : 2,   "border" : "TOELHOLY.bmp", "area" : "TZELHOLY.bmp" },
-				{ "id" : 27, "animation" : "TBELEXT2.def", "x" : 232, "y" : 205 },
-				{ "id" : 28, "animation" : "TBELEXT3.def", "x" : 516, "y" : 223, "z" : 1 },
-				{ "id" : 29, "animation" : "TBELEXT4.def", "x" : 0,   "y" : 252, "z" : 6 },
-				{ "id" : 30, "animation" : "TBELDW_0.def", "x" : 689, "y" : 250, "border" : "TOELDW_0.bmp", "area" : "TZELDW_0.bmp" },
-				{ "id" : 31, "animation" : "TBELDW_1.def", "x" : 630, "y" : 50,  "border" : "TOELDW_1.bmp", "area" : "TZELDW_1.bmp" },
-				{ "id" : 32, "animation" : "TBELDW_2.def", "x" : 709, "y" : 210, "z" : -1, "border" : "TOELDW_2.bmp", "area" : "TZELDW_2.bmp" },
-				{ "id" : 33, "animation" : "TBELDW_3.def", "x" : 108, "y" : 131, "z" : -1, "border" : "TOELDW_3.bmp", "area" : "TZELDW_3.bmp" },
-				{ "id" : 34, "animation" : "TBELDW_4.def", "x" : 264, "y" : 168, "z" : -1, "border" : "TOELDW_4.bmp", "area" : "TZELDW_4.bmp" },
-				{ "id" : 35, "animation" : "TBELDW_5.def", "x" : 394, "y" : 283, "z" : 2,  "border" : "TOELDW_5.bmp", "area" : "TZELDW_5.bmp" },
-				{ "id" : 36, "animation" : "TBELDW_6.def", "x" : 43,  "y" : 16,  "z" : -2, "border" : "TOELDW_6.bmp", "area" : "TZELDW_6.bmp" },
-				{ "id" : 37, "animation" : "TBELUP_0.def", "x" : 689, "y" : 250, "border" : "TOELUP_0.bmp", "area" : "TZELUP_0.bmp" },
-				{ "id" : 38, "animation" : "TBELUP_1.def", "x" : 630, "y" : 50,  "border" : "TOELUP_1.bmp", "area" : "TZELUP_1.bmp" },
-				{ "id" : 39, "animation" : "TBELUP_2.def", "x" : 709, "y" : 210, "z" : -1, "border" : "TOELUP_2.bmp", "area" : "TZELUP_2.bmp" },
-				{ "id" : 40, "animation" : "TBELUP_3.def", "x" : 108, "y" : 131, "z" : -1, "border" : "TOELUP_3.bmp", "area" : "TZELUP_3.bmp" },
-				{ "id" : 41, "animation" : "TBELUP_4.def", "x" : 264, "y" : 168, "z" : -1, "border" : "TOELUP_4.bmp", "area" : "TZELUP_4.bmp" },
-				{ "id" : 42, "animation" : "TBELUP_5.def", "x" : 394, "y" : 283, "z" : 2,  "border" : "TOELUP_5.bmp", "area" : "TZELUP_5.bmp" },
-				{ "id" : 43, "animation" : "TBELUP_6.def", "x" : 43,  "y" : 0,   "z" : -2, "border" : "TOELUP_6.bmp", "area" : "TZELUP_6.bmp" },
-			],
+			{
+				"extraAnimation2":{ "animation" : "TBELEXT5.def", "x" : 682, "y" : 183,  "z" : -1, },
+				"extraAnimation": { "animation" : "TBELEXT1.def", "x" : 23,  "y" : 218 },
+				"mageGuild1":     { "id" : 0,  "animation" : "TBELMAGE.def", "x" : 206, "y" : 58,  "z" : 4,  "border" : "TOELMAGE.bmp", "area" : "TZELMAGE.bmp" },
+				"mageGuild2":     { "id" : 1,  "animation" : "TBELMAG2.def", "x" : 206, "y" : 58,  "z" : 4,  "border" : "TOELMAG2.bmp", "area" : "TZELMAG2.bmp" },
+				"mageGuild3":     { "id" : 2,  "animation" : "TBELMAG3.def", "x" : 206, "y" : 58,  "z" : 4,  "border" : "TOELMAG3.bmp", "area" : "TZELMAG3.bmp" },
+				"mageGuild4":     { "id" : 3,  "animation" : "TBELMAG4.def", "x" : 206, "y" : 58,  "z" : 4,  "border" : "TOELMAG4.bmp", "area" : "TZELMAG4.bmp" },
+				"mageGuild5":     { "id" : 4,  "animation" : "TBELMAG5.def", "x" : 206, "y" : 58,  "z" : 4,  "border" : "TOELMAG5.bmp", "area" : "TZELMAG5.bmp" },
+				"tavern":         { "id" : 5,  "animation" : "TBELTVRN.def", "x" : 553, "y" : 203, "z" : 1,  "border" : "TOELTVRN.bmp", "area" : "TZELTVRN.bmp" },
+				"shipyard":       { "id" : 6,  "animation" : "TBELDOCK.def", "x" : 239, "y" : 215, "z" : 2,  "border" : "TOELDOCK.bmp", "area" : "TZELDOCK.bmp" },
+				"fort":           { "id" : 7,  "animation" : "TBELCSTL.def", "x" : 349, "y" : 101, "z" : -1, "border" : "TOELCSTL.bmp", "area" : "TZELCSTL.bmp" },
+				"citadel":        { "id" : 8,  "animation" : "TBELCAS2.def", "x" : 349, "y" : 101, "z" : -1, "border" : "TOELCAS2.bmp", "area" : "TZELCAS2.bmp" },
+				"castle":         { "id" : 9,  "animation" : "TBELCAS3.def", "x" : 349, "y" : 101, "z" : -1, "border" : "TOELCAS3.bmp", "area" : "TZELCAS3.bmp" },
+				"villageHall":    { "id" : 10, "animation" : "TBELHALL.def", "x" : -1,  "y" : 164, "z" : 5,  "border" : "TOELHALL.bmp", "area" : "TZELHALL.bmp" },
+				"townHall":       { "id" : 11, "animation" : "TBELHAL2.def", "x" : 0,   "y" : 165, "z" : 5,  "border" : "TOELHAL2.bmp", "area" : "TZELHAL2.bmp" },
+				"cityHall":       { "id" : 12, "animation" : "TBELHAL3.def", "x" : 0,   "y" : 165, "z" : 5,  "border" : "TOELHAL3.bmp", "area" : "TZELHAL3.bmp" },
+				"capitol":        { "id" : 13, "animation" : "TBELHAL4.def", "x" : 0,   "y" : 164, "z" : 5,  "border" : "TOELHAL4.bmp", "area" : "TZELHAL4.bmp" },
+				"marketplace":    { "id" : 14, "animation" : "TBELMARK.def", "x" : 347, "y" : 216, "z" : 4,  "border" : "TOELMARK.bmp", "area" : "TZELMARK.bmp" },
+				"resourceSilo":  { "id" : 15, "animation" : "TBELSILO.def", "x" : 372, "y" : 171, "z" : 2,  "border" : "TOELSILO.bmp", "area" : "TZELSILO.bmp" },
+				"blacksmith":     { "id" : 16, "animation" : "TBELBLAK.def", "x" : 449, "y" : 151, "z" : 1,  "border" : "TOELBLAK.bmp", "area" : "TZELBLAK.bmp" },
+				"special1":       { "id" : 17, "animation" : "TBELSPEC.def", "x" : 284, "y" : 246, "z" : 4,  "border" : "TOELSPEC.bmp", "area" : "TZELSPEC.bmp" },
+				"horde1":         { "id" : 18, "animation" : "TBELHRD1.def", "x" : 689, "y" : 250, "border" : "TOELHRD1.bmp", "area" : "TZELHRD1.bmp", "hidden" : true },
+				"horde1Upgr":     { "id" : 19, "animation" : "TBELHRD2.def", "x" : 689, "y" : 250, "border" : "TOELHRD2.bmp", "area" : "TZELHRD2.bmp", "hidden" : true, "builds" : 18 },
+				"ship":           { "id" : 20, "animation" : "TBELBOAT.def", "x" : 239, "y" : 215, "z" : 2,  "border" : "TOELBOAT.bmp", "area" : "TZELBOAT.bmp", "hidden" : true },
+				"special2":       { "id" : 21, "animation" : "TBELEXT6.def", "x" : 104, "y" : 170, "z" : 3,  "border" : "TOELEXT6.bmp", "area" : "TZELEXT6.bmp" },
+				"grail":          { "id" : 26, "animation" : "TBELHOLY.def", "x" : 307, "y" : 2,   "border" : "TOELHOLY.bmp", "area" : "TZELHOLY.bmp" },
+				"extraTownHall":  { "id" : 27, "animation" : "TBELEXT2.def", "x" : 232, "y" : 205 },
+				"extraCityHall":  { "id" : 28, "animation" : "TBELEXT3.def", "x" : 516, "y" : 223, "z" : 1 },
+				"extraCapitol":   { "id" : 29, "animation" : "TBELEXT4.def", "x" : 0,   "y" : 252, "z" : 6 },
+				"dwellingLvl1":   { "id" : 30, "animation" : "TBELDW_0.def", "x" : 689, "y" : 250, "border" : "TOELDW_0.bmp", "area" : "TZELDW_0.bmp" },
+				"dwellingLvl2":   { "id" : 31, "animation" : "TBELDW_1.def", "x" : 630, "y" : 50,  "border" : "TOELDW_1.bmp", "area" : "TZELDW_1.bmp" },
+				"dwellingLvl3":   { "id" : 32, "animation" : "TBELDW_2.def", "x" : 709, "y" : 210, "z" : -1, "border" : "TOELDW_2.bmp", "area" : "TZELDW_2.bmp" },
+				"dwellingLvl4":   { "id" : 33, "animation" : "TBELDW_3.def", "x" : 108, "y" : 131, "z" : -1, "border" : "TOELDW_3.bmp", "area" : "TZELDW_3.bmp" },
+				"dwellingLvl5":   { "id" : 34, "animation" : "TBELDW_4.def", "x" : 264, "y" : 168, "z" : -1, "border" : "TOELDW_4.bmp", "area" : "TZELDW_4.bmp" },
+				"dwellingLvl6":   { "id" : 35, "animation" : "TBELDW_5.def", "x" : 394, "y" : 283, "z" : 2,  "border" : "TOELDW_5.bmp", "area" : "TZELDW_5.bmp" },
+				"dwellingLvl7":   { "id" : 36, "animation" : "TBELDW_6.def", "x" : 43,  "y" : 16,  "z" : -2, "border" : "TOELDW_6.bmp", "area" : "TZELDW_6.bmp" },
+				"dwellingUpLvl1": { "id" : 37, "animation" : "TBELUP_0.def", "x" : 689, "y" : 250, "border" : "TOELUP_0.bmp", "area" : "TZELUP_0.bmp" },
+				"dwellingUpLvl2": { "id" : 38, "animation" : "TBELUP_1.def", "x" : 630, "y" : 50,  "border" : "TOELUP_1.bmp", "area" : "TZELUP_1.bmp" },
+				"dwellingUpLvl3": { "id" : 39, "animation" : "TBELUP_2.def", "x" : 709, "y" : 210, "z" : -1, "border" : "TOELUP_2.bmp", "area" : "TZELUP_2.bmp" },
+				"dwellingUpLvl4": { "id" : 40, "animation" : "TBELUP_3.def", "x" : 108, "y" : 131, "z" : -1, "border" : "TOELUP_3.bmp", "area" : "TZELUP_3.bmp" },
+				"dwellingUpLvl5": { "id" : 41, "animation" : "TBELUP_4.def", "x" : 264, "y" : 168, "z" : -1, "border" : "TOELUP_4.bmp", "area" : "TZELUP_4.bmp" },
+				"dwellingUpLvl6": { "id" : 42, "animation" : "TBELUP_5.def", "x" : 394, "y" : 283, "z" : 2,  "border" : "TOELUP_5.bmp", "area" : "TZELUP_5.bmp" },
+				"dwellingUpLvl7": { "id" : 43, "animation" : "TBELUP_6.def", "x" : 43,  "y" : 0,   "z" : -2, "border" : "TOELUP_6.bmp", "area" : "TZELUP_6.bmp" }
+			},
 			"icons" :
 			{
 				"village" : {"normal" : 34, "built" : 35 },
@@ -154,48 +154,53 @@
 			"moatDamage" : 70,
 
 			"buildings" :
-			[
-				{ "id" : 0 },
-				{ "id" : 1,  "upgrades" : 0 },
-				{ "id" : 2,  "upgrades" : 1 },
-				{ "id" : 3,  "upgrades" : 2 },
-				{ "id" : 4,  "upgrades" : 3 },
-				{ "id" : 5 },
-				{ "id" : 6 },
-				{ "id" : 7 },
-				{ "id" : 8,  "upgrades" : 7 },
-				{ "id" : 9,  "upgrades" : 8 },
-				{ "id" : 10, "mode" : "auto" },
-				{ "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
-				{ "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
-				{ "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
-				{ "id" : 14 },
-				{ "id" : 15, "requires" : [ 14 ] },
-				{ "id" : 16 },
-				{ "id" : 17, "requires" : [ 14 ] },
-				{ "id" : 18, "upgrades" : 30 },
-				{ "id" : 19, "upgrades" : 37, "requires" : [ 18 ], "mode" : "auto" },
-				{ "id" : 20, "upgrades" : 6 },
-				{ "id" : 21, "requires" : [ 0 ] },
-				{ "id" : 26, "mode" : "grail"},
-				{ "id" : 27, "requires" : [ 11 ], "mode" : "auto" },
-				{ "id" : 28, "requires" : [ 12 ], "mode" : "auto" },
-				{ "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
-				{ "id" : 30, "requires" : [ 7 ] },
-				{ "id" : 31, "requires" : [ 30, 0 ] },
-				{ "id" : 32, "requires" : [ 30, 0 ] },
-				{ "id" : 33, "requires" : [ 31 ] },
-				{ "id" : 34, "requires" : [ 32 ] },
-				{ "id" : 35, "requires" : [ 33, 34 ] },
-				{ "id" : 36, "requires" : [ 35 ] },
-				{ "id" : 37, "upgrades" : 30 },
-				{ "id" : 38, "upgrades" : 31 },
-				{ "id" : 39, "upgrades" : 32 },
-				{ "id" : 40, "upgrades" : 33, "requires" : [ 31 ] },
-				{ "id" : 41, "upgrades" : 34 },
-				{ "id" : 42, "upgrades" : 35, "requires" : [ 1 ] },
-				{ "id" : 43, "upgrades" : 36 }
-			],
+			{
+				"mageGuild1":     { "id" : 0 },
+				"mageGuild2":     { "id" : 1,  "upgrades" : 0 },
+				"mageGuild3":     { "id" : 2,  "upgrades" : 1 },
+				"mageGuild4":     { "id" : 3,  "upgrades" : 2 },
+				"mageGuild5":     { "id" : 4,  "upgrades" : 3 },
+				"tavern":         { "id" : 5 },
+				"shipyard":       { "id" : 6 },
+				"fort":           { "id" : 7 },
+				"citadel":        { "id" : 8,  "upgrades" : 7 },
+				"castle":         { "id" : 9,  "upgrades" : 8 },
+				"villageHall":    { "id" : 10, "mode" : "auto" },
+				"townHall":       { "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
+				"cityHall":       { "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
+				"capitol":        { "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
+				"marketplace":    { "id" : 14 },
+				"resourceSilo":  { "id" : 15, "requires" : [ 14 ] },
+				"blacksmith":     { "id" : 16 },
+				"special1":       { "id" : 17, "requires" : [ 14 ] },
+				"horde1":         { "id" : 18, "upgrades" : 30 },
+				"horde1Upgr":     { "id" : 19, "upgrades" : 37, "requires" : [ 18 ], "mode" : "auto" },
+				"ship":           { "id" : 20, "upgrades" : 6 },
+				"special2":       { "id" : 21, "requires" : [ 0 ] },
+				"grail":          { "id" : 26, "mode" : "grail"},
+				"extraTownHall":  { "id" : 27, "requires" : [ 11 ], "mode" : "auto" },
+				"extraCityHall":  { "id" : 28, "requires" : [ 12 ], "mode" : "auto" },
+				"extraCapitol":   { "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
+				"dwellingLvl1":   { "id" : 30, "requires" : [ 7 ] },
+				"dwellingLvl2":   { "id" : 31, "requires" : [ 30, 0 ] },
+				"dwellingLvl3":   { "id" : 32, "requires" : [ 30, 0 ] },
+				"dwellingLvl4":   { "id" : 33, "requires" : [ 31 ] },
+				"dwellingLvl5":   { "id" : 34, "requires" : [ 32 ] },
+				"dwellingLvl6":   { "id" : 35, "requires" : [ 33, 34 ] },
+				"dwellingLvl7":   { "id" : 36, "requires" : [ 35 ] },
+				"dwellingUpLvl1": { "id" : 37, "upgrades" : 30 },
+				"dwellingUpLvl2": { "id" : 38, "upgrades" : 31 },
+				"dwellingUpLvl3": { "id" : 39, "upgrades" : 32 },
+				"dwellingUpLvl4": { "id" : 40, "upgrades" : 33, "requires" : [ 31 ] },
+				"dwellingUpLvl5": { "id" : 41, "upgrades" : 34 },
+				"dwellingUpLvl6": { "id" : 42, "upgrades" : 35, "requires" : [ 1 ] },
+				"dwellingUpLvl7": { "id" : 43, "upgrades" : 36 },
+
+				"horde2" : null,
+				"horde2Upgr" : null,
+				"special3" : null,
+				"special4" : null
+			},
 
 			"siege" :
 			{

+ 83 - 81
config/factions/dungeon.json

@@ -74,45 +74,45 @@
 				"capitol" : "AVCDUNZ0.DEF"
 			},
 			"structures" :
-			[
-				{ "id" : 0,  "animation" : "TBDNMAGE.def", "x" : 164, "y" : 119, "z" : -1, "border" : "TODMAG1.bmp",  "area" : "TZDMAG1.bmp" },
-				{ "id" : 1,  "animation" : "TBDNMAG2.def", "x" : 164, "y" : 97,  "z" : -1, "border" : "TODMAG2.bmp",  "area" : "TZDMAG2.bmp" },
-				{ "id" : 2,  "animation" : "TBDNMAG3.def", "x" : 164, "y" : 77,  "z" : -1, "border" : "TODMAG3.bmp",  "area" : "TZDMAG3.bmp" },
-				{ "id" : 3,  "animation" : "TBDNMAG4.def", "x" : 164, "y" : 61,  "z" : -1, "border" : "TODMAG4.bmp",  "area" : "TZDMAG4.bmp" },
-				{ "id" : 4,  "animation" : "TBDNMAG5.def", "x" : 164, "y" : 15,  "z" : -1, "border" : "TODMAG5.bmp",  "area" : "TZDMAG5.bmp" },
-				{ "id" : 5,  "animation" : "TBDNTVRN.def", "x" : 211, "y" : 297, "border" : "TODTAV.bmp",   "area" : "TZDTAV.bmp" },
-				{ "id" : 7,  "animation" : "TBDNCSTL.def", "x" : 363, "y" : 87,  "z" : 2,  "border" : "TODCAS1.bmp",  "area" : "TZDCAS1.bmp" },
-				{ "id" : 8,  "animation" : "TBDNCAS2.def", "x" : 363, "y" : 87,  "z" : 2,  "border" : "TODCAS2.bmp",  "area" : "TZDCAS2.bmp" },
-				{ "id" : 9,  "animation" : "TBDNCAS3.def", "x" : 363, "y" : 87,  "z" : 2,  "border" : "TODCAS3.bmp",  "area" : "TZDCAS3.bmp" },
-				{ "id" : 10, "animation" : "TBDNHALL.def", "x" : 0,   "y" : 234, "border" : "TODHALL1.bmp", "area" : "TZDHALL1.bmp" },
-				{ "id" : 11, "animation" : "TBDNHAL2.def", "x" : 0,   "y" : 223, "border" : "TODHALL2.bmp", "area" : "TZDHALL2.bmp" },
-				{ "id" : 12, "animation" : "TBDNHAL3.def", "x" : 0,   "y" : 223, "border" : "TODHALL3.bmp", "area" : "TZDHALL3.bmp" },
-				{ "id" : 13, "animation" : "TBDNHAL4.def", "x" : 0,   "y" : 203, "z" : -1, "border" : "TODHALL4.bmp", "area" : "TZDHALL4.bmp" },
-				{ "id" : 14, "animation" : "TBDNMARK.def", "x" : 590, "y" : 318, "z" : -2, "border" : "TODMARK.bmp",  "area" : "TZDMARK.bmp" },
-				{ "id" : 15, "animation" : "TBDNSILO.def", "x" : 624, "y" : 335, "z" : 1,  "border" : "TODSILO.bmp",  "area" : "TZDSILO.bmp" },
-				{ "id" : 16, "animation" : "TBDNBLAK.def", "x" : 544, "y" : 248, "z" : -3, "border" : "TODSMITH.bmp", "area" : "TZDSMITH.bmp" },
-				{ "id" : 17, "animation" : "TBDNSPEC.def", "x" : 746, "y" : 294, "z" : 1,  "border" : "TODART.bmp",   "area" : "TZDART.bmp" },
-				{ "id" : 18, "animation" : "TBDNHRD1.def", "x" : 0,   "y" : 326, "z" : 2,  "border" : "TODTR1HA.bmp", "area" : "TZDTR1HA.bmp", "hidden" : true },
-				{ "id" : 19, "animation" : "TBDNHRD2.def", "x" : 0,   "y" : 300, "z" : 2,  "border" : "TODTR2HA.bmp", "area" : "TZDTR2HA.bmp", "hidden" : true, "builds" : 18 },
-				{ "id" : 21, "animation" : "TBDNEXT0.def", "x" : 131, "y" : 26 , "border" : "TODVOR1A.bmp", "area" : "TZDVOR1A.bmp" },
-				{ "id" : 22, "animation" : "TBDNEXT1.def", "x" : 687, "y" : 177, "border" : "TODPORTA.bmp", "area" : "TZDPORTA.bmp" },
-				{ "id" : 23, "animation" : "TBDNEXT2.def", "x" : 313, "y" : 298, "border" : "TODACAD.bmp",  "area" : "TZDACAD.bmp" },
-				{ "id" : 26, "animation" : "TBDNHOLY.def", "x" : 562, "y" : 24,  "z" : 1,  "border" : "TODHOLY.bmp",  "area" : "TZDHOLY.bmp" },
-				{ "id" : 30, "animation" : "TBDNDW_0.def", "x" : 0,   "y" : 326, "z" : 2,  "border" : "TODTRG1A.bmp", "area" : "TZDTRG1A.bmp" },
-				{ "id" : 31, "animation" : "TBDNDW_1.def", "x" : 0,   "y" : 26,  "border" : "TODHAR1.bmp",  "area" : "TZDHAR1.bmp" },
-				{ "id" : 32, "animation" : "TBDNDW_2.def", "x" : 118, "y" : 308, "z" : 1,  "border" : "TODBEH1A.bmp", "area" : "TZDBEH1A.bmp" },
-				{ "id" : 33, "animation" : "TBDNDW_3.def", "x" : 300, "y" : 29,  "z" : -1, "border" : "TODMED1.bmp",  "area" : "TZDMED1.bmp" },
-				{ "id" : 34, "animation" : "TBDNDW_4.def", "x" : 551, "y" : 186, "z" : 1,  "border" : "TODMIN1.bmp",  "area" : "TZDMIN1.bmp" },
-				{ "id" : 35, "animation" : "TBDNDW_5.def", "x" : 270, "y" : 253, "z" : -1, "border" : "TODMAN1.bmp",  "area" : "TZDMAN1.bmp" },
-				{ "id" : 36, "animation" : "TBDNDW_6.def", "x" : 550, "y" : 0,   "z" : -1, "border" : "TODDRA1A.bmp", "area" : "TZDDRA1A.bmp" },
-				{ "id" : 37, "animation" : "TBDNUP_0.def", "x" : 0,   "y" : 300, "z" : 2,  "border" : "TODTRG2A.bmp", "area" : "TZDTRG2A.bmp" },
-				{ "id" : 38, "animation" : "TBDNUP_1.def", "x" : 0,   "y" : 26,  "border" : "TODHAR2.bmp",  "area" : "TZDHAR2.bmp" },
-				{ "id" : 39, "animation" : "TBDNUP_2.def", "x" : 118, "y" : 256, "z" : 1,  "border" : "TODBEH2A.bmp", "area" : "TZDBEH2A.bmp" },
-				{ "id" : 40, "animation" : "TBDNUP_3.def", "x" : 300, "y" : 29,  "z" : -1, "border" : "TODMED2.bmp",  "area" : "TZDMED2.bmp" },
-				{ "id" : 41, "animation" : "TBDNUP_4.def", "x" : 519, "y" : 172, "z" : 1,  "border" : "TODMIN2.bmp",  "area" : "TZDMIN2.bmp" },
-				{ "id" : 42, "animation" : "TBDNUP_5.def", "x" : 270, "y" : 253, "z" : -1, "border" : "TODMAN2.bmp",  "area" : "TZDMAN2.bmp" },
-				{ "id" : 43, "animation" : "TBDNUP_6.def", "x" : 550, "y" : 0,   "z" : -1, "border" : "TODDRA2A.bmp", "area" : "TZDDRA2A.bmp" },
-			],
+			{
+				"mageGuild1":     { "id" : 0,  "animation" : "TBDNMAGE.def", "x" : 164, "y" : 119, "z" : -1, "border" : "TODMAG1.bmp",  "area" : "TZDMAG1.bmp" },
+				"mageGuild2":     { "id" : 1,  "animation" : "TBDNMAG2.def", "x" : 164, "y" : 97,  "z" : -1, "border" : "TODMAG2.bmp",  "area" : "TZDMAG2.bmp" },
+				"mageGuild3":     { "id" : 2,  "animation" : "TBDNMAG3.def", "x" : 164, "y" : 77,  "z" : -1, "border" : "TODMAG3.bmp",  "area" : "TZDMAG3.bmp" },
+				"mageGuild4":     { "id" : 3,  "animation" : "TBDNMAG4.def", "x" : 164, "y" : 61,  "z" : -1, "border" : "TODMAG4.bmp",  "area" : "TZDMAG4.bmp" },
+				"mageGuild5":     { "id" : 4,  "animation" : "TBDNMAG5.def", "x" : 164, "y" : 15,  "z" : -1, "border" : "TODMAG5.bmp",  "area" : "TZDMAG5.bmp" },
+				"tavern":         { "id" : 5,  "animation" : "TBDNTVRN.def", "x" : 211, "y" : 297, "border" : "TODTAV.bmp",   "area" : "TZDTAV.bmp" },
+				"fort":           { "id" : 7,  "animation" : "TBDNCSTL.def", "x" : 363, "y" : 87,  "z" : 2,  "border" : "TODCAS1.bmp",  "area" : "TZDCAS1.bmp" },
+				"citadel":        { "id" : 8,  "animation" : "TBDNCAS2.def", "x" : 363, "y" : 87,  "z" : 2,  "border" : "TODCAS2.bmp",  "area" : "TZDCAS2.bmp" },
+				"castle":         { "id" : 9,  "animation" : "TBDNCAS3.def", "x" : 363, "y" : 87,  "z" : 2,  "border" : "TODCAS3.bmp",  "area" : "TZDCAS3.bmp" },
+				"villageHall":    { "id" : 10, "animation" : "TBDNHALL.def", "x" : 0,   "y" : 234, "border" : "TODHALL1.bmp", "area" : "TZDHALL1.bmp" },
+				"townHall":       { "id" : 11, "animation" : "TBDNHAL2.def", "x" : 0,   "y" : 223, "border" : "TODHALL2.bmp", "area" : "TZDHALL2.bmp" },
+				"cityHall":       { "id" : 12, "animation" : "TBDNHAL3.def", "x" : 0,   "y" : 223, "border" : "TODHALL3.bmp", "area" : "TZDHALL3.bmp" },
+				"capitol":        { "id" : 13, "animation" : "TBDNHAL4.def", "x" : 0,   "y" : 203, "z" : -1, "border" : "TODHALL4.bmp", "area" : "TZDHALL4.bmp" },
+				"marketplace":    { "id" : 14, "animation" : "TBDNMARK.def", "x" : 590, "y" : 318, "z" : -2, "border" : "TODMARK.bmp",  "area" : "TZDMARK.bmp" },
+				"resourceSilo":  { "id" : 15, "animation" : "TBDNSILO.def", "x" : 624, "y" : 335, "z" : 1,  "border" : "TODSILO.bmp",  "area" : "TZDSILO.bmp" },
+				"blacksmith":     { "id" : 16, "animation" : "TBDNBLAK.def", "x" : 544, "y" : 248, "z" : -3, "border" : "TODSMITH.bmp", "area" : "TZDSMITH.bmp" },
+				"special1":       { "id" : 17, "animation" : "TBDNSPEC.def", "x" : 746, "y" : 294, "z" : 1,  "border" : "TODART.bmp",   "area" : "TZDART.bmp" },
+				"horde1":         { "id" : 18, "animation" : "TBDNHRD1.def", "x" : 0,   "y" : 326, "z" : 2,  "border" : "TODTR1HA.bmp", "area" : "TZDTR1HA.bmp", "hidden" : true },
+				"horde1Upgr":     { "id" : 19, "animation" : "TBDNHRD2.def", "x" : 0,   "y" : 300, "z" : 2,  "border" : "TODTR2HA.bmp", "area" : "TZDTR2HA.bmp", "hidden" : true, "builds" : 18 },
+				"special2":       { "id" : 21, "animation" : "TBDNEXT0.def", "x" : 131, "y" : 26 , "border" : "TODVOR1A.bmp", "area" : "TZDVOR1A.bmp" },
+				"special3":       { "id" : 22, "animation" : "TBDNEXT1.def", "x" : 687, "y" : 177, "border" : "TODPORTA.bmp", "area" : "TZDPORTA.bmp" },
+				"special4":       { "id" : 23, "animation" : "TBDNEXT2.def", "x" : 313, "y" : 298, "border" : "TODACAD.bmp",  "area" : "TZDACAD.bmp" },
+				"grail":          { "id" : 26, "animation" : "TBDNHOLY.def", "x" : 562, "y" : 24,  "z" : 1,  "border" : "TODHOLY.bmp",  "area" : "TZDHOLY.bmp" },
+				"dwellingLvl1":   { "id" : 30, "animation" : "TBDNDW_0.def", "x" : 0,   "y" : 326, "z" : 2,  "border" : "TODTRG1A.bmp", "area" : "TZDTRG1A.bmp" },
+				"dwellingLvl2":   { "id" : 31, "animation" : "TBDNDW_1.def", "x" : 0,   "y" : 26,  "border" : "TODHAR1.bmp",  "area" : "TZDHAR1.bmp" },
+				"dwellingLvl3":   { "id" : 32, "animation" : "TBDNDW_2.def", "x" : 118, "y" : 308, "z" : 1,  "border" : "TODBEH1A.bmp", "area" : "TZDBEH1A.bmp" },
+				"dwellingLvl4":   { "id" : 33, "animation" : "TBDNDW_3.def", "x" : 300, "y" : 29,  "z" : -1, "border" : "TODMED1.bmp",  "area" : "TZDMED1.bmp" },
+				"dwellingLvl5":   { "id" : 34, "animation" : "TBDNDW_4.def", "x" : 551, "y" : 186, "z" : 1,  "border" : "TODMIN1.bmp",  "area" : "TZDMIN1.bmp" },
+				"dwellingLvl6":   { "id" : 35, "animation" : "TBDNDW_5.def", "x" : 270, "y" : 253, "z" : -1, "border" : "TODMAN1.bmp",  "area" : "TZDMAN1.bmp" },
+				"dwellingLvl7":   { "id" : 36, "animation" : "TBDNDW_6.def", "x" : 550, "y" : 0,   "z" : -1, "border" : "TODDRA1A.bmp", "area" : "TZDDRA1A.bmp" },
+				"dwellingUpLvl1": { "id" : 37, "animation" : "TBDNUP_0.def", "x" : 0,   "y" : 300, "z" : 2,  "border" : "TODTRG2A.bmp", "area" : "TZDTRG2A.bmp" },
+				"dwellingUpLvl2": { "id" : 38, "animation" : "TBDNUP_1.def", "x" : 0,   "y" : 26,  "border" : "TODHAR2.bmp",  "area" : "TZDHAR2.bmp" },
+				"dwellingUpLvl3": { "id" : 39, "animation" : "TBDNUP_2.def", "x" : 118, "y" : 256, "z" : 1,  "border" : "TODBEH2A.bmp", "area" : "TZDBEH2A.bmp" },
+				"dwellingUpLvl4": { "id" : 40, "animation" : "TBDNUP_3.def", "x" : 300, "y" : 29,  "z" : -1, "border" : "TODMED2.bmp",  "area" : "TZDMED2.bmp" },
+				"dwellingUpLvl5": { "id" : 41, "animation" : "TBDNUP_4.def", "x" : 519, "y" : 172, "z" : 1,  "border" : "TODMIN2.bmp",  "area" : "TZDMIN2.bmp" },
+				"dwellingUpLvl6": { "id" : 42, "animation" : "TBDNUP_5.def", "x" : 270, "y" : 253, "z" : -1, "border" : "TODMAN2.bmp",  "area" : "TZDMAN2.bmp" },
+				"dwellingUpLvl7": { "id" : 43, "animation" : "TBDNUP_6.def", "x" : 550, "y" : 0,   "z" : -1, "border" : "TODDRA2A.bmp", "area" : "TZDDRA2A.bmp" }
+			},
 			"icons" :
 			{
 				"village" : {"normal" : 28, "built" : 29 },
@@ -149,48 +149,50 @@
 			"moatDamage" : 90,
 
 			"buildings" :
-			[
-				{ "id" : 0 },
-				{ "id" : 1,  "upgrades" : 0 },
-				{ "id" : 2,  "upgrades" : 1 },
-				{ "id" : 3,  "upgrades" : 2 },
-				{ "id" : 4,  "upgrades" : 3 },
-				{ "id" : 5 },
-				{ "id" : 7 },
-				{ "id" : 8,  "upgrades" : 7 },
-				{ "id" : 9,  "upgrades" : 8 },
-				{ "id" : 10, "mode" : "auto" },
-				{ "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
-				{ "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
-				{ "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
-				{ "id" : 14 },
-				{ "id" : 15, "requires" : [ 14 ] },
-				{ "id" : 16 },
-				{ "id" : 17, "requires" : [ 14 ] },
-				{ "id" : 18, "upgrades" : 30 },
-				{ "id" : 19, "upgrades" : 37, "requires" : [ 18 ], "mode" : "auto" },
-				{ "id" : 21, "requires" : [ 0 ] },
-				{ "id" : 22 },
-				{ "id" : 23 },
-				{ "id" : 26, "mode" : "grail"},
-				{ "id" : 27, "requires" : [ 11 ], "mode" : "auto" },
-				{ "id" : 28, "requires" : [ 12 ], "mode" : "auto" },
-				{ "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
-				{ "id" : 30, "requires" : [ 7 ] },
-				{ "id" : 31, "requires" : [ 30 ] },
-				{ "id" : 32, "requires" : [ 30 ] },
-				{ "id" : 33, "requires" : [ 31, 32 ] },
-				{ "id" : 34, "requires" : [ 33 ] },
-				{ "id" : 35, "requires" : [ 33 ] },
-				{ "id" : 36, "requires" : [ 1, 34, 35 ] },
-				{ "id" : 37, "upgrades" : 30 },
-				{ "id" : 38, "upgrades" : 31 },
-				{ "id" : 39, "upgrades" : 32 },
-				{ "id" : 40, "upgrades" : 33 },
-				{ "id" : 41, "upgrades" : 34 },
-				{ "id" : 42, "upgrades" : 35 },
-				{ "id" : 43, "upgrades" : 36, "requires" : [ 2 ] }
-			],
+			{
+				"mageGuild1":     { "id" : 0 },
+				"mageGuild2":     { "id" : 1,  "upgrades" : 0 },
+				"mageGuild3":     { "id" : 2,  "upgrades" : 1 },
+				"mageGuild4":     { "id" : 3,  "upgrades" : 2 },
+				"mageGuild5":     { "id" : 4,  "upgrades" : 3 },
+				"tavern":         { "id" : 5 },
+				"fort":           { "id" : 7 },
+				"citadel":        { "id" : 8,  "upgrades" : 7 },
+				"castle":         { "id" : 9,  "upgrades" : 8 },
+				"villageHall":    { "id" : 10, "mode" : "auto" },
+				"townHall":       { "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
+				"cityHall":       { "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
+				"capitol":        { "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
+				"marketplace":    { "id" : 14 },
+				"resourceSilo":  { "id" : 15, "requires" : [ 14 ] },
+				"blacksmith":     { "id" : 16 },
+				"special1":       { "id" : 17, "requires" : [ 14 ] },
+				"horde1":         { "id" : 18, "upgrades" : 30 },
+				"horde1Upgr":     { "id" : 19, "upgrades" : 37, "requires" : [ 18 ], "mode" : "auto" },
+				"special2":       { "id" : 21, "requires" : [ 0 ] },
+				"special3":       { "id" : 22 },
+				"special4":       { "id" : 23 },
+				"grail":          { "id" : 26, "mode" : "grail"},
+				"dwellingLvl1":   { "id" : 30, "requires" : [ 7 ] },
+				"dwellingLvl2":   { "id" : 31, "requires" : [ 30 ] },
+				"dwellingLvl3":   { "id" : 32, "requires" : [ 30 ] },
+				"dwellingLvl4":   { "id" : 33, "requires" : [ 31, 32 ] },
+				"dwellingLvl5":   { "id" : 34, "requires" : [ 33 ] },
+				"dwellingLvl6":   { "id" : 35, "requires" : [ 33 ] },
+				"dwellingLvl7":   { "id" : 36, "requires" : [ 1, 34, 35 ] },
+				"dwellingUpLvl1": { "id" : 37, "upgrades" : 30 },
+				"dwellingUpLvl2": { "id" : 38, "upgrades" : 31 },
+				"dwellingUpLvl3": { "id" : 39, "upgrades" : 32 },
+				"dwellingUpLvl4": { "id" : 40, "upgrades" : 33 },
+				"dwellingUpLvl5": { "id" : 41, "upgrades" : 34 },
+				"dwellingUpLvl6": { "id" : 42, "upgrades" : 35 },
+				"dwellingUpLvl7": { "id" : 43, "upgrades" : 36, "requires" : [ 2 ] },
+				
+				"horde2" : null,
+				"horde2Upgr" : null,
+				"ship" : null,
+				"shipyard" : null
+			},
 
 			"siege" :
 			{

+ 85 - 83
config/factions/fortress.json

@@ -74,46 +74,46 @@
 				"capitol" : "AVCFORZ0.DEF"
 			},
 			"structures" :
-			[
-				{ "animation" : "TBFREXT2.def", "x" : 372, "y" : 227 },
-				{ "id" : 0,  "animation" : "TBFRMAGE.def", "x" : 0,   "y" : 200, "z" : -1, "border" : "TOFMAG1A.bmp", "area" : "TZFMAG1A.bmp" },
-				{ "id" : 1,  "animation" : "TBFRMAG2.def", "x" : 0,   "y" : 177, "z" : -1, "border" : "TOFMAG2A.bmp", "area" : "TZFMAG2A.bmp" },
-				{ "id" : 2,  "animation" : "TBFRMAG3.def", "x" : 0,   "y" : 135, "z" : -1, "border" : "TOFMAG3A.bmp", "area" : "TZFMAG3A.bmp" },
-				{ "id" : 5,  "animation" : "TBFRTVRN.def", "x" : 634, "y" : 219, "z" : 3,  "border" : "TOFTAVA.bmp",  "area" : "TZFTAVA.bmp" },
-				{ "id" : 6,  "animation" : "TBFRDOCK.def", "x" : 197, "y" : 294, "border" : "TOFDCK2.bmp",  "area" : "TZFDCK2.bmp" },
-				{ "id" : 7,  "animation" : "TBFRCSTL.def", "x" : 368, "y" : 118, "z" : -1, "border" : "TOFCAS1.bmp",  "area" : "TZFCAS1.bmp" },
-				{ "id" : 8,  "animation" : "TBFRCAS2.def", "x" : 368, "y" : 98,  "z" : -1, "border" : "TOFCAS2.bmp",  "area" : "TZFCAS2.bmp" },
-				{ "id" : 9,  "animation" : "TBFRCAS3.def", "x" : 368, "y" : 55,  "z" : -1, "border" : "TOFCAS3.bmp",  "area" : "TZFCAS3.bmp" },
-				{ "id" : 10, "animation" : "TBFRHALL.def", "x" : 166, "y" : 128, "z" : 1,  "border" : "TOFHAL1.bmp",  "area" : "TZFHAL1.bmp" },
-				{ "id" : 11, "animation" : "TBFRHAL2.def", "x" : 166, "y" : 97,  "z" : 1,  "border" : "TOFHAL2.bmp",  "area" : "TZFHAL2.bmp" },
-				{ "id" : 12, "animation" : "TBFRHAL3.def", "x" : 166, "y" : 51,  "z" : 1,  "border" : "TOFHAL3.bmp",  "area" : "TZFHAL3.bmp" },
-				{ "id" : 13, "animation" : "TBFRHAL4.def", "x" : 166, "y" : 2,   "z" : 1,  "border" : "TOFHAL4.bmp",  "area" : "TZFHAL4.bmp" },
-				{ "id" : 14, "animation" : "TBFRMARK.def", "x" : 382, "y" : 219, "z" : 4,  "border" : "TOFMRKAA.bmp", "area" : "TZFMRKAA.bmp" },
-				{ "id" : 15, "animation" : "TBFRSILO.def", "x" : 448, "y" : 210, "z" : 2,  "border" : "TOFMRK2A.bmp", "area" : "TZFMRK2A.bmp" },
-				{ "id" : 16, "animation" : "TBFRBLAK.def", "x" : 360, "y" : 160, "border" : "TOFAIDA.bmp",  "area" : "TZFAIDA.bmp" },
-				{ "id" : 17, "animation" : "TBFRSPEC.def", "x" : 703, "y" : 36,  "border" : "TOFCAGE.bmp",  "area" : "TZFCAGE.bmp" },
-				{ "id" : 18, "animation" : "TBFRHRD1.def", "x" : 641, "y" : 121, "z" : 1,  "border" : "TOFGNL1H.bmp", "area" : "TZFGNL1H.bmp", "hidden" : true },
-				{ "id" : 19, "animation" : "TBFRHRD2.def", "x" : 641, "y" : 68,  "z" : 1,  "border" : "TOFGNL2H.bmp", "area" : "TZFGNL2H.bmp", "hidden" : true, "builds" : 18 },
-				{ "id" : 20, "animation" : "TBFRBOAT.def", "x" : 197, "y" : 294, "z" : 1,  "border" : "TOFDCK1.bmp",  "area" : "TZFDCK1.bmp", "hidden" : true },
-				{ "id" : 21, "animation" : "TBFREXT0.def", "x" : 341, "y" : 174, "border" : "TOFCASD.bmp",  "area" : "TZFCASD.bmp" },
-				{ "id" : 22, "animation" : "TBFREXT1.def", "x" : 349, "y" : 79,  "z" : -2, "border" : "TOFCASA.bmp",  "area" : "TZFCASA.bmp" },
-				{ "id" : 26, "animation" : "TBFRHOLY.def", "x" : 468, "y" : 260, "z" : 5,  "border" : "TOFHLYAA.bmp", "area" : "TZFHLYAA.bmp" },
-				{ "id" : 29, "animation" : "TBFRWTRW.def", "x" : 320, "y" : 141 },
-				{ "id" : 30, "animation" : "TBFRDW_0.def", "x" : 641, "y" : 168, "z" : 1,  "border" : "TOFGNL1.bmp",  "area" : "TZFGNL1.bmp" },
-				{ "id" : 31, "animation" : "TBFRDW_1.def", "x" : 141, "y" : 178, "border" : "TOFLIZ1.bmp",  "area" : "TZFLIZ1.bmp" },
-				{ "id" : 32, "animation" : "TBFRDW_3.def", "x" : 192, "y" : 85,  "border" : "TOFFLY1A.bmp", "area" : "TZFFLY1A.bmp" },
-				{ "id" : 33, "animation" : "TBFRDW_4.def", "x" : 0,   "y" : 292, "border" : "TOFBAS1.bmp",  "area" : "TZFBAS1.bmp" },
-				{ "id" : 34, "animation" : "TBFRDW_2.def", "x" : 15,  "y" : 127, "z" : -2, "border" : "TOFGOR1.bmp",  "area" : "TZFGOR1.bmp" },
-				{ "id" : 35, "animation" : "TBFRDW_5.def", "x" : 0,   "y" : 4,   "border" : "TOFWYV1.bmp",  "area" : "TZFWYV1.bmp" },
-				{ "id" : 36, "animation" : "TBFRDW_6.def", "x" : 612, "y" : 291, "z" : 5,  "border" : "TOFHYD1A.bmp", "area" : "TZFHYD1A.bmp" },
-				{ "id" : 37, "animation" : "TBFRUP_0.def", "x" : 641, "y" : 107, "z" : 1,  "border" : "TOFGNL2.bmp",  "area" : "TZFGNL2.bmp" },
-				{ "id" : 38, "animation" : "TBFRUP_1.def", "x" : 125, "y" : 163, "border" : "TOFLIZ2.bmp",  "area" : "TZFLIZ2.bmp" },
-				{ "id" : 39, "animation" : "TBFRUP_3.def", "x" : 159, "y" : 19,  "border" : "TOFFLY2A.bmp", "area" : "TZFFLY2A.bmp" },
-				{ "id" : 40, "animation" : "TBFRUP_4.def", "x" : 0,   "y" : 257, "border" : "TOFBAS2.bmp",  "area" : "TZFBAS2.bmp" },
-				{ "id" : 41, "animation" : "TBFRUP_2.def", "x" : 15,  "y" : 69,  "z" : -2, "border" : "TOFGOR2.bmp",  "area" : "TZFGOR2.bmp" },
-				{ "id" : 42, "animation" : "TBFRUP_5.def", "x" : 0,   "y" : 4,   "border" : "TOFWYV2.bmp",  "area" : "TZFWYV2.bmp" },
-				{ "id" : 43, "animation" : "TBFRUP_6.def", "x" : 587, "y" : 263, "z" : 5,  "border" : "TOFHYD2A.bmp", "area" : "TZFHYD2A.bmp" }
-			],
+			{
+				"extraAnimation": { "animation" : "TBFREXT2.def", "x" : 372, "y" : 227 },
+				"mageGuild1":     { "id" : 0,  "animation" : "TBFRMAGE.def", "x" : 0,   "y" : 200, "z" : -1, "border" : "TOFMAG1A.bmp", "area" : "TZFMAG1A.bmp" },
+				"mageGuild2":     { "id" : 1,  "animation" : "TBFRMAG2.def", "x" : 0,   "y" : 177, "z" : -1, "border" : "TOFMAG2A.bmp", "area" : "TZFMAG2A.bmp" },
+				"mageGuild3":     { "id" : 2,  "animation" : "TBFRMAG3.def", "x" : 0,   "y" : 135, "z" : -1, "border" : "TOFMAG3A.bmp", "area" : "TZFMAG3A.bmp" },
+				"tavern":         { "id" : 5,  "animation" : "TBFRTVRN.def", "x" : 634, "y" : 219, "z" : 3,  "border" : "TOFTAVA.bmp",  "area" : "TZFTAVA.bmp" },
+				"shipyard":       { "id" : 6,  "animation" : "TBFRDOCK.def", "x" : 197, "y" : 294, "border" : "TOFDCK2.bmp",  "area" : "TZFDCK2.bmp" },
+				"fort":           { "id" : 7,  "animation" : "TBFRCSTL.def", "x" : 368, "y" : 118, "z" : -1, "border" : "TOFCAS1.bmp",  "area" : "TZFCAS1.bmp" },
+				"citadel":        { "id" : 8,  "animation" : "TBFRCAS2.def", "x" : 368, "y" : 98,  "z" : -1, "border" : "TOFCAS2.bmp",  "area" : "TZFCAS2.bmp" },
+				"castle":         { "id" : 9,  "animation" : "TBFRCAS3.def", "x" : 368, "y" : 55,  "z" : -1, "border" : "TOFCAS3.bmp",  "area" : "TZFCAS3.bmp" },
+				"villageHall":    { "id" : 10, "animation" : "TBFRHALL.def", "x" : 166, "y" : 128, "z" : 1,  "border" : "TOFHAL1.bmp",  "area" : "TZFHAL1.bmp" },
+				"townHall":       { "id" : 11, "animation" : "TBFRHAL2.def", "x" : 166, "y" : 97,  "z" : 1,  "border" : "TOFHAL2.bmp",  "area" : "TZFHAL2.bmp" },
+				"cityHall":       { "id" : 12, "animation" : "TBFRHAL3.def", "x" : 166, "y" : 51,  "z" : 1,  "border" : "TOFHAL3.bmp",  "area" : "TZFHAL3.bmp" },
+				"capitol":        { "id" : 13, "animation" : "TBFRHAL4.def", "x" : 166, "y" : 2,   "z" : 1,  "border" : "TOFHAL4.bmp",  "area" : "TZFHAL4.bmp" },
+				"marketplace":    { "id" : 14, "animation" : "TBFRMARK.def", "x" : 382, "y" : 219, "z" : 4,  "border" : "TOFMRKAA.bmp", "area" : "TZFMRKAA.bmp" },
+				"resourceSilo":  { "id" : 15, "animation" : "TBFRSILO.def", "x" : 448, "y" : 210, "z" : 2,  "border" : "TOFMRK2A.bmp", "area" : "TZFMRK2A.bmp" },
+				"blacksmith":     { "id" : 16, "animation" : "TBFRBLAK.def", "x" : 360, "y" : 160, "border" : "TOFAIDA.bmp",  "area" : "TZFAIDA.bmp" },
+				"special1":       { "id" : 17, "animation" : "TBFRSPEC.def", "x" : 703, "y" : 36,  "border" : "TOFCAGE.bmp",  "area" : "TZFCAGE.bmp" },
+				"horde1":         { "id" : 18, "animation" : "TBFRHRD1.def", "x" : 641, "y" : 121, "z" : 1,  "border" : "TOFGNL1H.bmp", "area" : "TZFGNL1H.bmp", "hidden" : true },
+				"horde1Upgr":     { "id" : 19, "animation" : "TBFRHRD2.def", "x" : 641, "y" : 68,  "z" : 1,  "border" : "TOFGNL2H.bmp", "area" : "TZFGNL2H.bmp", "hidden" : true, "builds" : 18 },
+				"ship":           { "id" : 20, "animation" : "TBFRBOAT.def", "x" : 197, "y" : 294, "z" : 1,  "border" : "TOFDCK1.bmp",  "area" : "TZFDCK1.bmp", "hidden" : true },
+				"special2":       { "id" : 21, "animation" : "TBFREXT0.def", "x" : 341, "y" : 174, "border" : "TOFCASD.bmp",  "area" : "TZFCASD.bmp" },
+				"special3":       { "id" : 22, "animation" : "TBFREXT1.def", "x" : 349, "y" : 79,  "z" : -2, "border" : "TOFCASA.bmp",  "area" : "TZFCASA.bmp" },
+				"grail":          { "id" : 26, "animation" : "TBFRHOLY.def", "x" : 468, "y" : 260, "z" : 5,  "border" : "TOFHLYAA.bmp", "area" : "TZFHLYAA.bmp" },
+				"extraCapitol":   { "id" : 29, "animation" : "TBFRWTRW.def", "x" : 320, "y" : 141 },
+				"dwellingLvl1":   { "id" : 30, "animation" : "TBFRDW_0.def", "x" : 641, "y" : 168, "z" : 1,  "border" : "TOFGNL1.bmp",  "area" : "TZFGNL1.bmp" },
+				"dwellingLvl2":   { "id" : 31, "animation" : "TBFRDW_1.def", "x" : 141, "y" : 178, "border" : "TOFLIZ1.bmp",  "area" : "TZFLIZ1.bmp" },
+				"dwellingLvl3":   { "id" : 32, "animation" : "TBFRDW_3.def", "x" : 192, "y" : 85,  "border" : "TOFFLY1A.bmp", "area" : "TZFFLY1A.bmp" },
+				"dwellingLvl4":   { "id" : 33, "animation" : "TBFRDW_4.def", "x" : 0,   "y" : 292, "border" : "TOFBAS1.bmp",  "area" : "TZFBAS1.bmp" },
+				"dwellingLvl5":   { "id" : 34, "animation" : "TBFRDW_2.def", "x" : 15,  "y" : 127, "z" : -2, "border" : "TOFGOR1.bmp",  "area" : "TZFGOR1.bmp" },
+				"dwellingLvl6":   { "id" : 35, "animation" : "TBFRDW_5.def", "x" : 0,   "y" : 4,   "border" : "TOFWYV1.bmp",  "area" : "TZFWYV1.bmp" },
+				"dwellingLvl7":   { "id" : 36, "animation" : "TBFRDW_6.def", "x" : 612, "y" : 291, "z" : 5,  "border" : "TOFHYD1A.bmp", "area" : "TZFHYD1A.bmp" },
+				"dwellingUpLvl1": { "id" : 37, "animation" : "TBFRUP_0.def", "x" : 641, "y" : 107, "z" : 1,  "border" : "TOFGNL2.bmp",  "area" : "TZFGNL2.bmp" },
+				"dwellingUpLvl2": { "id" : 38, "animation" : "TBFRUP_1.def", "x" : 125, "y" : 163, "border" : "TOFLIZ2.bmp",  "area" : "TZFLIZ2.bmp" },
+				"dwellingUpLvl3": { "id" : 39, "animation" : "TBFRUP_3.def", "x" : 159, "y" : 19,  "border" : "TOFFLY2A.bmp", "area" : "TZFFLY2A.bmp" },
+				"dwellingUpLvl4": { "id" : 40, "animation" : "TBFRUP_4.def", "x" : 0,   "y" : 257, "border" : "TOFBAS2.bmp",  "area" : "TZFBAS2.bmp" },
+				"dwellingUpLvl5": { "id" : 41, "animation" : "TBFRUP_2.def", "x" : 15,  "y" : 69,  "z" : -2, "border" : "TOFGOR2.bmp",  "area" : "TZFGOR2.bmp" },
+				"dwellingUpLvl6": { "id" : 42, "animation" : "TBFRUP_5.def", "x" : 0,   "y" : 4,   "border" : "TOFWYV2.bmp",  "area" : "TZFWYV2.bmp" },
+				"dwellingUpLvl7": { "id" : 43, "animation" : "TBFRUP_6.def", "x" : 587, "y" : 263, "z" : 5,  "border" : "TOFHYD2A.bmp", "area" : "TZFHYD2A.bmp" }
+			},
 			"icons" :
 			{
 				"village" : {"normal" : 32, "built" : 33 },
@@ -149,49 +149,51 @@
 			"moatDamage" : 90,
 
 			"buildings" :
-			[
-				{ "id" : 0 },
-				{ "id" : 1,  "upgrades" : 0 },
-				{ "id" : 2,  "upgrades" : 1 },
-				{ "id" : 3,  "upgrades" : 2 },
-				{ "id" : 4,  "upgrades" : 3 },
-				{ "id" : 5 },
-				{ "id" : 6 },
-				{ "id" : 7 },
-				{ "id" : 8,  "upgrades" : 7 },
-				{ "id" : 9,  "upgrades" : 8 },
-				{ "id" : 10, "mode" : "auto" },
-				{ "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
-				{ "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
-				{ "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
-				{ "id" : 14 },
-				{ "id" : 15, "requires" : [ 14 ] },
-				{ "id" : 16 },
-				{ "id" : 17, "requires" : [ 11, 21 ] },
-				{ "id" : 18, "upgrades" : 30 },
-				{ "id" : 19, "upgrades" : 37, "requires" : [ 18 ], "mode" : "auto" },
-				{ "id" : 20, "upgrades" : 6 },
-				{ "id" : 21, "requires" : [ 7 ] },
-				{ "id" : 22, "requires" : [ 21 ] },
-				{ "id" : 26, "mode" : "grail"},
-				{ "id" : 27, "requires" : [ 11 ], "mode" : "auto" },
-				{ "id" : 28, "requires" : [ 12 ], "mode" : "auto" },
-				{ "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
-				{ "id" : 30, "requires" : [ 7 ] },
-				{ "id" : 31, "requires" : [ 30 ] },
-				{ "id" : 32, "requires" : [ 30 ] },
-				{ "id" : 33, "requires" : [ 32 ] },
-				{ "id" : 34, "requires" : [ 31, 32 ] },
-				{ "id" : 35, "requires" : [ 31 ] },
-				{ "id" : 36, "requires" : [ 33, 35 ] },
-				{ "id" : 37, "upgrades" : 30, "requires" : [ 5 ] },
-				{ "id" : 38, "upgrades" : 31 },
-				{ "id" : 39, "upgrades" : 32 },
-				{ "id" : 40, "upgrades" : 33 },
-				{ "id" : 41, "upgrades" : 34, "requires" : [ 15 ] },
-				{ "id" : 42, "upgrades" : 35 },
-				{ "id" : 43, "upgrades" : 36 }
-			],
+			{
+				"mageGuild1":     { "id" : 0 },
+				"mageGuild2":     { "id" : 1,  "upgrades" : 0 },
+				"mageGuild3":     { "id" : 2,  "upgrades" : 1 },
+				"tavern":         { "id" : 5 },
+				"shipyard":       { "id" : 6 },
+				"fort":           { "id" : 7 },
+				"citadel":        { "id" : 8,  "upgrades" : 7 },
+				"castle":         { "id" : 9,  "upgrades" : 8 },
+				"villageHall":    { "id" : 10, "mode" : "auto" },
+				"townHall":       { "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
+				"cityHall":       { "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
+				"capitol":        { "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
+				"marketplace":    { "id" : 14 },
+				"resourceSilo":  { "id" : 15, "requires" : [ 14 ] },
+				"blacksmith":     { "id" : 16 },
+				"special1":       { "id" : 17, "requires" : [ 11, 21 ] },
+				"horde1":         { "id" : 18, "upgrades" : 30 },
+				"horde1Upgr":     { "id" : 19, "upgrades" : 37, "requires" : [ 18 ], "mode" : "auto" },
+				"ship":           { "id" : 20, "upgrades" : 6 },
+				"special2":       { "id" : 21, "requires" : [ 7 ] },
+				"special3":       { "id" : 22, "requires" : [ 21 ] },
+				"grail":          { "id" : 26, "mode" : "grail"},
+				"extraCapitol":   { "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
+				"dwellingLvl1":   { "id" : 30, "requires" : [ 7 ] },
+				"dwellingLvl2":   { "id" : 31, "requires" : [ 30 ] },
+				"dwellingLvl3":   { "id" : 32, "requires" : [ 30 ] },
+				"dwellingLvl4":   { "id" : 33, "requires" : [ 32 ] },
+				"dwellingLvl5":   { "id" : 34, "requires" : [ 31, 32 ] },
+				"dwellingLvl6":   { "id" : 35, "requires" : [ 31 ] },
+				"dwellingLvl7":   { "id" : 36, "requires" : [ 33, 35 ] },
+				"dwellingUpLvl1": { "id" : 37, "upgrades" : 30, "requires" : [ 5 ] },
+				"dwellingUpLvl2": { "id" : 38, "upgrades" : 31 },
+				"dwellingUpLvl3": { "id" : 39, "upgrades" : 32 },
+				"dwellingUpLvl4": { "id" : 40, "upgrades" : 33 },
+				"dwellingUpLvl5": { "id" : 41, "upgrades" : 34, "requires" : [ 15 ] },
+				"dwellingUpLvl6": { "id" : 42, "upgrades" : 35 },
+				"dwellingUpLvl7": { "id" : 43, "upgrades" : 36 },
+
+				"horde2" : null,
+				"horde2Upgr" : null,
+				"mageGuild4" : null,
+				"mageGuild5" : null,
+				"special4" : null
+			},
 
 			"siege" :
 			{

+ 84 - 84
config/factions/inferno.json

@@ -74,46 +74,46 @@
 				"capitol" : "AVCINFZ0.DEF"
 			},
 			"structures" :
-			[
-				{ "id" : 0,  "animation" : "TBINMAGE.def", "x" : 667, "y" : 127, "border" : "TOIMAG1A.bmp", "area" : "TZIMAG1A.bmp" },
-				{ "id" : 1,  "animation" : "TBINMAG2.def", "x" : 667, "y" : 101, "border" : "TOIMAG2A.bmp", "area" : "TZIMAG2A.bmp" },
-				{ "id" : 2,  "animation" : "TBINMAG3.def", "x" : 667, "y" : 83,  "border" : "TOIMAG3A.bmp", "area" : "TZIMAG3A.bmp" },
-				{ "id" : 3,  "animation" : "TBINMAG4.def", "x" : 667, "y" : 56,  "border" : "TOIMAG4A.bmp", "area" : "TZIMAG4A.bmp" },
-				{ "id" : 4,  "animation" : "TBINMAG5.def", "x" : 667, "y" : 35,  "border" : "TOIMAG5A.bmp", "area" : "TZIMAG5A.bmp" },
-				{ "id" : 5,  "animation" : "TBINTVRN.def", "x" : 105, "y" : 219, "z" : 1,  "border" : "TOITAV.bmp",   "area" : "TZITAV.bmp" },
-				{ "id" : 7,  "animation" : "TBINCSTL.def", "x" : 222, "y" : 44,  "border" : "TOICAS2A.bmp", "area" : "TZICAS2A.bmp" },
-				{ "id" : 8,  "animation" : "TBINCAS2.def", "x" : 222, "y" : 44,  "border" : "TOICAS1A.bmp", "area" : "TZICAS1A.bmp" },
-				{ "id" : 9,  "animation" : "TBINCAS3.def", "x" : 222, "y" : 18,  "border" : "TOICAS3A.bmp", "area" : "TZICAS3A.bmp" },
-				{ "id" : 10, "animation" : "TBINHALL.def", "x" : 0,   "y" : 174, "border" : "TOIHAL1.bmp",  "area" : "TZIHAL1.bmp"  },
-				{ "id" : 11, "animation" : "TBINHAL2.def", "x" : 0,   "y" : 174, "border" : "TOIHAL2.bmp",  "area" : "TZIHAL2.bmp"  },
-				{ "id" : 12, "animation" : "TBINHAL3.def", "x" : 0,   "y" : 174, "border" : "TOIHAL3.bmp",  "area" : "TZIHAL3.bmp"  },
-				{ "id" : 13, "animation" : "TBINHAL4.def", "x" : 0,   "y" : 131, "border" : "TOIHAL4.bmp",  "area" : "TZIHAL4.bmp"  },
-				{ "id" : 14, "animation" : "TBINMARK.def", "x" : 511, "y" : 301, "z" : 4,  "border" : "TOIMAR1.bmp",  "area" : "TZIMAR1.bmp" },
-				{ "id" : 15, "animation" : "TBINSILO.def", "x" : 497, "y" : 337, "z" : 5,  "border" : "TOIMAR2.bmp",  "area" : "TZIMAR2.bmp" },
-				{ "id" : 16, "animation" : "TBINBLAK.def", "x" : 684, "y" : 253, "z" : 1,  "border" : "TOIBLKA.bmp",  "area" : "TZIBLKA.bmp" },
-				{ "id" : 18, "animation" : "TBINHRD1.def", "x" : 614, "y" : 256, "border" : "TOIMP1HA.bmp", "area" : "TZIMP1HA.bmp", "hidden" : true },
-				{ "id" : 19, "animation" : "TBINHRD2.def", "x" : 614, "y" : 221, "border" : "TOIMP2HA.bmp", "area" : "TZIMP2HA.bmp", "hidden" : true, "builds" : 18 },
-				{ "id" : 21, "animation" : "TBINEXT0.def", "x" : 297, "y" : 0,   "z" : -1, "border" : "TOICAB1A.bmp", "area" : "TZICAB1A.bmp" },
-				{ "id" : 22, "animation" : "TBINEXT1.def", "x" : 227, "y" : 174, "z" : 2,  "border" : "TOICASGA.bmp", "area" : "TZICASGA.bmp" },
-				{ "id" : 23, "animation" : "TBINEXT2.def", "x" : 593, "y" : 104, "border" : "TOIPAIN.bmp",  "area" : "TZIPAIN.bmp"  },
-				{ "id" : 24, "animation" : "TBINHRD3.def", "x" : 10,  "y" : 301, "border" : "TOIHND1H.bmp", "area" : "TZIHND1H.bmp", "hidden" : true },
-				{ "id" : 25, "animation" : "TBINHRD4.def", "x" : 9,   "y" : 273, "border" : "TOIHND2H.bmp", "area" : "TZIHND2H.bmp", "hidden" : true, "builds" : 24 },
-				{ "id" : 26, "animation" : "TBINHOLY.def", "x" : 24,  "y" : 10,  "z" : -1, "border" : "TOIHOLY.bmp",  "area" : "TZIHOLY.bmp" },
-				{ "id" : 30, "animation" : "TBINDW_0.def", "x" : 614, "y" : 256, "border" : "TOIMP1A.bmp",  "area" : "TZIMP1A.bmp"  },
-				{ "id" : 31, "animation" : "TBINDW_1.def", "x" : 187, "y" : 248, "z" : 4,  "border" : "TOIGOG1A.bmp", "area" : "TZIGOG1A.bmp" },
-				{ "id" : 32, "animation" : "TBINDW_2.def", "x" : 9,   "y" : 325, "border" : "TOIHND1.bmp",  "area" : "TZIHND1.bmp"  },
-				{ "id" : 33, "animation" : "TBINDW_3.def", "x" : 414, "y" : 204, "z" : 2,  "border" : "TOIDMN1.bmp",  "area" : "TZIDMN1.bmp" },
-				{ "id" : 34, "animation" : "TBINDW_4.def", "x" : 359, "y" : 296, "z" : 3,  "border" : "TOIPIT1.bmp",  "area" : "TZIPIT1.bmp" },
-				{ "id" : 35, "animation" : "TBINDW_5.def", "x" : 220, "y" : 350, "z" : 5,  "border" : "TOIEFR1.bmp",  "area" : "TZIEFR1.bmp" },
-				{ "id" : 36, "animation" : "TBINDW_6.def", "x" : 420, "y" : 153, "z" : -1, "border" : "TOIDVL1.bmp",  "area" : "TZIDVL1.bmp" },
-				{ "id" : 37, "animation" : "TBINUP_0.def", "x" : 614, "y" : 221, "border" : "TOIMP2A.bmp",  "area" : "TZIMP2A.bmp"  },
-				{ "id" : 38, "animation" : "TBINUP_1.def", "x" : 187, "y" : 212, "z" : 4,  "border" : "TOIGOG2A.bmp", "area" : "TZIGOG2A.bmp" },
-				{ "id" : 39, "animation" : "TBINUP_2.def", "x" : 9,   "y" : 273, "border" : "TOIHND2.bmp",  "area" : "TZIHND2.bmp"  },
-				{ "id" : 40, "animation" : "TBINUP_3.def", "x" : 412, "y" : 197, "z" : 2,  "border" : "TOIDMN2.bmp",  "area" : "TZIDMN2.bmp" },
-				{ "id" : 41, "animation" : "TBINUP_4.def", "x" : 359, "y" : 244, "z" : 3,  "border" : "TOIPIT2.bmp",  "area" : "TZIPIT2.bmp" },
-				{ "id" : 42, "animation" : "TBINUP_5.def", "x" : 220, "y" : 282, "z" : 5,  "border" : "TOIEFR2.bmp",  "area" : "TZIEFR2.bmp" },
-				{ "id" : 43, "animation" : "TBINUP_6.def", "x" : 420, "y" : 105, "z" : -1, "border" : "TOIDVL2.bmp",  "area" : "TZIDVL2.bmp" }
-			],
+			{
+				"mageGuild1":     { "id" : 0,  "animation" : "TBINMAGE.def", "x" : 667, "y" : 127, "border" : "TOIMAG1A.bmp", "area" : "TZIMAG1A.bmp" },
+				"mageGuild2":     { "id" : 1,  "animation" : "TBINMAG2.def", "x" : 667, "y" : 101, "border" : "TOIMAG2A.bmp", "area" : "TZIMAG2A.bmp" },
+				"mageGuild3":     { "id" : 2,  "animation" : "TBINMAG3.def", "x" : 667, "y" : 83,  "border" : "TOIMAG3A.bmp", "area" : "TZIMAG3A.bmp" },
+				"mageGuild4":     { "id" : 3,  "animation" : "TBINMAG4.def", "x" : 667, "y" : 56,  "border" : "TOIMAG4A.bmp", "area" : "TZIMAG4A.bmp" },
+				"mageGuild5":     { "id" : 4,  "animation" : "TBINMAG5.def", "x" : 667, "y" : 35,  "border" : "TOIMAG5A.bmp", "area" : "TZIMAG5A.bmp" },
+				"tavern":         { "id" : 5,  "animation" : "TBINTVRN.def", "x" : 105, "y" : 219, "z" : 1,  "border" : "TOITAV.bmp",   "area" : "TZITAV.bmp" },
+				"fort":           { "id" : 7,  "animation" : "TBINCSTL.def", "x" : 222, "y" : 44,  "border" : "TOICAS2A.bmp", "area" : "TZICAS2A.bmp" },
+				"citadel":        { "id" : 8,  "animation" : "TBINCAS2.def", "x" : 222, "y" : 44,  "border" : "TOICAS1A.bmp", "area" : "TZICAS1A.bmp" },
+				"castle":         { "id" : 9,  "animation" : "TBINCAS3.def", "x" : 222, "y" : 18,  "border" : "TOICAS3A.bmp", "area" : "TZICAS3A.bmp" },
+				"villageHall":    { "id" : 10, "animation" : "TBINHALL.def", "x" : 0,   "y" : 174, "border" : "TOIHAL1.bmp",  "area" : "TZIHAL1.bmp"  },
+				"townHall":       { "id" : 11, "animation" : "TBINHAL2.def", "x" : 0,   "y" : 174, "border" : "TOIHAL2.bmp",  "area" : "TZIHAL2.bmp"  },
+				"cityHall":       { "id" : 12, "animation" : "TBINHAL3.def", "x" : 0,   "y" : 174, "border" : "TOIHAL3.bmp",  "area" : "TZIHAL3.bmp"  },
+				"capitol":        { "id" : 13, "animation" : "TBINHAL4.def", "x" : 0,   "y" : 131, "border" : "TOIHAL4.bmp",  "area" : "TZIHAL4.bmp"  },
+				"marketplace":    { "id" : 14, "animation" : "TBINMARK.def", "x" : 511, "y" : 301, "z" : 4,  "border" : "TOIMAR1.bmp",  "area" : "TZIMAR1.bmp" },
+				"resourceSilo":  { "id" : 15, "animation" : "TBINSILO.def", "x" : 497, "y" : 337, "z" : 5,  "border" : "TOIMAR2.bmp",  "area" : "TZIMAR2.bmp" },
+				"blacksmith":     { "id" : 16, "animation" : "TBINBLAK.def", "x" : 684, "y" : 253, "z" : 1,  "border" : "TOIBLKA.bmp",  "area" : "TZIBLKA.bmp" },
+				"horde1":         { "id" : 18, "animation" : "TBINHRD1.def", "x" : 614, "y" : 256, "border" : "TOIMP1HA.bmp", "area" : "TZIMP1HA.bmp", "hidden" : true },
+				"horde1Upgr":     { "id" : 19, "animation" : "TBINHRD2.def", "x" : 614, "y" : 221, "border" : "TOIMP2HA.bmp", "area" : "TZIMP2HA.bmp", "hidden" : true, "builds" : 18 },
+				"special2":       { "id" : 21, "animation" : "TBINEXT0.def", "x" : 297, "y" : 0,   "z" : -1, "border" : "TOICAB1A.bmp", "area" : "TZICAB1A.bmp" },
+				"special3":       { "id" : 22, "animation" : "TBINEXT1.def", "x" : 227, "y" : 174, "z" : 2,  "border" : "TOICASGA.bmp", "area" : "TZICASGA.bmp" },
+				"special4":       { "id" : 23, "animation" : "TBINEXT2.def", "x" : 593, "y" : 104, "border" : "TOIPAIN.bmp",  "area" : "TZIPAIN.bmp"  },
+				"horde2":         { "id" : 24, "animation" : "TBINHRD3.def", "x" : 10,  "y" : 301, "border" : "TOIHND1H.bmp", "area" : "TZIHND1H.bmp", "hidden" : true },
+				"horde2Upgr":     { "id" : 25, "animation" : "TBINHRD4.def", "x" : 9,   "y" : 273, "border" : "TOIHND2H.bmp", "area" : "TZIHND2H.bmp", "hidden" : true, "builds" : 24 },
+				"grail":          { "id" : 26, "animation" : "TBINHOLY.def", "x" : 24,  "y" : 10,  "z" : -1, "border" : "TOIHOLY.bmp",  "area" : "TZIHOLY.bmp" },
+				"dwellingLvl1":   { "id" : 30, "animation" : "TBINDW_0.def", "x" : 614, "y" : 256, "border" : "TOIMP1A.bmp",  "area" : "TZIMP1A.bmp"  },
+				"dwellingLvl2":   { "id" : 31, "animation" : "TBINDW_1.def", "x" : 187, "y" : 248, "z" : 4,  "border" : "TOIGOG1A.bmp", "area" : "TZIGOG1A.bmp" },
+				"dwellingLvl3":   { "id" : 32, "animation" : "TBINDW_2.def", "x" : 9,   "y" : 325, "border" : "TOIHND1.bmp",  "area" : "TZIHND1.bmp"  },
+				"dwellingLvl4":   { "id" : 33, "animation" : "TBINDW_3.def", "x" : 414, "y" : 204, "z" : 2,  "border" : "TOIDMN1.bmp",  "area" : "TZIDMN1.bmp" },
+				"dwellingLvl5":   { "id" : 34, "animation" : "TBINDW_4.def", "x" : 359, "y" : 296, "z" : 3,  "border" : "TOIPIT1.bmp",  "area" : "TZIPIT1.bmp" },
+				"dwellingLvl6":   { "id" : 35, "animation" : "TBINDW_5.def", "x" : 220, "y" : 350, "z" : 5,  "border" : "TOIEFR1.bmp",  "area" : "TZIEFR1.bmp" },
+				"dwellingLvl7":   { "id" : 36, "animation" : "TBINDW_6.def", "x" : 420, "y" : 153, "z" : -1, "border" : "TOIDVL1.bmp",  "area" : "TZIDVL1.bmp" },
+				"dwellingUpLvl1": { "id" : 37, "animation" : "TBINUP_0.def", "x" : 614, "y" : 221, "border" : "TOIMP2A.bmp",  "area" : "TZIMP2A.bmp"  },
+				"dwellingUpLvl2": { "id" : 38, "animation" : "TBINUP_1.def", "x" : 187, "y" : 212, "z" : 4,  "border" : "TOIGOG2A.bmp", "area" : "TZIGOG2A.bmp" },
+				"dwellingUpLvl3": { "id" : 39, "animation" : "TBINUP_2.def", "x" : 9,   "y" : 273, "border" : "TOIHND2.bmp",  "area" : "TZIHND2.bmp"  },
+				"dwellingUpLvl4": { "id" : 40, "animation" : "TBINUP_3.def", "x" : 412, "y" : 197, "z" : 2,  "border" : "TOIDMN2.bmp",  "area" : "TZIDMN2.bmp" },
+				"dwellingUpLvl5": { "id" : 41, "animation" : "TBINUP_4.def", "x" : 359, "y" : 244, "z" : 3,  "border" : "TOIPIT2.bmp",  "area" : "TZIPIT2.bmp" },
+				"dwellingUpLvl6": { "id" : 42, "animation" : "TBINUP_5.def", "x" : 220, "y" : 282, "z" : 5,  "border" : "TOIEFR2.bmp",  "area" : "TZIEFR2.bmp" },
+				"dwellingUpLvl7": { "id" : 43, "animation" : "TBINUP_6.def", "x" : 420, "y" : 105, "z" : -1, "border" : "TOIDVL2.bmp",  "area" : "TZIDVL2.bmp" }
+			},
 			"icons" :
 			{
 				"village" : {"normal" : 24, "built" : 25 },
@@ -150,50 +150,50 @@
 			"moatDamage" : 90,
 
 			"buildings" :
-			[
-				{ "id" : 0 },
-				{ "id" : 1,  "upgrades" : 0 },
-				{ "id" : 2,  "upgrades" : 1 },
-				{ "id" : 3,  "upgrades" : 2 },
-				{ "id" : 4,  "upgrades" : 3 },
-				{ "id" : 5 },
-				{ "id" : 7 },
-				{ "id" : 8,  "upgrades" : 7 },
-				{ "id" : 9,  "upgrades" : 8 },
-				{ "id" : 10, "mode" : "auto" },
-				{ "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
-				{ "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
-				{ "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
-				{ "id" : 14 },
-				{ "id" : 15, "requires" : [ 14 ] },
-				{ "id" : 16 },
-				{ "id" : 18, "upgrades" : 30 },
-				{ "id" : 19, "upgrades" : 37, "requires" : [ 18 ], "mode" : "auto" },
-				{ "id" : 21, "requires" : [ 7 ] },
-				{ "id" : 22, "requires" : [ 8 ] },
-				{ "id" : 23, "requires" : [ 0 ] },
-				{ "id" : 24, "upgrades" : 32 },
-				{ "id" : 25, "upgrades" : 39, "requires" : [ 24 ], "mode" : "auto" },
-				{ "id" : 26, "mode" : "grail"},
-				{ "id" : 27, "requires" : [ 11 ], "mode" : "auto" },
-				{ "id" : 28, "requires" : [ 12 ], "mode" : "auto" },
-				{ "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
-				{ "id" : 26 },
-				{ "id" : 30, "requires" : [ 7 ] },
-				{ "id" : 31, "requires" : [ 30 ] },
-				{ "id" : 32, "requires" : [ 30 ] },
-				{ "id" : 33, "requires" : [ 31 ] },
-				{ "id" : 34, "requires" : [ 33 ] },
-				{ "id" : 35, "requires" : [ 0, 33 ] },
-				{ "id" : 36, "requires" : [ 34, 35 ] },
-				{ "id" : 37, "upgrades" : 30 },
-				{ "id" : 38, "upgrades" : 31 },
-				{ "id" : 39, "upgrades" : 32 },
-				{ "id" : 40, "upgrades" : 33 },
-				{ "id" : 41, "upgrades" : 34, "requires" : [ 1 ] },
-				{ "id" : 42, "upgrades" : 35 },
-				{ "id" : 43, "upgrades" : 36 }
-			],
+			{
+				"mageGuild1":     { "id" : 0 },
+				"mageGuild2":     { "id" : 1,  "upgrades" : 0 },
+				"mageGuild3":     { "id" : 2,  "upgrades" : 1 },
+				"mageGuild4":     { "id" : 3,  "upgrades" : 2 },
+				"mageGuild5":     { "id" : 4,  "upgrades" : 3 },
+				"tavern":         { "id" : 5 },
+				"fort":           { "id" : 7 },
+				"citadel":        { "id" : 8,  "upgrades" : 7 },
+				"castle":         { "id" : 9,  "upgrades" : 8 },
+				"villageHall":    { "id" : 10, "mode" : "auto" },
+				"townHall":       { "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
+				"cityHall":       { "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
+				"capitol":        { "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
+				"marketplace":    { "id" : 14 },
+				"resourceSilo":  { "id" : 15, "requires" : [ 14 ] },
+				"blacksmith":     { "id" : 16 },
+				"horde1":         { "id" : 18, "upgrades" : 30 },
+				"horde1Upgr":     { "id" : 19, "upgrades" : 37, "requires" : [ 18 ], "mode" : "auto" },
+				"special2":       { "id" : 21, "requires" : [ 7 ] },
+				"special3":       { "id" : 22, "requires" : [ 8 ] },
+				"special4":       { "id" : 23, "requires" : [ 0 ] },
+				"horde2":         { "id" : 24, "upgrades" : 32 },
+				"horde2Upgr":     { "id" : 25, "upgrades" : 39, "requires" : [ 24 ], "mode" : "auto" },
+				"grail":          { "id" : 26, "mode" : "grail"},
+				"dwellingLvl1":   { "id" : 30, "requires" : [ 7 ] },
+				"dwellingLvl2":   { "id" : 31, "requires" : [ 30 ] },
+				"dwellingLvl3":   { "id" : 32, "requires" : [ 30 ] },
+				"dwellingLvl4":   { "id" : 33, "requires" : [ 31 ] },
+				"dwellingLvl5":   { "id" : 34, "requires" : [ 33 ] },
+				"dwellingLvl6":   { "id" : 35, "requires" : [ 0, 33 ] },
+				"dwellingLvl7":   { "id" : 36, "requires" : [ 34, 35 ] },
+				"dwellingUpLvl1": { "id" : 37, "upgrades" : 30 },
+				"dwellingUpLvl2": { "id" : 38, "upgrades" : 31 },
+				"dwellingUpLvl3": { "id" : 39, "upgrades" : 32 },
+				"dwellingUpLvl4": { "id" : 40, "upgrades" : 33 },
+				"dwellingUpLvl5": { "id" : 41, "upgrades" : 34, "requires" : [ 1 ] },
+				"dwellingUpLvl6": { "id" : 42, "upgrades" : 35 },
+				"dwellingUpLvl7": { "id" : 43, "upgrades" : 36 },
+
+				"ship" : null,
+				"shipyard" : null,
+				"special1" : null
+			},
 
 			"siege" :
 			{

+ 91 - 87
config/factions/necropolis.json

@@ -74,50 +74,50 @@
 				"capitol" : "AVCNECZ0.DEF"
 			},
 			"structures" :
-			[
-				{ "animation" : "TBNCEXT2.def", "x" : 25,  "y" : 279 },
-				{ "id" : 0,  "animation" : "TBNCMAGE.def", "x" : 341, "y" : 116, "z" : -1, "border" : "TONMAG1.bmp",  "area" : "TZNMAG1.bmp" },
-				{ "id" : 1,  "animation" : "TBNCMAG2.def", "x" : 341, "y" : 97,  "z" : -1, "border" : "TONMAG2.bmp",  "area" : "TZNMAG2.bmp" },
-				{ "id" : 2,  "animation" : "TBNCMAG3.def", "x" : 341, "y" : 78,  "z" : -1, "border" : "TONMAG3.bmp",  "area" : "TZNMAG3.bmp" },
-				{ "id" : 3,  "animation" : "TBNCMAG4.def", "x" : 340, "y" : 62,  "z" : -1, "border" : "TONMAG4.bmp",  "area" : "TZNMAG4.bmp" },
-				{ "id" : 4,  "animation" : "TBNCMAG5.def", "x" : 343, "y" : 35,  "z" : -1, "border" : "TONMAG5.bmp",  "area" : "TZNMAG5.bmp" },
-				{ "id" : 5,  "animation" : "TBNCTVRN.def", "x" : 508, "y" : 189, "border" : "TONTAV.bmp",   "area" : "TZNTAV.bmp"  },
-				{ "id" : 6,  "animation" : "TBNCDOCK.def", "x" : 617, "y" : 265, "z" : -2, "border" : "TONSHPBA.bmp", "area" : "TZNSHPBA.bmp" },
-				{ "id" : 7,  "animation" : "TBNCCSTL.def", "x" : 138, "y" : 66,  "border" : "TONCAS1.bmp",  "area" : "TZNCAS1.bmp" },
-				{ "id" : 8,  "animation" : "TBNCCAS2.def", "x" : 139, "y" : 66,  "border" : "TONCAS2.bmp",  "area" : "TZNCAS2.bmp" },
-				{ "id" : 9,  "animation" : "TBNCCAS3.def", "x" : 34,  "y" : 18,  "border" : "TONCAS3.bmp",  "area" : "TZNCAS3.bmp" },
-				{ "id" : 10, "animation" : "TBNCHALL.def", "x" : 468, "y" : 76,  "z" : -1, "border" : "TONHAL1.bmp",  "area" : "TZNHAL1.bmp" },
-				{ "id" : 11, "animation" : "TBNCHAL2.def", "x" : 482, "y" : 56,  "z" : -1, "border" : "TONHAL2.bmp",  "area" : "TZNHAL2.bmp" },
-				{ "id" : 12, "animation" : "TBNCHAL3.def", "x" : 478, "y" : 26,  "z" : -1, "border" : "TONHAL3.bmp",  "area" : "TZNHAL3.bmp" },
-				{ "id" : 13, "animation" : "TBNCHAL4.def", "x" : 481, "y" : 26,  "z" : -1, "border" : "TONHAL4.bmp",  "area" : "TZNHAL4.bmp" },
-				{ "id" : 14, "animation" : "TBNCMARK.def", "x" : 347, "y" : 215, "z" : 2,  "border" : "TONMRK1.bmp",  "area" : "TZNMRK1.bmp" },
-				{ "id" : 15, "animation" : "TBNCSILO.def", "x" : 276, "y" : 185, "z" : 1,  "border" : "TONMRK2.bmp",  "area" : "TZNMRK2.bmp" },
-				{ "id" : 16, "animation" : "TBNCBLAK.def", "x" : 382, "y" : 252, "z" : 4,  "border" : "TONSMITA.bmp", "area" : "TZNSMITA.bmp" },
-				{ "id" : 17, "animation" : "TBNCSPEC.def", "x" : 18,  "y" : 0,   "z" : -1, "border" : "TONSHRDA.bmp", "area" : "TZNSHRDA.bmp" },
-				{ "id" : 18, "animation" : "TBNCHRD1.def", "x" : 80,  "y" : 222, "z" : 4, "border" : "TONSKE1H.bmp", "area" : "TZNSKE1H.bmp", "hidden" : true },
-				{ "id" : 19, "animation" : "TBNCHRD2.def", "x" : 64,  "y" : 222, "z" : 4, "border" : "TONSKE2H.bmp", "area" : "TZNSKE2H.bmp", "hidden" : true, "builds" : 18 },
-				{ "id" : 20, "animation" : "TBNCBOAT.def", "x" : 617, "y" : 265, "z" : -2, "border" : "TONSHPNA.bmp", "area" : "TZNSHPNA.bmp", "hidden" : true },
-				{ "id" : 21, "animation" : "TBNCEXT0.def", "x" : 307, "y" : 61,  "z" : -2, "border" : "TONNECRA.bmp", "area" : "TZNNECRA.bmp" },
-				{ "id" : 22, "animation" : "TBNCEXT1.def", "x" : 247, "y" : 275, "z" : 4,  "border" : "TONSKELT.bmp", "area" : "TZNSKELT.bmp" },
-				{ "id" : 26, "animation" : "TBNCHOLY.def", "x" : 410, "y" : 88,  "border" : "TONHOLYA.bmp", "area" : "TZNHOLYA.bmp" },
-				{ "id" : 27, "animation" : "TBNCEXT3.def", "x" : 0,   "y" : 241 },
-				{ "id" : 28, "animation" : "TBNCEXT4.def", "x" : 321, "y" : 255 },
-				{ "id" : 29, "animation" : "TBNCEXT5.def", "x" : 475, "y" : 257 },
-				{ "id" : 30, "animation" : "TBNCDW_0.def", "x" : 80,  "y" : 222, "z" : 4, "border" : "TONSKEL1.bmp", "area" : "TZNSKEL1.bmp" },
-				{ "id" : 31, "animation" : "TBNCDW_1.def", "x" : 502, "y" : 223, "border" : "TONZOMB1.bmp", "area" : "TZNZOMB1.bmp" },
-				{ "id" : 32, "animation" : "TBNCDW_2.def", "x" : 0,   "y" : 187, "z" : 2, "border" : "TONWIGH1.bmp", "area" : "TZNWIGH1.bmp" },
-				{ "id" : 33, "animation" : "TBNCDW_3.def", "x" : 607, "y" : 212, "z" : 2, "border" : "TONVAM1.bmp",  "area" : "TZNVAM1.bmp" },
-				{ "id" : 34, "animation" : "TBNCDW_4.def", "x" : 206, "y" : 207, "z" : 3, "border" : "TONLICH1.bmp", "area" : "TZNLICH1.bmp" },
-				{ "id" : 35, "animation" : "TBNCDW_5.def", "x" : 0,   "y" : 31,  "border" : "TONBKN1.bmp",  "area" : "TZNBKN1.bmp" },
-				{ "id" : 36, "animation" : "TBNCDW_6.def", "x" : 663, "y" : 25,  "border" : "TONBON1.bmp",  "area" : "TZNBON1.bmp" },
-				{ "id" : 37, "animation" : "TBNCUP_0.def", "x" : 64,  "y" : 222, "z" : 4, "border" : "TONSKEL2.bmp", "area" : "TZNSKEL2.bmp" },
-				{ "id" : 38, "animation" : "TBNCUP_1.def", "x" : 498, "y" : 224, "border" : "TONZOMB2.bmp", "area" : "TZNZOMB2.bmp" },
-				{ "id" : 39, "animation" : "TBNCUP_2.def", "x" : 0,   "y" : 179, "z" : 2, "border" : "TONWIGH2.bmp", "area" : "TZNWIGH2.bmp" },
-				{ "id" : 40, "animation" : "TBNCUP_3.def", "x" : 615, "y" : 193, "z" : 2, "border" : "TONVAM2.bmp",  "area" : "TZNVAM2.bmp" },
-				{ "id" : 41, "animation" : "TBNCUP_4.def", "x" : 222, "y" : 171, "z" : 3, "border" : "TONLICH2.bmp", "area" : "TZNLICH2.bmp" },
-				{ "id" : 42, "animation" : "TBNCUP_5.def", "x" : 0,   "y" : 30,  "border" : "TONBKN2.bmp",  "area" : "TZNBKN2.bmp" },
-				{ "id" : 43, "animation" : "TBNCUP_6.def", "x" : 662, "y" : 23,  "border" : "TONBON2.bmp",  "area" : "TZNBON2.bmp" }
-			],
+			{
+				"extraAnimation": { "animation" : "TBNCEXT2.def", "x" : 25,  "y" : 279 },
+				"mageGuild1":     { "id" : 0,  "animation" : "TBNCMAGE.def", "x" : 341, "y" : 116, "z" : -1, "border" : "TONMAG1.bmp",  "area" : "TZNMAG1.bmp" },
+				"mageGuild2":     { "id" : 1,  "animation" : "TBNCMAG2.def", "x" : 341, "y" : 97,  "z" : -1, "border" : "TONMAG2.bmp",  "area" : "TZNMAG2.bmp" },
+				"mageGuild3":     { "id" : 2,  "animation" : "TBNCMAG3.def", "x" : 341, "y" : 78,  "z" : -1, "border" : "TONMAG3.bmp",  "area" : "TZNMAG3.bmp" },
+				"mageGuild4":     { "id" : 3,  "animation" : "TBNCMAG4.def", "x" : 340, "y" : 62,  "z" : -1, "border" : "TONMAG4.bmp",  "area" : "TZNMAG4.bmp" },
+				"mageGuild5":     { "id" : 4,  "animation" : "TBNCMAG5.def", "x" : 343, "y" : 35,  "z" : -1, "border" : "TONMAG5.bmp",  "area" : "TZNMAG5.bmp" },
+				"tavern":         { "id" : 5,  "animation" : "TBNCTVRN.def", "x" : 508, "y" : 189, "border" : "TONTAV.bmp",   "area" : "TZNTAV.bmp"  },
+				"shipyard":       { "id" : 6,  "animation" : "TBNCDOCK.def", "x" : 617, "y" : 265, "z" : -2, "border" : "TONSHPBA.bmp", "area" : "TZNSHPBA.bmp" },
+				"fort":           { "id" : 7,  "animation" : "TBNCCSTL.def", "x" : 138, "y" : 66,  "border" : "TONCAS1.bmp",  "area" : "TZNCAS1.bmp" },
+				"citadel":        { "id" : 8,  "animation" : "TBNCCAS2.def", "x" : 139, "y" : 66,  "border" : "TONCAS2.bmp",  "area" : "TZNCAS2.bmp" },
+				"castle":         { "id" : 9,  "animation" : "TBNCCAS3.def", "x" : 34,  "y" : 18,  "border" : "TONCAS3.bmp",  "area" : "TZNCAS3.bmp" },
+				"villageHall":    { "id" : 10, "animation" : "TBNCHALL.def", "x" : 468, "y" : 76,  "z" : -1, "border" : "TONHAL1.bmp",  "area" : "TZNHAL1.bmp" },
+				"townHall":       { "id" : 11, "animation" : "TBNCHAL2.def", "x" : 482, "y" : 56,  "z" : -1, "border" : "TONHAL2.bmp",  "area" : "TZNHAL2.bmp" },
+				"cityHall":       { "id" : 12, "animation" : "TBNCHAL3.def", "x" : 478, "y" : 26,  "z" : -1, "border" : "TONHAL3.bmp",  "area" : "TZNHAL3.bmp" },
+				"capitol":        { "id" : 13, "animation" : "TBNCHAL4.def", "x" : 481, "y" : 26,  "z" : -1, "border" : "TONHAL4.bmp",  "area" : "TZNHAL4.bmp" },
+				"marketplace":    { "id" : 14, "animation" : "TBNCMARK.def", "x" : 347, "y" : 215, "z" : 2,  "border" : "TONMRK1.bmp",  "area" : "TZNMRK1.bmp" },
+				"resourceSilo":  { "id" : 15, "animation" : "TBNCSILO.def", "x" : 276, "y" : 185, "z" : 1,  "border" : "TONMRK2.bmp",  "area" : "TZNMRK2.bmp" },
+				"blacksmith":     { "id" : 16, "animation" : "TBNCBLAK.def", "x" : 382, "y" : 252, "z" : 4,  "border" : "TONSMITA.bmp", "area" : "TZNSMITA.bmp" },
+				"special1":       { "id" : 17, "animation" : "TBNCSPEC.def", "x" : 18,  "y" : 0,   "z" : -1, "border" : "TONSHRDA.bmp", "area" : "TZNSHRDA.bmp" },
+				"horde1":         { "id" : 18, "animation" : "TBNCHRD1.def", "x" : 80,  "y" : 222, "z" : 4, "border" : "TONSKE1H.bmp", "area" : "TZNSKE1H.bmp", "hidden" : true },
+				"horde1Upgr":     { "id" : 19, "animation" : "TBNCHRD2.def", "x" : 64,  "y" : 222, "z" : 4, "border" : "TONSKE2H.bmp", "area" : "TZNSKE2H.bmp", "hidden" : true, "builds" : 18 },
+				"ship":           { "id" : 20, "animation" : "TBNCBOAT.def", "x" : 617, "y" : 265, "z" : -2, "border" : "TONSHPNA.bmp", "area" : "TZNSHPNA.bmp", "hidden" : true },
+				"special2":       { "id" : 21, "animation" : "TBNCEXT0.def", "x" : 307, "y" : 61,  "z" : -2, "border" : "TONNECRA.bmp", "area" : "TZNNECRA.bmp" },
+				"special3":       { "id" : 22, "animation" : "TBNCEXT1.def", "x" : 247, "y" : 275, "z" : 4,  "border" : "TONSKELT.bmp", "area" : "TZNSKELT.bmp" },
+				"grail":          { "id" : 26, "animation" : "TBNCHOLY.def", "x" : 410, "y" : 88,  "border" : "TONHOLYA.bmp", "area" : "TZNHOLYA.bmp" },
+				"extraTownHall":  { "id" : 27, "animation" : "TBNCEXT3.def", "x" : 0,   "y" : 241 },
+				"extraCityHall":  { "id" : 28, "animation" : "TBNCEXT4.def", "x" : 321, "y" : 255 },
+				"extraCapitol":   { "id" : 29, "animation" : "TBNCEXT5.def", "x" : 475, "y" : 257 },
+				"dwellingLvl1":   { "id" : 30, "animation" : "TBNCDW_0.def", "x" : 80,  "y" : 222, "z" : 4, "border" : "TONSKEL1.bmp", "area" : "TZNSKEL1.bmp" },
+				"dwellingLvl2":   { "id" : 31, "animation" : "TBNCDW_1.def", "x" : 502, "y" : 223, "border" : "TONZOMB1.bmp", "area" : "TZNZOMB1.bmp" },
+				"dwellingLvl3":   { "id" : 32, "animation" : "TBNCDW_2.def", "x" : 0,   "y" : 187, "z" : 2, "border" : "TONWIGH1.bmp", "area" : "TZNWIGH1.bmp" },
+				"dwellingLvl4":   { "id" : 33, "animation" : "TBNCDW_3.def", "x" : 607, "y" : 212, "z" : 2, "border" : "TONVAM1.bmp",  "area" : "TZNVAM1.bmp" },
+				"dwellingLvl5":   { "id" : 34, "animation" : "TBNCDW_4.def", "x" : 206, "y" : 207, "z" : 3, "border" : "TONLICH1.bmp", "area" : "TZNLICH1.bmp" },
+				"dwellingLvl6":   { "id" : 35, "animation" : "TBNCDW_5.def", "x" : 0,   "y" : 31,  "border" : "TONBKN1.bmp",  "area" : "TZNBKN1.bmp" },
+				"dwellingLvl7":   { "id" : 36, "animation" : "TBNCDW_6.def", "x" : 663, "y" : 25,  "border" : "TONBON1.bmp",  "area" : "TZNBON1.bmp" },
+				"dwellingUpLvl1": { "id" : 37, "animation" : "TBNCUP_0.def", "x" : 64,  "y" : 222, "z" : 4, "border" : "TONSKEL2.bmp", "area" : "TZNSKEL2.bmp" },
+				"dwellingUpLvl2": { "id" : 38, "animation" : "TBNCUP_1.def", "x" : 498, "y" : 224, "border" : "TONZOMB2.bmp", "area" : "TZNZOMB2.bmp" },
+				"dwellingUpLvl3": { "id" : 39, "animation" : "TBNCUP_2.def", "x" : 0,   "y" : 179, "z" : 2, "border" : "TONWIGH2.bmp", "area" : "TZNWIGH2.bmp" },
+				"dwellingUpLvl4": { "id" : 40, "animation" : "TBNCUP_3.def", "x" : 615, "y" : 193, "z" : 2, "border" : "TONVAM2.bmp",  "area" : "TZNVAM2.bmp" },
+				"dwellingUpLvl5": { "id" : 41, "animation" : "TBNCUP_4.def", "x" : 222, "y" : 171, "z" : 3, "border" : "TONLICH2.bmp", "area" : "TZNLICH2.bmp" },
+				"dwellingUpLvl6": { "id" : 42, "animation" : "TBNCUP_5.def", "x" : 0,   "y" : 30,  "border" : "TONBKN2.bmp",  "area" : "TZNBKN2.bmp" },
+				"dwellingUpLvl7": { "id" : 43, "animation" : "TBNCUP_6.def", "x" : 662, "y" : 23,  "border" : "TONBON2.bmp",  "area" : "TZNBON2.bmp" }
+			},
 			"icons" :
 			{
 				"village" : {"normal" : 26, "built" : 27 },
@@ -153,49 +153,53 @@
 			"moatDamage" : 70,
 
 			"buildings" :
-			[
-				{ "id" : 0 },
-				{ "id" : 1,  "upgrades" : 0 },
-				{ "id" : 2,  "upgrades" : 1 },
-				{ "id" : 3,  "upgrades" : 2 },
-				{ "id" : 4,  "upgrades" : 3 },
-				{ "id" : 5 },
-				{ "id" : 6 },
-				{ "id" : 7 },
-				{ "id" : 8,  "upgrades" : 7 },
-				{ "id" : 9,  "upgrades" : 8 },
-				{ "id" : 10, "mode" : "auto" },
-				{ "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
-				{ "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
-				{ "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
-				{ "id" : 14 },
-				{ "id" : 15, "requires" : [ 14 ] },
-				{ "id" : 16 },
-				{ "id" : 17, "requires" : [ 7 ] },
-				{ "id" : 18, "upgrades" : 30, "requires" : [ 22 ] },
-				{ "id" : 19, "upgrades" : 37, "requires" : [ 18 ], "mode" : "auto" },
-				{ "id" : 20, "upgrades" : 6 },
-				{ "id" : 21, "requires" : [ 0 ] },
-				{ "id" : 22, "requires" : [ 30 ] },
-				{ "id" : 26, "mode" : "grail"},
-				{ "id" : 27, "requires" : [ 11 ], "mode" : "auto" },
-				{ "id" : 28, "requires" : [ 12 ], "mode" : "auto" },
-				{ "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
-				{ "id" : 30, "requires" : [ 7 ] },
-				{ "id" : 31, "requires" : [ 30 ] },
-				{ "id" : 32, "requires" : [ 30 ] },
-				{ "id" : 33, "requires" : [ 31 ] },
-				{ "id" : 34, "requires" : [ 0, 31 ] },
-				{ "id" : 35, "requires" : [ 33, 34 ] },
-				{ "id" : 36, "requires" : [ 35 ] },
-				{ "id" : 37, "upgrades" : 30 },
-				{ "id" : 38, "upgrades" : 31 },
-				{ "id" : 39, "upgrades" : 32 },
-				{ "id" : 40, "upgrades" : 33, "requires" : [ 21 ] },
-				{ "id" : 41, "upgrades" : 34 },
-				{ "id" : 42, "upgrades" : 35 },
-				{ "id" : 43, "upgrades" : 36 }
-			],
+			{
+				"mageGuild1":     { "id" : 0 },
+				"mageGuild2":     { "id" : 1,  "upgrades" : 0 },
+				"mageGuild3":     { "id" : 2,  "upgrades" : 1 },
+				"mageGuild4":     { "id" : 3,  "upgrades" : 2 },
+				"mageGuild5":     { "id" : 4,  "upgrades" : 3 },
+				"tavern":         { "id" : 5 },
+				"shipyard":       { "id" : 6 },
+				"fort":           { "id" : 7 },
+				"citadel":        { "id" : 8,  "upgrades" : 7 },
+				"castle":         { "id" : 9,  "upgrades" : 8 },
+				"villageHall":    { "id" : 10, "mode" : "auto" },
+				"townHall":       { "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
+				"cityHall":       { "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
+				"capitol":        { "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
+				"marketplace":    { "id" : 14 },
+				"resourceSilo":  { "id" : 15, "requires" : [ 14 ] },
+				"blacksmith":     { "id" : 16 },
+				"special1":       { "id" : 17, "requires" : [ 7 ] },
+				"horde1":         { "id" : 18, "upgrades" : 30, "requires" : [ 22 ] },
+				"horde1Upgr":     { "id" : 19, "upgrades" : 37, "requires" : [ 18 ], "mode" : "auto" },
+				"ship":           { "id" : 20, "upgrades" : 6 },
+				"special2":       { "id" : 21, "requires" : [ 0 ] },
+				"special3":       { "id" : 22, "requires" : [ 30 ] },
+				"grail":          { "id" : 26, "mode" : "grail"},
+				"extraTownHall":  { "id" : 27, "requires" : [ 11 ], "mode" : "auto" },
+				"extraCityHall":  { "id" : 28, "requires" : [ 12 ], "mode" : "auto" },
+				"extraCapitol":   { "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
+				"dwellingLvl1":   { "id" : 30, "requires" : [ 7 ] },
+				"dwellingLvl2":   { "id" : 31, "requires" : [ 30 ] },
+				"dwellingLvl3":   { "id" : 32, "requires" : [ 30 ] },
+				"dwellingLvl4":   { "id" : 33, "requires" : [ 31 ] },
+				"dwellingLvl5":   { "id" : 34, "requires" : [ 0, 31 ] },
+				"dwellingLvl6":   { "id" : 35, "requires" : [ 33, 34 ] },
+				"dwellingLvl7":   { "id" : 36, "requires" : [ 35 ] },
+				"dwellingUpLvl1": { "id" : 37, "upgrades" : 30 },
+				"dwellingUpLvl2": { "id" : 38, "upgrades" : 31 },
+				"dwellingUpLvl3": { "id" : 39, "upgrades" : 32 },
+				"dwellingUpLvl4": { "id" : 40, "upgrades" : 33, "requires" : [ 21 ] },
+				"dwellingUpLvl5": { "id" : 41, "upgrades" : 34 },
+				"dwellingUpLvl6": { "id" : 42, "upgrades" : 35 },
+				"dwellingUpLvl7": { "id" : 43, "upgrades" : 36 },
+				
+				"horde2" : null,
+				"horde2Upgr" : null,
+				"special4" : null
+			},
 
 			"siege" :
 			{

+ 91 - 88
config/factions/rampart.json

@@ -74,50 +74,50 @@
 				"capitol" : "AVCRAMZ0.DEF"
 			},
 			"structures" :
-			[
-				{ "animation" : "TBRMEXT2.def", "x" : 327, "y" : 236 },
-				{ "id" : 0,  "animation" : "TBRMMAGE.def", "x" : 454, "y" : 200, "z" : -1, "border" : "TORMAG1.bmp",  "area" : "TZRMAG1.bmp" },
-				{ "id" : 1,  "animation" : "TBRMMAG2.def", "x" : 438, "y" : 178, "z" : -1, "border" : "TORMAG2.bmp",  "area" : "TZRMAG2.bmp" },
-				{ "id" : 2,  "animation" : "TBRMMAG3.def", "x" : 418, "y" : 153, "z" : -1, "border" : "TORMAG3.bmp",  "area" : "TZRMAG3.bmp" },
-				{ "id" : 3,  "animation" : "TBRMMAG4.def", "x" : 406, "y" : 129, "z" : -1, "border" : "TORMAG4.bmp",  "area" : "TZRMAG4.bmp" },
-				{ "id" : 4,  "animation" : "TBRMMAG5.def", "x" : 384, "y" : 104, "z" : -1, "border" : "TORMAG5.bmp",  "area" : "TZRMAG5.bmp" },
-				{ "id" : 5,  "animation" : "TBRMTVRN.def", "x" : 181, "y" : 229, "z" : 1,  "border" : "TORTAV.bmp",   "area" : "TZRTAV.bmp" },
-				{ "id" : 7,  "animation" : "TBRMCSTL.def", "x" : 63,  "y" : 25,  "z" : -2, "border" : "TORCAS1.bmp",  "area" : "TZRCAS1.bmp" },
-				{ "id" : 8,  "animation" : "TBRMCAS2.def", "x" : 79,  "y" : 18,  "z" : -2, "border" : "TORCAS3.bmp",  "area" : "TZRCAS3.bmp" },
-				{ "id" : 9,  "animation" : "TBRMCAS3.def", "x" : 79,  "y" : 18,  "z" : -2, "border" : "TORCAS2.bmp",  "area" : "TZRCAS2.bmp" },
-				{ "id" : 10, "animation" : "TBRMHALL.def", "x" : 565, "y" : 216, "border" : "TORHAL1.bmp",  "area" : "TZRHAL1.bmp" },
-				{ "id" : 11, "animation" : "TBRMHAL2.def", "x" : 538, "y" : 187, "border" : "TORHAL2.bmp",  "area" : "TZRHAL2.bmp" },
-				{ "id" : 12, "animation" : "TBRMHAL3.def", "x" : 538, "y" : 187, "border" : "TORHAL3.bmp",  "area" : "TZRHAL3.bmp" },
-				{ "id" : 13, "animation" : "TBRMHAL4.def", "x" : 534, "y" : 187, "border" : "TORHAL4.bmp",  "area" : "TZRHAL4.bmp" },
-				{ "id" : 14, "animation" : "TBRMMARK.def", "x" : 129, "y" : 301, "z" : 3,  "border" : "TORMRK1.bmp",  "area" : "TZRMRK1.bmp" },
-				{ "id" : 15, "animation" : "TBRMSILO.def", "x" : 245, "y" : 324, "z" : 4,  "border" : "TORMRK2.bmp",  "area" : "TZRMRK2.bmp" },
-				{ "id" : 16, "animation" : "TBRMBLAK.def", "x" : 558, "y" : 105, "z" : -3, "border" : "TORAID.bmp",   "area" : "TZRAID.bmp" },
-				{ "id" : 17, "animation" : "TBRMSPEC.def", "x" : 555, "y" : 297, "border" : "TORGAR1A.bmp", "area" : "TZRGAR1A.bmp" },
-				{ "id" : 18, "animation" : "TBRMHRD1.def", "x" : 0,   "y" : 154, "border" : "TORDWF1H.bmp", "area" : "TZRDWF1H.bmp", "hidden" : true },
-				{ "id" : 19, "animation" : "TBRMHRD2.def", "x" : 0,   "y" : 143, "border" : "TORDWF2H.bmp", "area" : "TZRDWF2H.bmp", "hidden" : true, "builds" : 18 },
-				{ "id" : 21, "animation" : "TBRMEXT0.def", "x" : 555, "y" : 297, "z" : 2, "border" : "TORGAR2A.bmp", "area" : "TZRGAR2A.bmp" },
-				{ "id" : 22, "animation" : "TBRMEXT1.def", "x" : 0,   "y" : 181, "z" : 1, "border" : "TORDWFT.bmp",  "area" : "TZRDWFT.bmp" },
-				{ "id" : 24, "animation" : "TBRMHRD3.def", "x" : 47,  "y" : 142, "z" : -1, "border" : "TORTRE1H.bmp", "area" : "TZRTRE1H.bmp", "hidden" : true },
-				{ "id" : 25, "animation" : "TBRMHRD4.def", "x" : 47,  "y" : 142, "z" : -1, "border" : "TORTRE2H.bmp", "area" : "TZRTRE2H.bmp", "hidden" : true, "builds" : 24 },
-				{ "id" : 26, "animation" : "TBRMHOLY.def", "x" : 0,   "y" : 54,  "z" : -1, "border" : "TORHOLY.bmp",  "area" : "TZRHOLY.bmp" },
-				{ "id" : 27, "animation" : "TBRMEXT3.def", "x" : 293, "y" : 235 },
-				{ "id" : 28, "animation" : "TBRMEXT4.def", "x" : 295, "y" : 191 },
-				{ "id" : 29, "animation" : "TBRMEXT5.def", "x" : 260, "y" : 171 },
-				{ "id" : 30, "animation" : "TBRMDW_0.def", "x" : 0,   "y" : 236, "z" : 2,  "border" : "TORCEN1A.bmp", "area" : "TZRCEN1A.bmp" },
-				{ "id" : 31, "animation" : "TBRMDW_1.def", "x" : 0,   "y" : 154, "border" : "TORDWF1.bmp",  "area" : "TZRDWF1.bmp" },
-				{ "id" : 32, "animation" : "TBRMDW_2.def", "x" : 668, "y" : 101, "border" : "TORELF1.bmp",  "area" : "TZRELF1.bmp" },
-				{ "id" : 33, "animation" : "TBRMDW_3.def", "x" : 287, "y" : 73,  "z" : -1, "border" : "TORPEG1A.bmp", "area" : "TZRPEG1A.bmp" },
-				{ "id" : 34, "animation" : "TBRMDW_4.def", "x" : 68,  "y" : 146, "z" : -1, "border" : "TORTRE1.bmp",  "area" : "TZRTRE1.bmp" },
-				{ "id" : 35, "animation" : "TBRMDW_5.def", "x" : 362, "y" : 90,  "z" : -2, "border" : "TORUNI1.bmp",  "area" : "TZRUNI1.bmp" },
-				{ "id" : 36, "animation" : "TBRMDW_6.def", "x" : 502, "y" : 27,  "z" : -5, "border" : "TORDR1AA.bmp", "area" : "TZRDR1AA.bmp" },
-				{ "id" : 37, "animation" : "TBRMUP_0.def", "x" : 0,   "y" : 236, "z" : 2,  "border" : "TORCEN2A.bmp", "area" : "TZRCEN2A.bmp" },
-				{ "id" : 38, "animation" : "TBRMUP_1.def", "x" : 0,   "y" : 143, "border" : "TORDWF2.bmp",  "area" : "TZRDWF2.bmp" },
-				{ "id" : 39, "animation" : "TBRMUP_2.def", "x" : 665, "y" : 101, "border" : "TORELF2.bmp",  "area" : "TZRELF2.bmp" },
-				{ "id" : 40, "animation" : "TBRMUP_3.def", "x" : 287, "y" : 28,  "z" : -1, "border" : "TORPEG2A.bmp", "area" : "TZRPEG2A.bmp" },
-				{ "id" : 41, "animation" : "TBRMUP_4.def", "x" : 63,  "y" : 146, "z" : -1, "border" : "TORTRE2.bmp",  "area" : "TZRTRE2.bmp" },
-				{ "id" : 42, "animation" : "TBRMUP_5.def", "x" : 362, "y" : 90,  "z" : -2, "border" : "TORUNI2.bmp",  "area" : "TZRUNI2.bmp" },
-				{ "id" : 43, "animation" : "TBRMUP_6.def", "x" : 502, "y" : 5,   "z" : -5, "border" : "TORDR2AA.bmp", "area" : "TZRDR2AA.bmp" }
-			],
+			{
+				"extraAnimation": { "animation" : "TBRMEXT2.def", "x" : 327, "y" : 236 },
+				"mageGuild1":     { "id" : 0,  "animation" : "TBRMMAGE.def", "x" : 454, "y" : 200, "z" : -1, "border" : "TORMAG1.bmp",  "area" : "TZRMAG1.bmp" },
+				"mageGuild2":     { "id" : 1,  "animation" : "TBRMMAG2.def", "x" : 438, "y" : 178, "z" : -1, "border" : "TORMAG2.bmp",  "area" : "TZRMAG2.bmp" },
+				"mageGuild3":     { "id" : 2,  "animation" : "TBRMMAG3.def", "x" : 418, "y" : 153, "z" : -1, "border" : "TORMAG3.bmp",  "area" : "TZRMAG3.bmp" },
+				"mageGuild4":     { "id" : 3,  "animation" : "TBRMMAG4.def", "x" : 406, "y" : 129, "z" : -1, "border" : "TORMAG4.bmp",  "area" : "TZRMAG4.bmp" },
+				"mageGuild5":     { "id" : 4,  "animation" : "TBRMMAG5.def", "x" : 384, "y" : 104, "z" : -1, "border" : "TORMAG5.bmp",  "area" : "TZRMAG5.bmp" },
+				"tavern":         { "id" : 5,  "animation" : "TBRMTVRN.def", "x" : 181, "y" : 229, "z" : 1,  "border" : "TORTAV.bmp",   "area" : "TZRTAV.bmp" },
+				"fort":           { "id" : 7,  "animation" : "TBRMCSTL.def", "x" : 63,  "y" : 25,  "z" : -2, "border" : "TORCAS1.bmp",  "area" : "TZRCAS1.bmp" },
+				"citadel":        { "id" : 8,  "animation" : "TBRMCAS2.def", "x" : 79,  "y" : 18,  "z" : -2, "border" : "TORCAS3.bmp",  "area" : "TZRCAS3.bmp" },
+				"castle":         { "id" : 9,  "animation" : "TBRMCAS3.def", "x" : 79,  "y" : 18,  "z" : -2, "border" : "TORCAS2.bmp",  "area" : "TZRCAS2.bmp" },
+				"villageHall":    { "id" : 10, "animation" : "TBRMHALL.def", "x" : 565, "y" : 216, "border" : "TORHAL1.bmp",  "area" : "TZRHAL1.bmp" },
+				"townHall":       { "id" : 11, "animation" : "TBRMHAL2.def", "x" : 538, "y" : 187, "border" : "TORHAL2.bmp",  "area" : "TZRHAL2.bmp" },
+				"cityHall":       { "id" : 12, "animation" : "TBRMHAL3.def", "x" : 538, "y" : 187, "border" : "TORHAL3.bmp",  "area" : "TZRHAL3.bmp" },
+				"capitol":        { "id" : 13, "animation" : "TBRMHAL4.def", "x" : 534, "y" : 187, "border" : "TORHAL4.bmp",  "area" : "TZRHAL4.bmp" },
+				"marketplace":    { "id" : 14, "animation" : "TBRMMARK.def", "x" : 129, "y" : 301, "z" : 3,  "border" : "TORMRK1.bmp",  "area" : "TZRMRK1.bmp" },
+				"resourceSilo":  { "id" : 15, "animation" : "TBRMSILO.def", "x" : 245, "y" : 324, "z" : 4,  "border" : "TORMRK2.bmp",  "area" : "TZRMRK2.bmp" },
+				"blacksmith":     { "id" : 16, "animation" : "TBRMBLAK.def", "x" : 558, "y" : 105, "z" : -3, "border" : "TORAID.bmp",   "area" : "TZRAID.bmp" },
+				"special1":       { "id" : 17, "animation" : "TBRMSPEC.def", "x" : 555, "y" : 297, "border" : "TORGAR1A.bmp", "area" : "TZRGAR1A.bmp" },
+				"horde1":         { "id" : 18, "animation" : "TBRMHRD1.def", "x" : 0,   "y" : 154, "border" : "TORDWF1H.bmp", "area" : "TZRDWF1H.bmp", "hidden" : true },
+				"horde1Upgr":     { "id" : 19, "animation" : "TBRMHRD2.def", "x" : 0,   "y" : 143, "border" : "TORDWF2H.bmp", "area" : "TZRDWF2H.bmp", "hidden" : true, "builds" : 18 },
+				"special2":       { "id" : 21, "animation" : "TBRMEXT0.def", "x" : 555, "y" : 297, "z" : 2, "border" : "TORGAR2A.bmp", "area" : "TZRGAR2A.bmp" },
+				"special3":       { "id" : 22, "animation" : "TBRMEXT1.def", "x" : 0,   "y" : 181, "z" : 1, "border" : "TORDWFT.bmp",  "area" : "TZRDWFT.bmp" },
+				"horde2":         { "id" : 24, "animation" : "TBRMHRD3.def", "x" : 47,  "y" : 142, "z" : -1, "border" : "TORTRE1H.bmp", "area" : "TZRTRE1H.bmp", "hidden" : true },
+				"horde2Upgr":     { "id" : 25, "animation" : "TBRMHRD4.def", "x" : 47,  "y" : 142, "z" : -1, "border" : "TORTRE2H.bmp", "area" : "TZRTRE2H.bmp", "hidden" : true, "builds" : 24 },
+				"grail":          { "id" : 26, "animation" : "TBRMHOLY.def", "x" : 0,   "y" : 54,  "z" : -1, "border" : "TORHOLY.bmp",  "area" : "TZRHOLY.bmp" },
+				"extraTownHall":  { "id" : 27, "animation" : "TBRMEXT3.def", "x" : 293, "y" : 235 },
+				"extraCityHall":  { "id" : 28, "animation" : "TBRMEXT4.def", "x" : 295, "y" : 191 },
+				"extraCapitol":   { "id" : 29, "animation" : "TBRMEXT5.def", "x" : 260, "y" : 171 },
+				"dwellingLvl1":   { "id" : 30, "animation" : "TBRMDW_0.def", "x" : 0,   "y" : 236, "z" : 2,  "border" : "TORCEN1A.bmp", "area" : "TZRCEN1A.bmp" },
+				"dwellingLvl2":   { "id" : 31, "animation" : "TBRMDW_1.def", "x" : 0,   "y" : 154, "border" : "TORDWF1.bmp",  "area" : "TZRDWF1.bmp" },
+				"dwellingLvl3":   { "id" : 32, "animation" : "TBRMDW_2.def", "x" : 668, "y" : 101, "border" : "TORELF1.bmp",  "area" : "TZRELF1.bmp" },
+				"dwellingLvl4":   { "id" : 33, "animation" : "TBRMDW_3.def", "x" : 287, "y" : 73,  "z" : -1, "border" : "TORPEG1A.bmp", "area" : "TZRPEG1A.bmp" },
+				"dwellingLvl5":   { "id" : 34, "animation" : "TBRMDW_4.def", "x" : 68,  "y" : 146, "z" : -1, "border" : "TORTRE1.bmp",  "area" : "TZRTRE1.bmp" },
+				"dwellingLvl6":   { "id" : 35, "animation" : "TBRMDW_5.def", "x" : 362, "y" : 90,  "z" : -2, "border" : "TORUNI1.bmp",  "area" : "TZRUNI1.bmp" },
+				"dwellingLvl7":   { "id" : 36, "animation" : "TBRMDW_6.def", "x" : 502, "y" : 27,  "z" : -5, "border" : "TORDR1AA.bmp", "area" : "TZRDR1AA.bmp" },
+				"dwellingUpLvl1": { "id" : 37, "animation" : "TBRMUP_0.def", "x" : 0,   "y" : 236, "z" : 2,  "border" : "TORCEN2A.bmp", "area" : "TZRCEN2A.bmp" },
+				"dwellingUpLvl2": { "id" : 38, "animation" : "TBRMUP_1.def", "x" : 0,   "y" : 143, "border" : "TORDWF2.bmp",  "area" : "TZRDWF2.bmp" },
+				"dwellingUpLvl3": { "id" : 39, "animation" : "TBRMUP_2.def", "x" : 665, "y" : 101, "border" : "TORELF2.bmp",  "area" : "TZRELF2.bmp" },
+				"dwellingUpLvl4": { "id" : 40, "animation" : "TBRMUP_3.def", "x" : 287, "y" : 28,  "z" : -1, "border" : "TORPEG2A.bmp", "area" : "TZRPEG2A.bmp" },
+				"dwellingUpLvl5": { "id" : 41, "animation" : "TBRMUP_4.def", "x" : 63,  "y" : 146, "z" : -1, "border" : "TORTRE2.bmp",  "area" : "TZRTRE2.bmp" },
+				"dwellingUpLvl6": { "id" : 42, "animation" : "TBRMUP_5.def", "x" : 362, "y" : 90,  "z" : -2, "border" : "TORUNI2.bmp",  "area" : "TZRUNI2.bmp" },
+				"dwellingUpLvl7": { "id" : 43, "animation" : "TBRMUP_6.def", "x" : 502, "y" : 5,   "z" : -5, "border" : "TORDR2AA.bmp", "area" : "TZRDR2AA.bmp" }
+			},
 			"icons" :
 			{
 				"village" : {"normal" : 20, "built" : 21 },
@@ -155,50 +155,53 @@
 			"moatDamage" : 70,
 
 			"buildings" :
-			[
-				{ "id" : 0 },
-				{ "id" : 1,  "upgrades" : 0 },
-				{ "id" : 2,  "upgrades" : 1 },
-				{ "id" : 3,  "upgrades" : 2 },
-				{ "id" : 4,  "upgrades" : 3 },
-				{ "id" : 5 },
-				{ "id" : 7 },
-				{ "id" : 8,  "upgrades" : 7 },
-				{ "id" : 9,  "upgrades" : 8 },
-				{ "id" : 10, "mode" : "auto" },
-				{ "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
-				{ "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
-				{ "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
-				{ "id" : 14 },
-				{ "id" : 15, "requires" : [ 14 ] },
-				{ "id" : 16 },
-				{ "id" : 17 },
-				{ "id" : 18, "upgrades" : 31 },
-				{ "id" : 19, "upgrades" : 38, "requires" : [ 18 ], "mode" : "auto" },
-				{ "id" : 21, "requires" : [ 17 ] },
-				{ "id" : 22, "requires" : [ 18, 19 ] },
-				{ "id" : 24, "upgrades" : 34 },
-				{ "id" : 25, "upgrades" : 41, "requires" : [ 24 ], "mode" : "auto" },
-				{ "id" : 26, "mode" : "grail"},
-				{ "id" : 27, "requires" : [ 11 ], "mode" : "auto" },
-				{ "id" : 28, "requires" : [ 12 ], "mode" : "auto" },
-				{ "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
-				{ "id" : 26 },
-				{ "id" : 30, "requires" : [ 7 ] },
-				{ "id" : 31, "requires" : [ 30 ] },
-				{ "id" : 32, "requires" : [ 30 ] },
-				{ "id" : 33, "requires" : [ 32 ] },
-				{ "id" : 34, "requires" : [ 32 ] },
-				{ "id" : 35, "requires" : [ 33, 34 ] },
-				{ "id" : 36, "requires" : [ 35, 1 ] },
-				{ "id" : 37, "upgrades" : 30 },
-				{ "id" : 38, "upgrades" : 31 },
-				{ "id" : 39, "upgrades" : 32 },
-				{ "id" : 40, "upgrades" : 33 },
-				{ "id" : 41, "upgrades" : 34 },
-				{ "id" : 42, "upgrades" : 35 },
-				{ "id" : 43, "upgrades" : 36, "requires" : [ 2 ] }
-			],
+			{
+				"mageGuild1":     { "id" : 0 },
+				"mageGuild2":     { "id" : 1,  "upgrades" : 0 },
+				"mageGuild3":     { "id" : 2,  "upgrades" : 1 },
+				"mageGuild4":     { "id" : 3,  "upgrades" : 2 },
+				"mageGuild5":     { "id" : 4,  "upgrades" : 3 },
+				"tavern":         { "id" : 5 },
+				"fort":           { "id" : 7 },
+				"citadel":        { "id" : 8,  "upgrades" : 7 },
+				"castle":         { "id" : 9,  "upgrades" : 8 },
+				"villageHall":    { "id" : 10, "mode" : "auto" },
+				"townHall":       { "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
+				"cityHall":       { "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
+				"capitol":        { "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
+				"marketplace":    { "id" : 14 },
+				"resourceSilo":  { "id" : 15, "requires" : [ 14 ] },
+				"blacksmith":     { "id" : 16 },
+				"special1":       { "id" : 17 },
+				"horde1":         { "id" : 18, "upgrades" : 31 },
+				"horde1Upgr":     { "id" : 19, "upgrades" : 38, "requires" : [ 18 ], "mode" : "auto" },
+				"special2":       { "id" : 21, "requires" : [ 17 ] },
+				"special3":       { "id" : 22, "requires" : [ 18, 19 ] },
+				"horde2":         { "id" : 24, "upgrades" : 34 },
+				"horde2Upgr":     { "id" : 25, "upgrades" : 41, "requires" : [ 24 ], "mode" : "auto" },
+				"grail":          { "id" : 26, "mode" : "grail"},
+				"extraTownHall":  { "id" : 27, "requires" : [ 11 ], "mode" : "auto" },
+				"extraCityHall":  { "id" : 28, "requires" : [ 12 ], "mode" : "auto" },
+				"extraCapitol":   { "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
+				"dwellingLvl1":   { "id" : 30, "requires" : [ 7 ] },
+				"dwellingLvl2":   { "id" : 31, "requires" : [ 30 ] },
+				"dwellingLvl3":   { "id" : 32, "requires" : [ 30 ] },
+				"dwellingLvl4":   { "id" : 33, "requires" : [ 32 ] },
+				"dwellingLvl5":   { "id" : 34, "requires" : [ 32 ] },
+				"dwellingLvl6":   { "id" : 35, "requires" : [ 33, 34 ] },
+				"dwellingLvl7":   { "id" : 36, "requires" : [ 35, 1 ] },
+				"dwellingUpLvl1": { "id" : 37, "upgrades" : 30 },
+				"dwellingUpLvl2": { "id" : 38, "upgrades" : 31 },
+				"dwellingUpLvl3": { "id" : 39, "upgrades" : 32 },
+				"dwellingUpLvl4": { "id" : 40, "upgrades" : 33 },
+				"dwellingUpLvl5": { "id" : 41, "upgrades" : 34 },
+				"dwellingUpLvl6": { "id" : 42, "upgrades" : 35 },
+				"dwellingUpLvl7": { "id" : 43, "upgrades" : 36, "requires" : [ 2 ] },
+				
+				"ship" : null,
+				"shipyard" : null,
+				"special4" : null
+			},
 
 			"siege" :
 			{

+ 82 - 80
config/factions/stronghold.json

@@ -74,44 +74,44 @@
 				"capitol" : "AVCSTRZ0.DEF"
 			},
 			"structures" :
-			[
-				{ "animation" : "TBSTEXT3.def", "x" : 23,  "y" : 20 },
-				{ "id" : 0,  "animation" : "TBSTMAGE.def", "x" : 473, "y" : 67,  "z" : -1, "border" : "TOSMAG1.bmp",  "area" : "TZSMAG1.bmp" },
-				{ "id" : 1,  "animation" : "TBSTMAG2.def", "x" : 473, "y" : 37,  "z" : -1, "border" : "TOSMAG2.bmp",  "area" : "TZSMAG2.bmp" },
-				{ "id" : 2,  "animation" : "TBSTMAG3.def", "x" : 473, "y" : 1,   "z" : -1, "border" : "TOSMAG3.bmp",  "area" : "TZSMAG3.bmp" },
-				{ "id" : 5,  "animation" : "TBSTTVRN.def", "x" : 170, "y" : 280, "z" : 2,  "border" : "TOSTAV.bmp",   "area" : "TZSTAV.bmp" },
-				{ "id" : 7,  "animation" : "TBSTCSTL.def", "x" : 402, "y" : 148, "z" : -1, "border" : "TOSCA1.bmp",   "area" : "TZSCA1.bmp" },
-				{ "id" : 8,  "animation" : "TBSTCAS2.def", "x" : 402, "y" : 114, "z" : -1, "border" : "TOSCA2.bmp",   "area" : "TZSCA2.bmp" },
-				{ "id" : 9,  "animation" : "TBSTCAS3.def", "x" : 402, "y" : 114, "z" : -1, "border" : "TOSCA3.bmp",   "area" : "TZSCA3.bmp" },
-				{ "id" : 10, "animation" : "TBSTHALL.def", "x" : 0,   "y" : 259, "border" : "TOSHAL1A.bmp", "area" : "TZSHAL1A.bmp" },
-				{ "id" : 11, "animation" : "TBSTHAL2.def", "x" : 0,   "y" : 225, "border" : "TOSHAL2A.bmp", "area" : "TZSHAL2A.bmp" },
-				{ "id" : 12, "animation" : "TBSTHAL3.def", "x" : 0,   "y" : 201, "border" : "TOSHAL3A.bmp", "area" : "TZSHAL3A.bmp" },
-				{ "id" : 13, "animation" : "TBSTHAL4.def", "x" : 0,   "y" : 148, "border" : "TOSHAL4A.bmp", "area" : "TZSHAL4A.bmp" },
-				{ "id" : 14, "animation" : "TBSTMARK.def", "x" : 397, "y" : 308, "z" : 1,  "border" : "TOSMRK1.bmp",  "area" : "TZSMRK1.bmp" },
-				{ "id" : 15, "animation" : "TBSTSILO.def", "x" : 458, "y" : 248, "z" : 1,  "border" : "TOSMRK2.bmp",  "area" : "TZSMRK2.bmp" },
-				{ "id" : 16, "animation" : "TBSTBLAK.def", "x" : 660, "y" : 286, "border" : "TOSBLK1.bmp",  "area" : "TZSBLK1.bmp" },
-				{ "id" : 17, "animation" : "TBSTSPEC.def", "x" : 550, "y" : 229, "border" : "TOSCA1EA.bmp", "area" : "TZSCA1EA.bmp" },
-				{ "id" : 18, "animation" : "TBSTHRD1.def", "x" : 373, "y" : 239, "border" : "TOSGOB1H.bmp", "area" : "TZSGOB1H.bmp", "hidden" : true },
-				{ "id" : 19, "animation" : "TBSTHRD2.def", "x" : 373, "y" : 220, "border" : "TOSGOB2H.bmp", "area" : "TZSGOB2H.bmp", "hidden" : true, "builds" : 18 },
-				{ "id" : 21, "animation" : "TBSTEXT0.def", "x" : 473, "y" : 282, "z" : 3,  "border" : "TOSMRK1C.bmp", "area" : "TZSMRK1C.bmp" },
-				{ "id" : 22, "animation" : "TBSTEXT1.def", "x" : 617, "y" : 286, "z" : 1,  "border" : "TOSBLK2.bmp",  "area" : "TZSBLK2.bmp" },
-				{ "id" : 23, "animation" : "TBSTEXT2.def", "x" : 313, "y" : 13,  "z" : -1, "border" : "TOSVAH.bmp",   "area" : "TZSVAH.bmp" },
-				{ "id" : 26, "animation" : "TBSTHOLY.def", "x" : 321, "y" : 105, "z" : 2,  "border" : "TOSHOLYA.bmp", "area" : "TZSHOLYA.bmp" },
-				{ "id" : 30, "animation" : "TBSTDW_0.def", "x" : 373, "y" : 239, "border" : "TOSGOB1.bmp",  "area" : "TZSGOB1.bmp" },
-				{ "id" : 31, "animation" : "TBSTDW_1.def", "x" : 266, "y" : 246, "z" : 1,  "border" : "TOSWOL1.bmp",  "area" : "TZSWOL1.bmp" },
-				{ "id" : 32, "animation" : "TBSTDW_2.def", "x" : 566, "y" : 232, "z" : 2,  "border" : "TOSORC1.bmp",  "area" : "TZSORC1.bmp" },
-				{ "id" : 33, "animation" : "TBSTDW_3.def", "x" : 197, "y" : 204, "border" : "TOSOGR1.bmp",  "area" : "TZSOGR1.bmp" },
-				{ "id" : 34, "animation" : "TBSTDW_4.def", "x" : 137, "y" : 30,  "z" : -1, "border" : "TOSROC1.bmp",  "area" : "TZSROC1.bmp" },
-				{ "id" : 35, "animation" : "TBSTDW_5.def", "x" : 622, "y" : 160, "z" : -2, "border" : "TOSCYC1.bmp",  "area" : "TZSCYC1.bmp" },
-				{ "id" : 36, "animation" : "TBSTDW_6.def", "x" : 604, "y" : 0,   "border" : "TOSBEH1A.bmp", "area" : "TZSBEH1A.bmp" },
-				{ "id" : 37, "animation" : "TBSTUP_0.def", "x" : 373, "y" : 220, "border" : "TOSGOB2.bmp",  "area" : "TZSGOB2.bmp" },
-				{ "id" : 38, "animation" : "TBSTUP_1.def", "x" : 266, "y" : 225, "z" : 1,  "border" : "TOSWOL2.bmp",  "area" : "TZSWOL2.bmp" },
-				{ "id" : 39, "animation" : "TBSTUP_2.def", "x" : 566, "y" : 158, "z" : 2,  "border" : "TOSORC2.bmp",  "area" : "TZSORC2.bmp" },
-				{ "id" : 40, "animation" : "TBSTUP_3.def", "x" : 197, "y" : 137, "border" : "TOSOGR2.bmp",  "area" : "TZSOGR2.bmp" },
-				{ "id" : 41, "animation" : "TBSTUP_4.def", "x" : 129, "y" : 15,  "z" : -1, "border" : "TOSROC2.bmp",  "area" : "TZSROC2.bmp" },
-				{ "id" : 42, "animation" : "TBSTUP_5.def", "x" : 616, "y" : 93,  "z" : -2, "border" : "TOSCYC2A.bmp", "area" : "TZSCYC2A.bmp" },
-				{ "id" : 43, "animation" : "TBSTUP_6.def", "x" : 604, "y" : 0,   "border" : "TOSBEH2A.bmp", "area" : "TZSBEH2A.bmp" }
-			],
+			{
+				"extraAnimation": { "animation" : "TBSTEXT3.def", "x" : 23,  "y" : 20 },
+				"mageGuild1":     { "id" : 0,  "animation" : "TBSTMAGE.def", "x" : 473, "y" : 67,  "z" : -1, "border" : "TOSMAG1.bmp",  "area" : "TZSMAG1.bmp" },
+				"mageGuild2":     { "id" : 1,  "animation" : "TBSTMAG2.def", "x" : 473, "y" : 37,  "z" : -1, "border" : "TOSMAG2.bmp",  "area" : "TZSMAG2.bmp" },
+				"mageGuild3":     { "id" : 2,  "animation" : "TBSTMAG3.def", "x" : 473, "y" : 1,   "z" : -1, "border" : "TOSMAG3.bmp",  "area" : "TZSMAG3.bmp" },
+				"tavern":         { "id" : 5,  "animation" : "TBSTTVRN.def", "x" : 170, "y" : 280, "z" : 2,  "border" : "TOSTAV.bmp",   "area" : "TZSTAV.bmp" },
+				"fort":           { "id" : 7,  "animation" : "TBSTCSTL.def", "x" : 402, "y" : 148, "z" : -1, "border" : "TOSCA1.bmp",   "area" : "TZSCA1.bmp" },
+				"citadel":        { "id" : 8,  "animation" : "TBSTCAS2.def", "x" : 402, "y" : 114, "z" : -1, "border" : "TOSCA2.bmp",   "area" : "TZSCA2.bmp" },
+				"castle":         { "id" : 9,  "animation" : "TBSTCAS3.def", "x" : 402, "y" : 114, "z" : -1, "border" : "TOSCA3.bmp",   "area" : "TZSCA3.bmp" },
+				"villageHall":    { "id" : 10, "animation" : "TBSTHALL.def", "x" : 0,   "y" : 259, "border" : "TOSHAL1A.bmp", "area" : "TZSHAL1A.bmp" },
+				"townHall":       { "id" : 11, "animation" : "TBSTHAL2.def", "x" : 0,   "y" : 225, "border" : "TOSHAL2A.bmp", "area" : "TZSHAL2A.bmp" },
+				"cityHall":       { "id" : 12, "animation" : "TBSTHAL3.def", "x" : 0,   "y" : 201, "border" : "TOSHAL3A.bmp", "area" : "TZSHAL3A.bmp" },
+				"capitol":        { "id" : 13, "animation" : "TBSTHAL4.def", "x" : 0,   "y" : 148, "border" : "TOSHAL4A.bmp", "area" : "TZSHAL4A.bmp" },
+				"marketplace":    { "id" : 14, "animation" : "TBSTMARK.def", "x" : 397, "y" : 308, "z" : 1,  "border" : "TOSMRK1.bmp",  "area" : "TZSMRK1.bmp" },
+				"resourceSilo":  { "id" : 15, "animation" : "TBSTSILO.def", "x" : 458, "y" : 248, "z" : 1,  "border" : "TOSMRK2.bmp",  "area" : "TZSMRK2.bmp" },
+				"blacksmith":     { "id" : 16, "animation" : "TBSTBLAK.def", "x" : 660, "y" : 286, "border" : "TOSBLK1.bmp",  "area" : "TZSBLK1.bmp" },
+				"special1":       { "id" : 17, "animation" : "TBSTSPEC.def", "x" : 550, "y" : 229, "border" : "TOSCA1EA.bmp", "area" : "TZSCA1EA.bmp" },
+				"horde1":         { "id" : 18, "animation" : "TBSTHRD1.def", "x" : 373, "y" : 239, "border" : "TOSGOB1H.bmp", "area" : "TZSGOB1H.bmp", "hidden" : true },
+				"horde1Upgr":     { "id" : 19, "animation" : "TBSTHRD2.def", "x" : 373, "y" : 220, "border" : "TOSGOB2H.bmp", "area" : "TZSGOB2H.bmp", "hidden" : true, "builds" : 18 },
+				"special2":       { "id" : 21, "animation" : "TBSTEXT0.def", "x" : 473, "y" : 282, "z" : 3,  "border" : "TOSMRK1C.bmp", "area" : "TZSMRK1C.bmp" },
+				"special3":       { "id" : 22, "animation" : "TBSTEXT1.def", "x" : 617, "y" : 286, "z" : 1,  "border" : "TOSBLK2.bmp",  "area" : "TZSBLK2.bmp" },
+				"special4":       { "id" : 23, "animation" : "TBSTEXT2.def", "x" : 313, "y" : 13,  "z" : -1, "border" : "TOSVAH.bmp",   "area" : "TZSVAH.bmp" },
+				"grail":          { "id" : 26, "animation" : "TBSTHOLY.def", "x" : 321, "y" : 105, "z" : 2,  "border" : "TOSHOLYA.bmp", "area" : "TZSHOLYA.bmp" },
+				"dwellingLvl1":   { "id" : 30, "animation" : "TBSTDW_0.def", "x" : 373, "y" : 239, "border" : "TOSGOB1.bmp",  "area" : "TZSGOB1.bmp" },
+				"dwellingLvl2":   { "id" : 31, "animation" : "TBSTDW_1.def", "x" : 266, "y" : 246, "z" : 1,  "border" : "TOSWOL1.bmp",  "area" : "TZSWOL1.bmp" },
+				"dwellingLvl3":   { "id" : 32, "animation" : "TBSTDW_2.def", "x" : 566, "y" : 232, "z" : 2,  "border" : "TOSORC1.bmp",  "area" : "TZSORC1.bmp" },
+				"dwellingLvl4":   { "id" : 33, "animation" : "TBSTDW_3.def", "x" : 197, "y" : 204, "border" : "TOSOGR1.bmp",  "area" : "TZSOGR1.bmp" },
+				"dwellingLvl5":   { "id" : 34, "animation" : "TBSTDW_4.def", "x" : 137, "y" : 30,  "z" : -1, "border" : "TOSROC1.bmp",  "area" : "TZSROC1.bmp" },
+				"dwellingLvl6":   { "id" : 35, "animation" : "TBSTDW_5.def", "x" : 622, "y" : 160, "z" : -2, "border" : "TOSCYC1.bmp",  "area" : "TZSCYC1.bmp" },
+				"dwellingLvl7":   { "id" : 36, "animation" : "TBSTDW_6.def", "x" : 604, "y" : 0,   "border" : "TOSBEH1A.bmp", "area" : "TZSBEH1A.bmp" },
+				"dwellingUpLvl1": { "id" : 37, "animation" : "TBSTUP_0.def", "x" : 373, "y" : 220, "border" : "TOSGOB2.bmp",  "area" : "TZSGOB2.bmp" },
+				"dwellingUpLvl2": { "id" : 38, "animation" : "TBSTUP_1.def", "x" : 266, "y" : 225, "z" : 1,  "border" : "TOSWOL2.bmp",  "area" : "TZSWOL2.bmp" },
+				"dwellingUpLvl3": { "id" : 39, "animation" : "TBSTUP_2.def", "x" : 566, "y" : 158, "z" : 2,  "border" : "TOSORC2.bmp",  "area" : "TZSORC2.bmp" },
+				"dwellingUpLvl4": { "id" : 40, "animation" : "TBSTUP_3.def", "x" : 197, "y" : 137, "border" : "TOSOGR2.bmp",  "area" : "TZSOGR2.bmp" },
+				"dwellingUpLvl5": { "id" : 41, "animation" : "TBSTUP_4.def", "x" : 129, "y" : 15,  "z" : -1, "border" : "TOSROC2.bmp",  "area" : "TZSROC2.bmp" },
+				"dwellingUpLvl6": { "id" : 42, "animation" : "TBSTUP_5.def", "x" : 616, "y" : 93,  "z" : -2, "border" : "TOSCYC2A.bmp", "area" : "TZSCYC2A.bmp" },
+				"dwellingUpLvl7": { "id" : 43, "animation" : "TBSTUP_6.def", "x" : 604, "y" : 0,   "border" : "TOSBEH2A.bmp", "area" : "TZSBEH2A.bmp" }
+			},
 			"icons" :
 			{
 				"village" : {"normal" : 30, "built" : 31 },
@@ -147,48 +147,50 @@
 			"moatDamage" : 70,
 
 			"buildings" :
-			[
-				{ "id" : 0 },
-				{ "id" : 1,  "upgrades" : 0 },
-				{ "id" : 2,  "upgrades" : 1 },
-				{ "id" : 3,  "upgrades" : 2 },
-				{ "id" : 4,  "upgrades" : 3 },
-				{ "id" : 5 },
-				{ "id" : 7 },
-				{ "id" : 8,  "upgrades" : 7 },
-				{ "id" : 9,  "upgrades" : 8 },
-				{ "id" : 10, "mode" : "auto" },
-				{ "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
-				{ "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
-				{ "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
-				{ "id" : 14 },
-				{ "id" : 15, "requires" : [ 14 ] },
-				{ "id" : 16 },
-				{ "id" : 17, "requires" : [ 7 ] },
-				{ "id" : 18, "upgrades" : 30 },
-				{ "id" : 19, "upgrades" : 37, "requires" : [ 18 ], "mode" : "auto" },
-				{ "id" : 21, "requires" : [ 14 ] },
-				{ "id" : 22, "requires" : [ 16 ] },
-				{ "id" : 23, "requires" : [ 7 ] },
-				{ "id" : 26, "mode" : "grail"},
-				{ "id" : 27, "requires" : [ 11 ], "mode" : "auto" },
-				{ "id" : 28, "requires" : [ 12 ], "mode" : "auto" },
-				{ "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
-				{ "id" : 30, "requires" : [ 7 ] },
-				{ "id" : 31, "requires" : [ 30 ] },
-				{ "id" : 32, "requires" : [ 30 ] },
-				{ "id" : 33, "requires" : [ 32 ] },
-				{ "id" : 34, "requires" : [ 31 ] },
-				{ "id" : 35, "requires" : [ 33 ] },
-				{ "id" : 36, "requires" : [ 34 ] },
-				{ "id" : 37, "upgrades" : 30 },
-				{ "id" : 38, "upgrades" : 31, "requires" : [ 37 ] },
-				{ "id" : 39, "upgrades" : 32, "requires" : [ 16 ] },
-				{ "id" : 40, "upgrades" : 33, "requires" : [ 0 ] },
-				{ "id" : 41, "upgrades" : 34 },
-				{ "id" : 42, "upgrades" : 35 },
-				{ "id" : 43, "upgrades" : 36 }
-			],
+			{
+				"mageGuild1":     { "id" : 0 },
+				"mageGuild2":     { "id" : 1,  "upgrades" : 0 },
+				"mageGuild3":     { "id" : 2,  "upgrades" : 1 },
+				"tavern":         { "id" : 5 },
+				"fort":           { "id" : 7 },
+				"citadel":        { "id" : 8,  "upgrades" : 7 },
+				"castle":         { "id" : 9,  "upgrades" : 8 },
+				"villageHall":    { "id" : 10, "mode" : "auto" },
+				"townHall":       { "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
+				"cityHall":       { "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
+				"capitol":        { "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
+				"marketplace":    { "id" : 14 },
+				"resourceSilo":  { "id" : 15, "requires" : [ 14 ] },
+				"blacksmith":     { "id" : 16 },
+				"special1":       { "id" : 17, "requires" : [ 7 ] },
+				"horde1":         { "id" : 18, "upgrades" : 30 },
+				"horde1Upgr":     { "id" : 19, "upgrades" : 37, "requires" : [ 18 ], "mode" : "auto" },
+				"special2":       { "id" : 21, "requires" : [ 14 ] },
+				"special3":       { "id" : 22, "requires" : [ 16 ] },
+				"special4":       { "id" : 23, "requires" : [ 7 ] },
+				"grail":          { "id" : 26, "mode" : "grail"},
+				"dwellingLvl1":   { "id" : 30, "requires" : [ 7 ] },
+				"dwellingLvl2":   { "id" : 31, "requires" : [ 30 ] },
+				"dwellingLvl3":   { "id" : 32, "requires" : [ 30 ] },
+				"dwellingLvl4":   { "id" : 33, "requires" : [ 32 ] },
+				"dwellingLvl5":   { "id" : 34, "requires" : [ 31 ] },
+				"dwellingLvl6":   { "id" : 35, "requires" : [ 33 ] },
+				"dwellingLvl7":   { "id" : 36, "requires" : [ 34 ] },
+				"dwellingUpLvl1": { "id" : 37, "upgrades" : 30 },
+				"dwellingUpLvl2": { "id" : 38, "upgrades" : 31, "requires" : [ 37 ] },
+				"dwellingUpLvl3": { "id" : 39, "upgrades" : 32, "requires" : [ 16 ] },
+				"dwellingUpLvl4": { "id" : 40, "upgrades" : 33, "requires" : [ 0 ] },
+				"dwellingUpLvl5": { "id" : 41, "upgrades" : 34 },
+				"dwellingUpLvl6": { "id" : 42, "upgrades" : 35 },
+				"dwellingUpLvl7": { "id" : 43, "upgrades" : 36 },
+				
+				"horde2" : null,
+				"horde2Upgr" : null,
+				"mageGuild4" : null,
+				"mageGuild5" : null,
+				"ship" : null,
+				"shipyard" : null
+			},
 
 			"siege" :
 			{

+ 83 - 81
config/factions/tower.json

@@ -74,45 +74,45 @@
 				"capitol" : "AVCTOWZ0.DEF"
 			},
 			"structures" :
-			[
-				{ "id" : 0,  "animation" : "TBTWMAGE.def", "x" : 597, "y" : 82,  "border" : "TOTGLD1.bmp",  "area" : "TZTGLD1.bmp" },
-				{ "id" : 1,  "animation" : "TBTWMAG2.def", "x" : 593, "y" : 65,  "border" : "TOTGLD2.bmp",  "area" : "TZTGLD2.bmp" },
-				{ "id" : 2,  "animation" : "TBTWMAG3.def", "x" : 593, "y" : 48,  "border" : "TOTGLD3.bmp",  "area" : "TZTGLD3.bmp" },
-				{ "id" : 3,  "animation" : "TBTWMAG4.def", "x" : 593, "y" : 31,  "border" : "TOTGLD4.bmp",  "area" : "TZTGLD4.bmp" },
-				{ "id" : 4,  "animation" : "TBTWMAG5.def", "x" : 593, "y" : 14,  "border" : "TOTGLD5.bmp",  "area" : "TZTGLD5.bmp" },
-				{ "id" : 5,  "animation" : "TBTWTVRN.def", "x" : 375, "y" : 278, "z" : 1, "border" : "TOTTAV.bmp",   "area" : "TZTTAV.bmp" },
-				{ "id" : 7,  "animation" : "TBTWCSTL.def", "x" : 304, "y" : 0,   "border" : "TOTCAS1.bmp",  "area" : "TZTCAS1.bmp" },
-				{ "id" : 8,  "animation" : "TBTWCAS2.def", "x" : 301, "y" : 0,   "border" : "TOTCAS2.bmp",  "area" : "TZTCAS2.bmp" },
-				{ "id" : 9,  "animation" : "TBTWCAS3.def", "x" : 301, "y" : 0,   "border" : "TOTCAS3.bmp",  "area" : "TZTCAS3.bmp" },
-				{ "id" : 10, "animation" : "TBTWHALL.def", "x" : 0,   "y" : 259, "z" : 1,  "border" : "TOTHAL1.bmp",  "area" : "TZTHAL1.bmp" },
-				{ "id" : 11, "animation" : "TBTWHAL2.def", "x" : 0,   "y" : 220, "z" : 1,  "border" : "TOTHAL2.bmp",  "area" : "TZTHAL2.bmp" },
-				{ "id" : 12, "animation" : "TBTWHAL3.def", "x" : 0,   "y" : 82,  "z" : 1,  "border" : "TOTHAL3.bmp",  "area" : "TZTHAL3.bmp" },
-				{ "id" : 13, "animation" : "TBTWHAL4.def", "x" : 0,   "y" : 82,  "z" : 1,  "border" : "TOTHAL4.bmp",  "area" : "TZTHAL4.bmp" },
-				{ "id" : 14, "animation" : "TBTWMARK.def", "x" : 614, "y" : 292, "border" : "TOTMRK.bmp",   "area" : "TZTMRK.bmp" },
-				{ "id" : 15, "animation" : "TBTWSILO.def", "x" : 763, "y" : 214, "z" : 3, "border" : "TOTMRKS.bmp",  "area" : "TZTMRKS.bmp" },
-				{ "id" : 16, "animation" : "TBTWBLAK.def", "x" : 478, "y" : 211, "border" : "TOTBLKA.bmp",  "area" : "TZTBLKA.bmp" },
-				{ "id" : 17, "animation" : "TBTWSPEC.def", "x" : 674, "y" : 276, "z" : 2, "border" : "TOTMRKA.bmp",  "area" : "TZTMRKA.bmp" },
-				{ "id" : 18, "animation" : "TBTWHRD1.def", "x" : 0,   "y" : 47,  "border" : "TOTGAR1H.bmp", "area" : "TZTGAR1H.bmp", "hidden" : true },
-				{ "id" : 19, "animation" : "TBTWHRD2.def", "x" : 0,   "y" : 28,  "border" : "TOTGAR2H.bmp", "area" : "TZTGAR2H.bmp", "hidden" : true, "builds" : 18 },
-				{ "id" : 21, "animation" : "TBTWEXT0.def", "x" : 409, "y" : 82,  "border" : "TOTCASW.bmp",  "area" : "TZTCASW.bmp" },
-				{ "id" : 22, "animation" : "TBTWEXT1.def", "x" : 702, "y" : 115, "border" : "TOTGLDL.bmp",  "area" : "TZTGLDL.bmp" },
-				{ "id" : 23, "animation" : "TBTWEXT2.def", "x" : 592, "y" : 189, "z" : 1,  "border" : "TOTGLDW.bmp",  "area" : "TZTGLDW.bmp" },
-				{ "id" : 26, "animation" : "TBTWHOLY.def", "x" : 237, "y" : 14,  "z" : -1, "border" : "TOTHOLYA.bmp", "area" : "TZTHOLYA.bmp" },
-				{ "id" : 30, "animation" : "TBTWDW_0.def", "x" : 453, "y" : 221, "z" : 1,  "border" : "TOTGRM1A.bmp", "area" : "TZTGRM1A.bmp" },
-				{ "id" : 31, "animation" : "TBTWDW_1.def", "x" : 4,   "y" : 46,  "border" : "TOTGAR1.bmp",  "area" : "TZTGAR1.bmp" },
-				{ "id" : 32, "animation" : "TBTWDW_2.def", "x" : 209, "y" : 177, "z" : 1,  "border" : "TOTGOL1A.bmp", "area" : "TZTGOL1A.bmp" },
-				{ "id" : 33, "animation" : "TBTWDW_3.def", "x" : 613, "y" : 95,  "border" : "TOTMAG1.bmp",  "area" : "TZTMAG1.bmp" },
-				{ "id" : 34, "animation" : "TBTWDW_4.def", "x" : 511, "y" : 75,  "border" : "TOTGEN1.bmp",  "area" : "TZTGEN1.bmp" },
-				{ "id" : 35, "animation" : "TBTWDW_5.def", "x" : 681, "y" : 208, "z" : 2,  "border" : "TOTNAG1.bmp",  "area" : "TZTNAG1.bmp" },
-				{ "id" : 36, "animation" : "TBTWDW_6.def", "x" : 75,  "y" : 144, "z" : -1, "border" : "TOTTIT1.bmp",  "area" : "TZTTIT1.bmp" },
-				{ "id" : 37, "animation" : "TBTWUP_0.def", "x" : 446, "y" : 221, "z" : 1,  "border" : "TOTGRM2A.bmp", "area" : "TZTGRM2A.bmp" },
-				{ "id" : 38, "animation" : "TBTWUP_1.def", "x" : 4,   "y" : 28,  "border" : "TOTGAR2.bmp",  "area" : "TZTGAR2.bmp" },
-				{ "id" : 39, "animation" : "TBTWUP_2.def", "x" : 209, "y" : 177, "z" : 1,  "border" : "TOTGOL2A.bmp", "area" : "TZTGOL2A.bmp" },
-				{ "id" : 40, "animation" : "TBTWUP_3.def", "x" : 613, "y" : 74,  "border" : "TOTMAG2.bmp",  "area" : "TZTMAG2.bmp" },
-				{ "id" : 41, "animation" : "TBTWUP_4.def", "x" : 511, "y" : 8,   "border" : "TOTGEN2.bmp",  "area" : "TZTGEN2.bmp" },
-				{ "id" : 42, "animation" : "TBTWUP_5.def", "x" : 681, "y" : 157, "z" : 2,  "border" : "TOTNAG2.bmp",  "area" : "TZTNAG2.bmp" },
-				{ "id" : 43, "animation" : "TBTWUP_6.def", "x" : 75,  "y" : 91,  "z" : -1, "border" : "TOTTIT2.bmp",  "area" : "TZTTIT2.bmp" }
-			],
+			{
+				"mageGuild1":     { "id" : 0,  "animation" : "TBTWMAGE.def", "x" : 597, "y" : 82,  "border" : "TOTGLD1.bmp",  "area" : "TZTGLD1.bmp" },
+				"mageGuild2":     { "id" : 1,  "animation" : "TBTWMAG2.def", "x" : 593, "y" : 65,  "border" : "TOTGLD2.bmp",  "area" : "TZTGLD2.bmp" },
+				"mageGuild3":     { "id" : 2,  "animation" : "TBTWMAG3.def", "x" : 593, "y" : 48,  "border" : "TOTGLD3.bmp",  "area" : "TZTGLD3.bmp" },
+				"mageGuild4":     { "id" : 3,  "animation" : "TBTWMAG4.def", "x" : 593, "y" : 31,  "border" : "TOTGLD4.bmp",  "area" : "TZTGLD4.bmp" },
+				"mageGuild5":     { "id" : 4,  "animation" : "TBTWMAG5.def", "x" : 593, "y" : 14,  "border" : "TOTGLD5.bmp",  "area" : "TZTGLD5.bmp" },
+				"tavern":         { "id" : 5,  "animation" : "TBTWTVRN.def", "x" : 375, "y" : 278, "z" : 1, "border" : "TOTTAV.bmp",   "area" : "TZTTAV.bmp" },
+				"fort":           { "id" : 7,  "animation" : "TBTWCSTL.def", "x" : 304, "y" : 0,   "border" : "TOTCAS1.bmp",  "area" : "TZTCAS1.bmp" },
+				"citadel":        { "id" : 8,  "animation" : "TBTWCAS2.def", "x" : 301, "y" : 0,   "border" : "TOTCAS2.bmp",  "area" : "TZTCAS2.bmp" },
+				"castle":         { "id" : 9,  "animation" : "TBTWCAS3.def", "x" : 301, "y" : 0,   "border" : "TOTCAS3.bmp",  "area" : "TZTCAS3.bmp" },
+				"villageHall":    { "id" : 10, "animation" : "TBTWHALL.def", "x" : 0,   "y" : 259, "z" : 1,  "border" : "TOTHAL1.bmp",  "area" : "TZTHAL1.bmp" },
+				"townHall":       { "id" : 11, "animation" : "TBTWHAL2.def", "x" : 0,   "y" : 220, "z" : 1,  "border" : "TOTHAL2.bmp",  "area" : "TZTHAL2.bmp" },
+				"cityHall":       { "id" : 12, "animation" : "TBTWHAL3.def", "x" : 0,   "y" : 82,  "z" : 1,  "border" : "TOTHAL3.bmp",  "area" : "TZTHAL3.bmp" },
+				"capitol":        { "id" : 13, "animation" : "TBTWHAL4.def", "x" : 0,   "y" : 82,  "z" : 1,  "border" : "TOTHAL4.bmp",  "area" : "TZTHAL4.bmp" },
+				"marketplace":    { "id" : 14, "animation" : "TBTWMARK.def", "x" : 614, "y" : 292, "border" : "TOTMRK.bmp",   "area" : "TZTMRK.bmp" },
+				"resourceSilo":  { "id" : 15, "animation" : "TBTWSILO.def", "x" : 763, "y" : 214, "z" : 3, "border" : "TOTMRKS.bmp",  "area" : "TZTMRKS.bmp" },
+				"blacksmith":     { "id" : 16, "animation" : "TBTWBLAK.def", "x" : 478, "y" : 211, "border" : "TOTBLKA.bmp",  "area" : "TZTBLKA.bmp" },
+				"special1":       { "id" : 17, "animation" : "TBTWSPEC.def", "x" : 674, "y" : 276, "z" : 2, "border" : "TOTMRKA.bmp",  "area" : "TZTMRKA.bmp" },
+				"horde1":         { "id" : 18, "animation" : "TBTWHRD1.def", "x" : 0,   "y" : 47,  "border" : "TOTGAR1H.bmp", "area" : "TZTGAR1H.bmp", "hidden" : true },
+				"horde1Upgr":     { "id" : 19, "animation" : "TBTWHRD2.def", "x" : 0,   "y" : 28,  "border" : "TOTGAR2H.bmp", "area" : "TZTGAR2H.bmp", "hidden" : true, "builds" : 18 },
+				"special2":       { "id" : 21, "animation" : "TBTWEXT0.def", "x" : 409, "y" : 82,  "border" : "TOTCASW.bmp",  "area" : "TZTCASW.bmp" },
+				"special3":       { "id" : 22, "animation" : "TBTWEXT1.def", "x" : 702, "y" : 115, "border" : "TOTGLDL.bmp",  "area" : "TZTGLDL.bmp" },
+				"special4":       { "id" : 23, "animation" : "TBTWEXT2.def", "x" : 592, "y" : 189, "z" : 1,  "border" : "TOTGLDW.bmp",  "area" : "TZTGLDW.bmp" },
+				"grail":          { "id" : 26, "animation" : "TBTWHOLY.def", "x" : 237, "y" : 14,  "z" : -1, "border" : "TOTHOLYA.bmp", "area" : "TZTHOLYA.bmp" },
+				"dwellingLvl1":   { "id" : 30, "animation" : "TBTWDW_0.def", "x" : 453, "y" : 221, "z" : 1,  "border" : "TOTGRM1A.bmp", "area" : "TZTGRM1A.bmp" },
+				"dwellingLvl2":   { "id" : 31, "animation" : "TBTWDW_1.def", "x" : 4,   "y" : 46,  "border" : "TOTGAR1.bmp",  "area" : "TZTGAR1.bmp" },
+				"dwellingLvl3":   { "id" : 32, "animation" : "TBTWDW_2.def", "x" : 209, "y" : 177, "z" : 1,  "border" : "TOTGOL1A.bmp", "area" : "TZTGOL1A.bmp" },
+				"dwellingLvl4":   { "id" : 33, "animation" : "TBTWDW_3.def", "x" : 613, "y" : 95,  "border" : "TOTMAG1.bmp",  "area" : "TZTMAG1.bmp" },
+				"dwellingLvl5":   { "id" : 34, "animation" : "TBTWDW_4.def", "x" : 511, "y" : 75,  "border" : "TOTGEN1.bmp",  "area" : "TZTGEN1.bmp" },
+				"dwellingLvl6":   { "id" : 35, "animation" : "TBTWDW_5.def", "x" : 681, "y" : 208, "z" : 2,  "border" : "TOTNAG1.bmp",  "area" : "TZTNAG1.bmp" },
+				"dwellingLvl7":   { "id" : 36, "animation" : "TBTWDW_6.def", "x" : 75,  "y" : 144, "z" : -1, "border" : "TOTTIT1.bmp",  "area" : "TZTTIT1.bmp" },
+				"dwellingUpLvl1": { "id" : 37, "animation" : "TBTWUP_0.def", "x" : 446, "y" : 221, "z" : 1,  "border" : "TOTGRM2A.bmp", "area" : "TZTGRM2A.bmp" },
+				"dwellingUpLvl2": { "id" : 38, "animation" : "TBTWUP_1.def", "x" : 4,   "y" : 28,  "border" : "TOTGAR2.bmp",  "area" : "TZTGAR2.bmp" },
+				"dwellingUpLvl3": { "id" : 39, "animation" : "TBTWUP_2.def", "x" : 209, "y" : 177, "z" : 1,  "border" : "TOTGOL2A.bmp", "area" : "TZTGOL2A.bmp" },
+				"dwellingUpLvl4": { "id" : 40, "animation" : "TBTWUP_3.def", "x" : 613, "y" : 74,  "border" : "TOTMAG2.bmp",  "area" : "TZTMAG2.bmp" },
+				"dwellingUpLvl5": { "id" : 41, "animation" : "TBTWUP_4.def", "x" : 511, "y" : 8,   "border" : "TOTGEN2.bmp",  "area" : "TZTGEN2.bmp" },
+				"dwellingUpLvl6": { "id" : 42, "animation" : "TBTWUP_5.def", "x" : 681, "y" : 157, "z" : 2,  "border" : "TOTNAG2.bmp",  "area" : "TZTNAG2.bmp" },
+				"dwellingUpLvl7": { "id" : 43, "animation" : "TBTWUP_6.def", "x" : 75,  "y" : 91,  "z" : -1, "border" : "TOTTIT2.bmp",  "area" : "TZTTIT2.bmp" }
+			},
 			"icons" :
 			{
 				"village" : {"normal" : 22, "built" : 23 },
@@ -150,48 +150,50 @@
 			"moatDamage" : -1,
 
 			"buildings" :
-			[
-				{ "id" : 0 },
-				{ "id" : 1,  "upgrades" : 0 },
-				{ "id" : 2,  "upgrades" : 1 },
-				{ "id" : 3,  "upgrades" : 2 },
-				{ "id" : 4,  "upgrades" : 3 },
-				{ "id" : 5 },
-				{ "id" : 7 },
-				{ "id" : 8,  "upgrades" : 7 },
-				{ "id" : 9,  "upgrades" : 8 },
-				{ "id" : 10, "mode" : "auto" },
-				{ "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
-				{ "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
-				{ "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
-				{ "id" : 14 },
-				{ "id" : 15, "requires" : [ 14 ] },
-				{ "id" : 16 },
-				{ "id" : 17, "requires" : [ 14 ] },
-				{ "id" : 18, "upgrades" : 31 },
-				{ "id" : 19, "upgrades" : 38, "requires" : [ 18 ], "mode" : "auto" },
-				{ "id" : 21, "requires" : [ 7 ] },
-				{ "id" : 22, "requires" : [ 0 ] },
-				{ "id" : 23, "requires" : [ 0 ] },
-				{ "id" : 26, "mode" : "grail"},
-				{ "id" : 27, "requires" : [ 11 ], "mode" : "auto" },
-				{ "id" : 28, "requires" : [ 12 ], "mode" : "auto" },
-				{ "id" : 29, "requires" : [ 13 ], "mode" : "auto" },
-				{ "id" : 30, "requires" : [ 7 ] },
-				{ "id" : 31, "requires" : [ 30 ] },
-				{ "id" : 32, "requires" : [ 30 ] },
-				{ "id" : 33, "requires" : [ 0, 31, 32 ] },
-				{ "id" : 34, "requires" : [ 33 ] },
-				{ "id" : 35, "requires" : [ 33 ] },
-				{ "id" : 36, "requires" : [ 34, 35 ] },
-				{ "id" : 37, "upgrades" : 30 },
-				{ "id" : 38, "upgrades" : 31 },
-				{ "id" : 39, "upgrades" : 32 },
-				{ "id" : 40, "upgrades" : 33, "requires" : [ 22 ] },
-				{ "id" : 41, "upgrades" : 34 },
-				{ "id" : 42, "upgrades" : 35 },
-				{ "id" : 43, "upgrades" : 36 }
-			],
+			{
+				"mageGuild1":     { "id" : 0 },
+				"mageGuild2":     { "id" : 1,  "upgrades" : 0 },
+				"mageGuild3":     { "id" : 2,  "upgrades" : 1 },
+				"mageGuild4":     { "id" : 3,  "upgrades" : 2 },
+				"mageGuild5":     { "id" : 4,  "upgrades" : 3 },
+				"tavern":         { "id" : 5 },
+				"fort":           { "id" : 7 },
+				"citadel":        { "id" : 8,  "upgrades" : 7 },
+				"castle":         { "id" : 9,  "upgrades" : 8 },
+				"villageHall":    { "id" : 10, "mode" : "auto" },
+				"townHall":       { "id" : 11, "upgrades" : 10, "requires" : [ 5 ] },
+				"cityHall":       { "id" : 12, "upgrades" : 11, "requires" : [ 0, 14, 16 ] },
+				"capitol":        { "id" : 13, "upgrades" : 12, "requires" : [ 9 ] },
+				"marketplace":    { "id" : 14 },
+				"resourceSilo":  { "id" : 15, "requires" : [ 14 ] },
+				"blacksmith":     { "id" : 16 },
+				"special1":       { "id" : 17, "requires" : [ 14 ] },
+				"horde1":         { "id" : 18, "upgrades" : 31 },
+				"horde1Upgr":     { "id" : 19, "upgrades" : 38, "requires" : [ 18 ], "mode" : "auto" },
+				"special2":       { "id" : 21, "requires" : [ 7 ] },
+				"special3":       { "id" : 22, "requires" : [ 0 ] },
+				"special4":       { "id" : 23, "requires" : [ 0 ] },
+				"grail":          { "id" : 26, "mode" : "grail"},
+				"dwellingLvl1":   { "id" : 30, "requires" : [ 7 ] },
+				"dwellingLvl2":   { "id" : 31, "requires" : [ 30 ] },
+				"dwellingLvl3":   { "id" : 32, "requires" : [ 30 ] },
+				"dwellingLvl4":   { "id" : 33, "requires" : [ 0, 31, 32 ] },
+				"dwellingLvl5":   { "id" : 34, "requires" : [ 33 ] },
+				"dwellingLvl6":   { "id" : 35, "requires" : [ 33 ] },
+				"dwellingLvl7":   { "id" : 36, "requires" : [ 34, 35 ] },
+				"dwellingUpLvl1": { "id" : 37, "upgrades" : 30 },
+				"dwellingUpLvl2": { "id" : 38, "upgrades" : 31 },
+				"dwellingUpLvl3": { "id" : 39, "upgrades" : 32 },
+				"dwellingUpLvl4": { "id" : 40, "upgrades" : 33, "requires" : [ 22 ] },
+				"dwellingUpLvl5": { "id" : 41, "upgrades" : 34 },
+				"dwellingUpLvl6": { "id" : 42, "upgrades" : 35 },
+				"dwellingUpLvl7": { "id" : 43, "upgrades" : 36 },
+
+				"horde2" : null,
+				"horde2Upgr" : null,
+				"ship" : null,
+				"shipyard" : null
+			},
 
 			"siege" :
 			{

+ 10 - 0
config/gameConfig.json

@@ -45,7 +45,17 @@
 		"config/heroes/conflux.json",
 		"config/heroes/special.json"
 	],
+
+	"artifacts" :
+	[
+		"config/artifacts.json"
+	],
 	
+	"heroClasses" :
+	[
+		"config/heroClasses.json"
+	],
+
 	"bonuses" :
 	[
 		"config/bonuses.json",

+ 18 - 18
config/heroClasses.json

@@ -1,7 +1,7 @@
 {
 	"knight":
 	{
-		"id": 0,
+		"index": 0,
 		"faction" : "castle",
 		"animation":
 		{
@@ -11,7 +11,7 @@
 	},
 	"cleric" :
 	{
-		"id": 1,
+		"index": 1,
 		"faction" : "castle",
 		"animation":
 		{
@@ -21,7 +21,7 @@
 	},
 	"ranger" :
 	{
-		"id": 2,
+		"index": 2,
 		"faction" : "rampart",
 		"animation":
 		{
@@ -31,7 +31,7 @@
 	},
 	"druid" :
 	{
-		"id": 3,
+		"index": 3,
 		"faction" : "rampart",
 		"animation":
 		{
@@ -41,7 +41,7 @@
 	},
 	"alchemist" :
 	{
-		"id": 4,
+		"index": 4,
 		"faction" : "tower",
 		"animation":
 		{
@@ -51,7 +51,7 @@
 	},
 	"wizard" :
 	{
-		"id": 5,
+		"index": 5,
 		"faction" : "tower",
 		"animation":
 		{
@@ -61,7 +61,7 @@
 	},
 	"demoniac" :
 	{
-		"id": 6,
+		"index": 6,
 		"faction" : "inferno",
 		"animation":
 		{
@@ -71,7 +71,7 @@
 	},
 	"heretic" :
 	{
-		"id": 7,
+		"index": 7,
 		"faction" : "inferno",
 		"animation":
 		{
@@ -81,7 +81,7 @@
 	},
 	"deathknight" :
 	{
-		"id": 8,
+		"index": 8,
 		"faction" : "necropolis",
 		"animation":
 		{
@@ -91,7 +91,7 @@
 	},
 	"necromancer" :
 	{
-		"id": 9,
+		"index": 9,
 		"faction" : "necropolis",
 		"animation":
 		{
@@ -101,7 +101,7 @@
 	},
 	"warlock" :
 	{
-		"id": 10,
+		"index": 10,
 		"faction" : "dungeon",
 		"animation":
 		{
@@ -111,7 +111,7 @@
 	},
 	"overlord" :
 	{
-		"id": 11,
+		"index": 11,
 		"faction" : "dungeon",
 		"animation":
 		{
@@ -121,7 +121,7 @@
 	},
 	"barbarian" :
 	{
-		"id": 12,
+		"index": 12,
 		"faction" : "stronghold",
 		"animation":
 		{
@@ -131,7 +131,7 @@
 	},
 	"battlemage" :
 	{
-		"id": 13,
+		"index": 13,
 		"faction" : "stronghold",
 		"animation":
 		{
@@ -141,7 +141,7 @@
 	},
 	"beastmaster" :
 	{
-		"id": 14,
+		"index": 14,
 		"faction" : "fortress",
 		"animation":
 		{
@@ -151,7 +151,7 @@
 	},
 	"witch" :
 	{
-		"id": 15,
+		"index": 15,
 		"faction" : "fortress",
 		"animation":
 		{
@@ -161,7 +161,7 @@
 	},
 	"planeswalker" :
 	{
-		"id": 16,
+		"index": 16,
 		"faction" : "conflux",
 		"animation":
 		{
@@ -171,7 +171,7 @@
 	},
 	"elementalist" :
 	{
-		"id": 17,
+		"index": 17,
 		"faction" : "conflux",
 		"animation":
 		{

+ 16 - 16
config/heroes/castle.json

@@ -1,7 +1,7 @@
 {
 	"orrin":
 	{
-		"id": 0,
+		"index": 0,
 		"class" : "knight",
 		"female": false,
 		"skills":
@@ -16,7 +16,7 @@
 	},
 	"valeska":
 	{
-		"id": 1,
+		"index": 1,
 		"class" : "knight",
 		"female": true,
 		"skills":
@@ -31,7 +31,7 @@
 	},
 	"edric":
 	{
-		"id": 2,
+		"index": 2,
 		"class" : "knight",
 		"female": false,
 		"skills":
@@ -46,7 +46,7 @@
 	},
 	"sylvia":
 	{
-		"id": 3,
+		"index": 3,
 		"class" : "knight",
 		"female": true,
 		"skills":
@@ -61,7 +61,7 @@
 	},
 	"lordHaart":
 	{
-		"id": 4,
+		"index": 4,
 		"class" : "knight",
 		"female": false,
 		"special" : true, // Lord Haart in his living form. Disabled in H3 expansions
@@ -77,7 +77,7 @@
 	},
 	"sorsha":
 	{
-		"id": 5,
+		"index": 5,
 		"class" : "knight",
 		"female": true,
 		"skills":
@@ -92,7 +92,7 @@
 	},
 	"christian":
 	{
-		"id": 6,
+		"index": 6,
 		"class" : "knight",
 		"female": false,
 		"skills":
@@ -107,7 +107,7 @@
 	},
 	"tyris":
 	{
-		"id": 7,
+		"index": 7,
 		"class" : "knight",
 		"female": true,
 		"skills":
@@ -122,7 +122,7 @@
 	},
 	"rion":
 	{
-		"id": 8,
+		"index": 8,
 		"class" : "cleric",
 		"female": false,
 		"spellbook": [ "stoneSkin" ],
@@ -138,7 +138,7 @@
 	},
 	"adela":
 	{
-		"id": 9,
+		"index": 9,
 		"class" : "cleric",
 		"female": true,
 		"spellbook": [ "bless" ],
@@ -154,7 +154,7 @@
 	},
 	"cuthbert":
 	{
-		"id": 10,
+		"index": 10,
 		"class" : "cleric",
 		"female": false,
 		"spellbook": [ "weakness" ],
@@ -170,7 +170,7 @@
 	},
 	"adelaide":
 	{
-		"id": 11,
+		"index": 11,
 		"class" : "cleric",
 		"female": true,
 		"spellbook": [ "frostRing" ],
@@ -185,7 +185,7 @@
 	},
 	"ingham":
 	{
-		"id": 12,
+		"index": 12,
 		"class" : "cleric",
 		"female": false,
 		"spellbook": [ "curse" ],
@@ -201,7 +201,7 @@
 	},
 	"sanya":
 	{
-		"id": 13,
+		"index": 13,
 		"class" : "cleric",
 		"female": true,
 		"spellbook": [ "dispel" ],
@@ -217,7 +217,7 @@
 	},
 	"loynis":
 	{
-		"id": 14,
+		"index": 14,
 		"class" : "cleric",
 		"spellbook": [ "prayer" ],
 		"female": false,
@@ -233,7 +233,7 @@
 	},
 	"caitlin":
 	{
-		"id": 15,
+		"index": 15,
 		"class" : "cleric",
 		"female": true,
 		"spellbook": [ "cure" ],

+ 16 - 16
config/heroes/conflux.json

@@ -1,7 +1,7 @@
 {
 	"pasis":
 	{
-		"id": 128,
+		"index": 128,
 		"class" : "planeswalker",
 		"female": true,
 		"skills":
@@ -17,7 +17,7 @@
 	},
 	"thunar":
 	{
-		"id": 129,
+		"index": 129,
 		"class" : "planeswalker",
 		"female": true,
 		"skills":
@@ -34,7 +34,7 @@
 	},
 	"ignissa":
 	{
-		"id": 130,
+		"index": 130,
 		"class" : "planeswalker",
 		"female": true,
 		"skills":
@@ -51,7 +51,7 @@
 	},
 	"lacus":
 	{
-		"id": 131,
+		"index": 131,
 		"class" : "planeswalker",
 		"female": true,
 		"skills":
@@ -65,7 +65,7 @@
 	},
 	"monere":
 	{
-		"id": 132,
+		"index": 132,
 		"class" : "planeswalker",
 		"female": false,
 		"skills":
@@ -81,7 +81,7 @@
 	},
 	"erdamon":
 	{
-		"id": 133,
+		"index": 133,
 		"class" : "planeswalker",
 		"female": false,
 		"skills":
@@ -98,7 +98,7 @@
 	},
 	"fiur":
 	{
-		"id": 134,
+		"index": 134,
 		"class" : "planeswalker",
 		"female": false,
 		"skills":
@@ -114,7 +114,7 @@
 	},
 	"kalt":
 	{
-		"id": 135,
+		"index": 135,
 		"class" : "planeswalker",
 		"female": false,
 		"skills":
@@ -129,7 +129,7 @@
 	},
 	"luna":
 	{
-		"id": 136,
+		"index": 136,
 		"class" : "elementalist",
 		"spellbook": [ "fireWall" ],
 		"female": true,
@@ -145,7 +145,7 @@
 	},
 	"brissa":
 	{
-		"id": 137,
+		"index": 137,
 		"class" : "elementalist",
 		"female": true,
 		"spellbook": [ "haste" ],
@@ -161,7 +161,7 @@
 	},
 	"ciele":
 	{
-		"id": 138,
+		"index": 138,
 		"class" : "elementalist",
 		"female": true,
 		"spellbook": [ "magicArrow" ],
@@ -177,7 +177,7 @@
 	},
 	"labetha":
 	{
-		"id": 139,
+		"index": 139,
 		"class" : "elementalist",
 		"female": true,
 		"spellbook": [ "stoneSkin" ],
@@ -193,7 +193,7 @@
 	},
 	"inteus":
 	{
-		"id": 140,
+		"index": 140,
 		"class" : "elementalist",
 		"female": false,
 		"spellbook": [ "bloodlust" ],
@@ -209,7 +209,7 @@
 	},
 	"aenain":
 	{
-		"id": 141,
+		"index": 141,
 		"class" : "elementalist",
 		"female": false,
 		"spellbook": [ "disruptingRay" ],
@@ -225,7 +225,7 @@
 	},
 	"gelare":
 	{
-		"id": 142,
+		"index": 142,
 		"class" : "elementalist",
 		"female": false,
 		"spellbook": [ "dispel" ],
@@ -241,7 +241,7 @@
 	},
 	"grindan":
 	{
-		"id": 143,
+		"index": 143,
 		"class" : "elementalist",
 		"female": false,
 		"spellbook": [ "slow" ],

+ 16 - 16
config/heroes/dungeon.json

@@ -1,7 +1,7 @@
 {
 	"lorelei":
 	{
-		"id": 80,
+		"index": 80,
 		"class" : "warlock",
 		"female": true,
 		"skills":
@@ -16,7 +16,7 @@
 	},
 	"arlach":
 	{
-		"id": 81,
+		"index": 81,
 		"class" : "warlock",
 		"female": false,
 		"skills":
@@ -31,7 +31,7 @@
 	},
 	"dace":
 	{
-		"id": 82,
+		"index": 82,
 		"class" : "warlock",
 		"female": false,
 		"skills":
@@ -46,7 +46,7 @@
 	},
 	"ajit":
 	{
-		"id": 83,
+		"index": 83,
 		"class" : "warlock",
 		"female": false,
 		"skills":
@@ -61,7 +61,7 @@
 	},
 	"damacon":
 	{
-		"id": 84,
+		"index": 84,
 		"class" : "warlock",
 		"female": false,
 		"skills":
@@ -75,7 +75,7 @@
 	},
 	"gunnar":
 	{
-		"id": 85,
+		"index": 85,
 		"class" : "warlock",
 		"female": false,
 		"skills":
@@ -90,7 +90,7 @@
 	},
 	"synca":
 	{
-		"id": 86,
+		"index": 86,
 		"class" : "warlock",
 		"female": true,
 		"skills":
@@ -105,7 +105,7 @@
 	},
 	"shakti":
 	{
-		"id": 87,
+		"index": 87,
 		"class" : "warlock",
 		"female": false,
 		"skills":
@@ -120,7 +120,7 @@
 	},
 	"alamar":
 	{
-		"id": 88,
+		"index": 88,
 		"class" : "overlord",
 		"spellbook": [ "resurrection" ],
 		"female": false,
@@ -136,7 +136,7 @@
 	},
 	"jaegar":
 	{
-		"id": 89,
+		"index": 89,
 		"class" : "overlord",
 		"female": false,
 		"spellbook": [ "shield" ],
@@ -152,7 +152,7 @@
 	},
 	"malekith":
 	{
-		"id": 90,
+		"index": 90,
 		"class" : "overlord",
 		"female": false,
 		"spellbook": [ "bloodlust" ],
@@ -168,7 +168,7 @@
 	},
 	"jeddite":
 	{
-		"id": 91,
+		"index": 91,
 		"class" : "overlord",
 		"female": true,
 		"spellbook": [ "resurrection" ],
@@ -183,7 +183,7 @@
 	},
 	"geon":
 	{
-		"id": 92,
+		"index": 92,
 		"class" : "overlord",
 		"female": false,
 		"spellbook": [ "slow" ],
@@ -199,7 +199,7 @@
 	},
 	"deemer":
 	{
-		"id": 93,
+		"index": 93,
 		"class" : "overlord",
 		"female": false,
 		"spellbook": [ "meteorShower" ],
@@ -215,7 +215,7 @@
 	},
 	"sephinroth":
 	{
-		"id": 94,
+		"index": 94,
 		"class" : "overlord",
 		"female": true,
 		"spellbook": [ "protectAir" ],
@@ -231,7 +231,7 @@
 	},
 	"darkstorn":
 	{
-		"id": 95,
+		"index": 95,
 		"class" : "overlord",
 		"female": false,
 		"spellbook": [ "stoneSkin" ],

+ 16 - 16
config/heroes/fortress.json

@@ -1,7 +1,7 @@
 {
 	"bron":
 	{
-		"id": 112,
+		"index": 112,
 		"class" : "beastmaster",
 		"female": false,
 		"skills":
@@ -16,7 +16,7 @@
 	},
 	"drakon":
 	{
-		"id": 113,
+		"index": 113,
 		"class" : "beastmaster",
 		"female": false,
 		"skills":
@@ -31,7 +31,7 @@
 	},
 	"wystan":
 	{
-		"id": 114,
+		"index": 114,
 		"class" : "beastmaster",
 		"female": false,
 		"skills":
@@ -46,7 +46,7 @@
 	},
 	"tazar":
 	{
-		"id": 115,
+		"index": 115,
 		"class" : "beastmaster",
 		"female": false,
 		"skills":
@@ -60,7 +60,7 @@
 	},
 	"alkin":
 	{
-		"id": 116,
+		"index": 116,
 		"class" : "beastmaster",
 		"female": false,
 		"skills":
@@ -75,7 +75,7 @@
 	},
 	"korbac":
 	{
-		"id": 117,
+		"index": 117,
 		"class" : "beastmaster",
 		"female": false,
 		"skills":
@@ -90,7 +90,7 @@
 	},
 	"gerwulf":
 	{
-		"id": 118,
+		"index": 118,
 		"class" : "beastmaster",
 		"female": false,
 		"skills":
@@ -105,7 +105,7 @@
 	},
 	"broghild":
 	{
-		"id": 119,
+		"index": 119,
 		"class" : "beastmaster",
 		"female": false,
 		"skills":
@@ -120,7 +120,7 @@
 	},
 	"mirlanda":
 	{
-		"id": 120,
+		"index": 120,
 		"class" : "witch",
 		"spellbook": [ "weakness" ],
 		"female": true,
@@ -135,7 +135,7 @@
 	},
 	"rosic":
 	{
-		"id": 121,
+		"index": 121,
 		"class" : "witch",
 		"female": true,
 		"spellbook": [ "magicArrow" ],
@@ -151,7 +151,7 @@
 	},
 	"voy":
 	{
-		"id": 122,
+		"index": 122,
 		"class" : "witch",
 		"female": true,
 		"spellbook": [ "slow" ],
@@ -167,7 +167,7 @@
 	},
 	"verdish":
 	{
-		"id": 123,
+		"index": 123,
 		"class" : "witch",
 		"female": true,
 		"spellbook": [ "protectFire" ],
@@ -183,7 +183,7 @@
 	},
 	"merist":
 	{
-		"id": 124,
+		"index": 124,
 		"class" : "witch",
 		"female": true,
 		"spellbook": [ "stoneSkin" ],
@@ -199,7 +199,7 @@
 	},
 	"styg":
 	{
-		"id": 125,
+		"index": 125,
 		"class" : "witch",
 		"female": true,
 		"spellbook": [ "shield" ],
@@ -215,7 +215,7 @@
 	},
 	"andra":
 	{
-		"id": 126,
+		"index": 126,
 		"class" : "witch",
 		"female": true,
 		"spellbook": [ "dispel" ],
@@ -231,7 +231,7 @@
 	},
 	"tiva":
 	{
-		"id": 127,
+		"index": 127,
 		"class" : "witch",
 		"female": true,
 		"spellbook": [ "stoneSkin" ],

+ 16 - 16
config/heroes/inferno.json

@@ -1,7 +1,7 @@
 {
 	"fiona":
 	{
-		"id": 48,
+		"index": 48,
 		"class" : "demoniac",
 		"female": true,
 		"skills":
@@ -15,7 +15,7 @@
 	},
 	"rashka":
 	{
-		"id": 49,
+		"index": 49,
 		"class" : "demoniac",
 		"female": false,
 		"skills":
@@ -30,7 +30,7 @@
 	},
 	"marius":
 	{
-		"id": 50,
+		"index": 50,
 		"class" : "demoniac",
 		"female": true,
 		"skills":
@@ -44,7 +44,7 @@
 	},
 	"ignatius":
 	{
-		"id": 51,
+		"index": 51,
 		"class" : "demoniac",
 		"female": false,
 		"skills":
@@ -59,7 +59,7 @@
 	},
 	"octavia":
 	{
-		"id": 52,
+		"index": 52,
 		"class" : "demoniac",
 		"female": true,
 		"skills":
@@ -74,7 +74,7 @@
 	},
 	"calh":
 	{
-		"id": 53,
+		"index": 53,
 		"class" : "demoniac",
 		"female": false,
 		"skills":
@@ -89,7 +89,7 @@
 	},
 	"pyre":
 	{
-		"id": 54,
+		"index": 54,
 		"class" : "demoniac",
 		"female": true,
 		"skills":
@@ -104,7 +104,7 @@
 	},
 	"nymus":
 	{
-		"id": 55,
+		"index": 55,
 		"class" : "demoniac",
 		"female": true,
 		"skills":
@@ -118,7 +118,7 @@
 	},
 	"ayden":
 	{
-		"id": 56,
+		"index": 56,
 		"class" : "heretic",
 		"spellbook": [ "viewEarth" ],
 		"female": false,
@@ -134,7 +134,7 @@
 	},
 	"xyron":
 	{
-		"id": 57,
+		"index": 57,
 		"class" : "heretic",
 		"female": false,
 		"spellbook": [ "inferno" ],
@@ -150,7 +150,7 @@
 	},
 	"axsis":
 	{
-		"id": 58,
+		"index": 58,
 		"class" : "heretic",
 		"female": false,
 		"spellbook": [ "protectAir" ],
@@ -166,7 +166,7 @@
 	},
 	"olema":
 	{
-		"id": 59,
+		"index": 59,
 		"class" : "heretic",
 		"female": true,
 		"spellbook": [ "weakness" ],
@@ -182,7 +182,7 @@
 	},
 	"calid":
 	{
-		"id": 60,
+		"index": 60,
 		"class" : "heretic",
 		"female": false,
 		"spellbook": [ "haste" ],
@@ -198,7 +198,7 @@
 	},
 	"ash":
 	{
-		"id": 61,
+		"index": 61,
 		"class" : "heretic",
 		"female": true,
 		"spellbook": [ "bloodlust" ],
@@ -214,7 +214,7 @@
 	},
 	"zydar":
 	{
-		"id": 62,
+		"index": 62,
 		"class" : "heretic",
 		"female": false,
 		"spellbook": [ "stoneSkin" ],
@@ -230,7 +230,7 @@
 	},
 	"xarfax":
 	{
-		"id": 63,
+		"index": 63,
 		"class" : "heretic",
 		"female": false,
 		"spellbook": [ "fireball" ],

+ 16 - 16
config/heroes/necropolis.json

@@ -1,7 +1,7 @@
 {
 	"straker":
 	{
-		"id": 64,
+		"index": 64,
 		"class" : "deathknight",
 		"female": false,
 		"spellbook": [ "haste" ],
@@ -17,7 +17,7 @@
 	},
 	"vokial":
 	{
-		"id": 65,
+		"index": 65,
 		"class" : "deathknight",
 		"female": false,
 		"spellbook": [ "stoneSkin" ],
@@ -33,7 +33,7 @@
 	},
 	"moandor":
 	{
-		"id": 66,
+		"index": 66,
 		"class" : "deathknight",
 		"female": false,
 		"spellbook": [ "slow" ],
@@ -49,7 +49,7 @@
 	},
 	"charna":
 	{
-		"id": 67,
+		"index": 67,
 		"class" : "deathknight",
 		"female": true,
 		"spellbook": [ "magicArrow" ],
@@ -65,7 +65,7 @@
 	},
 	"tamika":
 	{
-		"id": 68,
+		"index": 68,
 		"class" : "deathknight",
 		"female": true,
 		"spellbook": [ "magicArrow" ],
@@ -81,7 +81,7 @@
 	},
 	"isra":
 	{
-		"id": 69,
+		"index": 69,
 		"class" : "deathknight",
 		"female": true,
 		"spellbook": [ "magicArrow" ],
@@ -96,7 +96,7 @@
 	},
 	"clavius":
 	{
-		"id": 70,
+		"index": 70,
 		"class" : "deathknight",
 		"female": false,
 		"spellbook": [ "magicArrow" ],
@@ -112,7 +112,7 @@
 	},
 	"galthran":
 	{
-		"id": 71,
+		"index": 71,
 		"class" : "deathknight",
 		"female": false,
 		"spellbook": [ "shield" ],
@@ -128,7 +128,7 @@
 	},
 	"septienna":
 	{
-		"id": 72,
+		"index": 72,
 		"class" : "necromancer",
 		"female": true,
 		"spellbook": [ "deathRipple" ],
@@ -144,7 +144,7 @@
 	},
 	"aislinn":
 	{
-		"id": 73,
+		"index": 73,
 		"class" : "necromancer",
 		"female": true,
 		"spellbook": [ "meteorShower" ],
@@ -160,7 +160,7 @@
 	},
 	"sandro":
 	{
-		"id": 74,
+		"index": 74,
 		"class" : "necromancer",
 		"female": false,
 		"spellbook": [ "slow" ],
@@ -176,7 +176,7 @@
 	},
 	"nimbus":
 	{
-		"id": 75,
+		"index": 75,
 		"class" : "necromancer",
 		"female": false,
 		"spellbook": [ "shield" ],
@@ -192,7 +192,7 @@
 	},
 	"thant":
 	{
-		"id": 76,
+		"index": 76,
 		"class" : "necromancer",
 		"female": false,
 		"spellbook": [ "animateDead" ],
@@ -208,7 +208,7 @@
 	},
 	"xsi":
 	{
-		"id": 77,
+		"index": 77,
 		"class" : "necromancer",
 		"female": true,
 		"spellbook": [ "stoneSkin" ],
@@ -224,7 +224,7 @@
 	},
 	"vidomina":
 	{
-		"id": 78,
+		"index": 78,
 		"class" : "necromancer",
 		"female": true,
 		"spellbook": [ "curse" ],
@@ -239,7 +239,7 @@
 	},
 	"nagash":
 	{
-		"id": 79,
+		"index": 79,
 		"class" : "necromancer",
 		"female": false,
 		"spellbook": [ "protectAir" ],

+ 16 - 16
config/heroes/rampart.json

@@ -1,7 +1,7 @@
 {
 	"mephala":
 	{
-		"id": 16,
+		"index": 16,
 		"class" : "ranger",
 		"female": true,
 		"skills":
@@ -16,7 +16,7 @@
 	},
 	"ufretin":
 	{
-		"id": 17,
+		"index": 17,
 		"class" : "ranger",
 		"female": false,
 		"skills":
@@ -31,7 +31,7 @@
 	},
 	"jenova":
 	{
-		"id": 18,
+		"index": 18,
 		"class" : "ranger",
 		"female": true,
 		"skills":
@@ -45,7 +45,7 @@
 	},
 	"ryland":
 	{
-		"id": 19,
+		"index": 19,
 		"class" : "ranger",
 		"female": false,
 		"skills":
@@ -60,7 +60,7 @@
 	},
 	"thorgrim":
 	{
-		"id": 20,
+		"index": 20,
 		"class" : "ranger",
 		"female": false,
 		"skills":
@@ -74,7 +74,7 @@
 	},
 	"ivor":
 	{
-		"id": 21,
+		"index": 21,
 		"class" : "ranger",
 		"female": false,
 		"skills":
@@ -89,7 +89,7 @@
 	},
 	"clancy":
 	{
-		"id": 22,
+		"index": 22,
 		"class" : "ranger",
 		"female": false,
 		"skills":
@@ -104,7 +104,7 @@
 	},
 	"kyrre":
 	{
-		"id": 23,
+		"index": 23,
 		"class" : "ranger",
 		"female": true,
 		"skills":
@@ -119,7 +119,7 @@
 	},
 	"coronius":
 	{
-		"id": 24,
+		"index": 24,
 		"class" : "druid",
 		"spellbook": [ "slayer" ],
 		"female": false,
@@ -135,7 +135,7 @@
 	},
 	"uland":
 	{
-		"id": 25,
+		"index": 25,
 		"class" : "druid",
 		"female": false,
 		"spellbook": [ "cure" ],
@@ -151,7 +151,7 @@
 	},
 	"elleshar":
 	{
-		"id": 26,
+		"index": 26,
 		"class" : "druid",
 		"female": false,
 		"spellbook": [ "curse" ],
@@ -167,7 +167,7 @@
 	},
 	"gem":
 	{
-		"id": 27,
+		"index": 27,
 		"class" : "druid",
 		"female": true,
 		"spellbook": [ "summonBoat" ],
@@ -183,7 +183,7 @@
 	},
 	"malcom":
 	{
-		"id": 28,
+		"index": 28,
 		"class" : "druid",
 		"female": false,
 		"spellbook": [ "magicArrow" ],
@@ -199,7 +199,7 @@
 	},
 	"melodia":
 	{
-		"id": 29,
+		"index": 29,
 		"class" : "druid",
 		"spellbook": [ "fortune" ],
 		"female": true,
@@ -215,7 +215,7 @@
 	},
 	"alagar":
 	{
-		"id": 30,
+		"index": 30,
 		"class" : "druid",
 		"female": false,
 		"spellbook": [ "iceBolt" ],
@@ -231,7 +231,7 @@
 	},
 	"aeris":
 	{
-		"id": 31,
+		"index": 31,
 		"class" : "druid",
 		"female": false,
 		"spellbook": [ "protectAir" ],

+ 12 - 12
config/heroes/special.json

@@ -2,7 +2,7 @@
 // "special" heroes for campaigns
 	"sirMullich":
 	{
-		"id": 144,
+		"index": 144,
 		"class" : "knight",
 		"female": false,
 		"special" : true,
@@ -17,7 +17,7 @@
 	},
 	"adrienne":
 	{
-		"id": 145,
+		"index": 145,
 		"class" : "witch",
 		"female": true,
 		"special" : true,
@@ -33,7 +33,7 @@
 	},
 	"catherine":
 	{
-		"id": 146,
+		"index": 146,
 		"class" : "knight",
 		"female": true,
 		"special" : true,
@@ -49,7 +49,7 @@
 	},
 	"dracon":
 	{
-		"id": 147,
+		"index": 147,
 		"class" : "wizard",
 		"female": false,
 		"special" : true,
@@ -66,7 +66,7 @@
 	},
 	"gelu":
 	{
-		"id": 148,
+		"index": 148,
 		"class" : "ranger",
 		"female": false,
 		"special" : true,
@@ -83,7 +83,7 @@
 	},
 	"kilgor":
 	{
-		"id": 149,
+		"index": 149,
 		"class" : "barbarian",
 		"female": false,
 		"special" : true,
@@ -100,7 +100,7 @@
 	},
 	"undeadHaart": // undead version of Lord Haart
 	{
-		"id": 150,
+		"index": 150,
 		"class" : "deathknight",
 		"female": false,
 		"special" : true,
@@ -118,7 +118,7 @@
 	},
 	"mutare":
 	{
-		"id": 151,
+		"index": 151,
 		"class" : "warlock",
 		"female": true,
 		"special" : true,
@@ -136,7 +136,7 @@
 	},
 	"roland":
 	{
-		"id": 152,
+		"index": 152,
 		"class" : "knight",
 		"female": false,
 		"special" : true,
@@ -152,7 +152,7 @@
 	},
 	"mutareDrake":
 	{
-		"id": 153,
+		"index": 153,
 		"class" : "warlock",
 		"female": true,
 		"special" : true,
@@ -182,7 +182,7 @@
 	},
 	"boragus":
 	{
-		"id": 154,
+		"index": 154,
 		"class" : "barbarian",
 		"female": false,
 		"special" : true,
@@ -210,7 +210,7 @@
 	},
 	"xeron":
 	{
-		"id": 155,
+		"index": 155,
 		"class" : "demoniac",
 		"female": false,
 		"special" : true,

+ 16 - 16
config/heroes/stronghold.json

@@ -1,7 +1,7 @@
 {
 	"yog":
 	{
-		"id": 96,
+		"index": 96,
 		"class" : "barbarian",
 		"female": false,
 		"skills":
@@ -16,7 +16,7 @@
 	},
 	"gurnisson":
 	{
-		"id": 97,
+		"index": 97,
 		"class" : "barbarian",
 		"female": false,
 		"skills":
@@ -31,7 +31,7 @@
 	},
 	"jabarkas":
 	{
-		"id": 98,
+		"index": 98,
 		"class" : "barbarian",
 		"female": false,
 		"skills":
@@ -46,7 +46,7 @@
 	},
 	"shiva":
 	{
-		"id": 99,
+		"index": 99,
 		"class" : "barbarian",
 		"female": true,
 		"skills":
@@ -61,7 +61,7 @@
 	},
 	"gretchin":
 	{
-		"id": 100,
+		"index": 100,
 		"class" : "barbarian",
 		"female": true,
 		"skills":
@@ -72,7 +72,7 @@
 	},
 	"krellion":
 	{
-		"id": 101,
+		"index": 101,
 		"class" : "barbarian",
 		"female": false,
 		"skills":
@@ -87,7 +87,7 @@
 	},
 	"cragHack":
 	{
-		"id": 102,
+		"index": 102,
 		"class" : "barbarian",
 		"female": false,
 		"skills":
@@ -101,7 +101,7 @@
 	},
 	"tyraxor":
 	{
-		"id": 103,
+		"index": 103,
 		"class" : "barbarian",
 		"female": false,
 		"skills":
@@ -116,7 +116,7 @@
 	},
 	"gird":
 	{
-		"id": 104,
+		"index": 104,
 		"class" : "battlemage",
 		"spellbook": [ "bloodlust" ],
 		"female": true,
@@ -132,7 +132,7 @@
 	},
 	"vey":
 	{
-		"id": 105,
+		"index": 105,
 		"class" : "battlemage",
 		"female": false,
 		"spellbook": [ "magicArrow" ],
@@ -148,7 +148,7 @@
 	},
 	"dessa":
 	{
-		"id": 106,
+		"index": 106,
 		"class" : "battlemage",
 		"female": true,
 		"spellbook": [ "stoneSkin" ],
@@ -164,7 +164,7 @@
 	},
 	"terek":
 	{
-		"id": 107,
+		"index": 107,
 		"class" : "battlemage",
 		"female": false,
 		"spellbook": [ "haste" ],
@@ -180,7 +180,7 @@
 	},
 	"zubin":
 	{
-		"id": 108,
+		"index": 108,
 		"class" : "battlemage",
 		"female": false,
 		"spellbook": [ "precision" ],
@@ -196,7 +196,7 @@
 	},
 	"gundula":
 	{
-		"id": 109,
+		"index": 109,
 		"class" : "battlemage",
 		"spellbook": [ "slow" ],
 		"female": true,
@@ -212,7 +212,7 @@
 	},
 	"oris":
 	{
-		"id": 110,
+		"index": 110,
 		"class" : "battlemage",
 		"female": true,
 		"spellbook": [ "protectAir" ],
@@ -228,7 +228,7 @@
 	},
 	"saurug":
 	{
-		"id": 111,
+		"index": 111,
 		"class" : "battlemage",
 		"female": false,
 		"spellbook": [ "bloodlust" ],

+ 16 - 16
config/heroes/tower.json

@@ -1,7 +1,7 @@
 {
 	"piquedram":
 	{
-		"id": 32,
+		"index": 32,
 		"class" : "alchemist",
 		"female": false,
 		"spellbook": [ "shield" ],
@@ -17,7 +17,7 @@
 	},
 	"thane":
 	{
-		"id": 33,
+		"index": 33,
 		"class" : "alchemist",
 		"female": false,
 		"spellbook": [ "magicArrow" ],
@@ -32,7 +32,7 @@
 	},
 	"josephine":
 	{
-		"id": 34,
+		"index": 34,
 		"class" : "alchemist",
 		"spellbook": [ "haste" ],
 		"female": true,
@@ -48,7 +48,7 @@
 	},
 	"neela":
 	{
-		"id": 35,
+		"index": 35,
 		"class" : "alchemist",
 		"female": true,
 		"spellbook": [ "shield" ],
@@ -64,7 +64,7 @@
 	},
 	"torosar ":
 	{
-		"id": 36,
+		"index": 36,
 		"class" : "alchemist",
 		"female": false,
 		"spellbook": [ "magicArrow" ],
@@ -80,7 +80,7 @@
 	},
 	"fafner":
 	{
-		"id": 37,
+		"index": 37,
 		"class" : "alchemist",
 		"female": false,
 		"spellbook": [ "haste" ],
@@ -96,7 +96,7 @@
 	},
 	"rissa":
 	{
-		"id": 38,
+		"index": 38,
 		"class" : "alchemist",
 		"female": true,
 		"spellbook": [ "magicArrow" ],
@@ -112,7 +112,7 @@
 	},
 	"iona":
 	{
-		"id": 39,
+		"index": 39,
 		"class" : "alchemist",
 		"spellbook": [ "magicArrow" ],
 		"female": true,
@@ -128,7 +128,7 @@
 	},
 	"astral":
 	{
-		"id": 40,
+		"index": 40,
 		"class" : "wizard",
 		"female": false,
 		"spellbook": [ "hypnotize" ],
@@ -143,7 +143,7 @@
 	},
 	"halon":
 	{
-		"id": 41,
+		"index": 41,
 		"class" : "wizard",
 		"female": false,
 		"spellbook": [ "stoneSkin" ],
@@ -159,7 +159,7 @@
 	},
 	"serena":
 	{
-		"id": 42,
+		"index": 42,
 		"class" : "wizard",
 		"female": true,
 		"spellbook": [ "dispel" ],
@@ -175,7 +175,7 @@
 	},
 	"daremyth":
 	{
-		"id": 43,
+		"index": 43,
 		"class" : "wizard",
 		"female": true,
 		"spellbook": [ "fortune" ],
@@ -191,7 +191,7 @@
 	},
 	"theodorus":
 	{
-		"id": 44,
+		"index": 44,
 		"class" : "wizard",
 		"spellbook": [ "shield" ],
 		"female": false,
@@ -207,7 +207,7 @@
 	},
 	"solmyr":
 	{
-		"id": 45,
+		"index": 45,
 		"class" : "wizard",
 		"female": false,
 		"spellbook": [ "chainLightning" ],
@@ -223,7 +223,7 @@
 	},
 	"cyra":
 	{
-		"id": 46,
+		"index": 46,
 		"class" : "wizard",
 		"female": true,
 		"spellbook": [ "haste" ],
@@ -239,7 +239,7 @@
 	},
 	"aine":
 	{
-		"id": 47,
+		"index": 47,
 		"class" : "wizard",
 		"female": true,
 		"spellbook": [ "curse" ],

+ 1 - 1
config/schemas/artifact.json

@@ -33,7 +33,7 @@
 			"enum" : [ "SPECIAL", "TREASURE", "MINOR", "MAJOR", "RELIC" ],
 			"description": "Artifact class, treasure, minor, major or relic"
 		},
-		"id" : {
+		"index" : {
 			"type" : "number",
 			"description" : "Private field to break things, do not use."
 		},

+ 1 - 1
config/schemas/creature.json

@@ -39,7 +39,7 @@
 			"type" : "string",
 			"description" : "Text version of creature abilities. Used only with original creature window"
 		},
-		"id" : {
+		"index" : {
 			"type" : "number",
 			"description" : "Private field to break things, do not use."
 		},

+ 4 - 4
config/schemas/faction.json

@@ -141,8 +141,8 @@
 					"description": "Path to .def file with building icons"
 				},
 				"buildings": {
-					"type" : "array",
-					"items" : {
+					"type" : "object",
+					"additionalProperties" : {
 						"$ref" : "vcmi:townBuilding"
 					}
 				},
@@ -242,8 +242,8 @@
 					"$ref" : "vcmi:townSiege"
 				},
 				"structures": {
-					"type" : "array",
-					"items" : {
+					"type" : "object",
+					"additionalProperties" : {
 						"$ref" : "vcmi:townStructure"
 					}
 				},

+ 1 - 1
config/schemas/hero.json

@@ -32,7 +32,7 @@
 				}
 			}
 		},
-		"id" : {
+		"index" : {
 			"type" : "number",
 			"description" : "Private field to break things, do not use."
 		},

+ 1 - 1
config/schemas/heroClass.json

@@ -50,7 +50,7 @@
 				}
 			}
 		},
-		"id" : {
+		"index" : {
 			"type" : "number",
 			"description" : "Private field to break things, do not use."
 		},

+ 1 - 1
lib/BattleState.cpp

@@ -372,7 +372,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp
 	{
 		curB->town = town;
 		curB->siege = town->fortLevel();
-		curB->terrainType = VLC->townh->factions[town->town->typeID].nativeTerrain;
+		curB->terrainType = VLC->townh->factions[town->subID]->nativeTerrain;
 	}
 	else
 	{

+ 22 - 36
lib/CArtHandler.cpp

@@ -148,10 +148,11 @@ CArtHandler::~CArtHandler()
 {
 }
 
-void CArtHandler::load(bool onlyTxt)
+std::vector<JsonNode> CArtHandler::loadLegacyData(size_t dataSize)
 {
-	if (onlyTxt)
-		return; // looks to be broken anyway...
+	artifacts.resize(dataSize);
+	std::vector<JsonNode> h3Data;
+	h3Data.reserve(dataSize);
 
 	#define ART_POS(x) (  #x)
 	const std::vector<std::string> artSlots = boost::assign::list_of ART_POS_LIST;
@@ -166,11 +167,7 @@ void CArtHandler::load(bool onlyTxt)
 	parser.endLine(); // header
 	parser.endLine();
 
-	std::map<ui32,ui8>::iterator itr;
-
-	std::vector<JsonNode> h3Data;
-
-	for (size_t i = 0; i < GameConstants::ARTIFACTS_QUANTITY; i++)
+	for (size_t i = 0; i < dataSize; i++)
 	{
 		JsonNode artData;
 
@@ -194,42 +191,31 @@ void CArtHandler::load(bool onlyTxt)
 		events.endLine();
 		h3Data.push_back(artData);
 	}
+	return h3Data;
+}
 
-	artifacts.resize(GameConstants::ARTIFACTS_QUANTITY);
-
-	JsonNode config(ResourceID("config/artifacts.json"));
-
-	BOOST_FOREACH(auto & node, config["artifacts"].Struct())
-	{
-		int numeric = node.second["id"].Float();
-		JsonNode & artData = h3Data[numeric];
-		JsonUtils::merge(artData, node.second);
-
-		//JsonUtils::validate(artData, "vcmi:artifact", node.first);
-		artifacts[numeric] = loadArtifact(artData);
-		artifacts[numeric]->id = ArtifactID(numeric);
+void CArtHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
+{
+	auto object = loadFromJson(data);
+	object->id = ArtifactID(artifacts.size());
 
-		VLC->modh->identifiers.registerObject ("artifact." + node.first, numeric);
-	}
+	artifacts.push_back(object);
 
-	for (size_t i=0; i < artifacts.size(); i++)
-	{
-		if (artifacts[i] == nullptr)
-            logGlobal->warnStream() << "Warning: artifact with id " << i << " is missing!";
-	}
+	VLC->modh->identifiers.registerObject(scope, "artifact", name, object->id);
 }
 
-void CArtHandler::load(std::string objectID, const JsonNode & node)
+void CArtHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
 {
-	CArtifact * art = loadArtifact(node);
-	art->id = ArtifactID(artifacts.size());
+	auto object = loadFromJson(data);
+	object->id = ArtifactID(index);
+
+	assert(artifacts[index] == nullptr); // ensure that this id was not loaded before
+	artifacts[index] = object;
 
-	artifacts.push_back(art);
-    logGlobal->traceStream() << "Added artifact: " << objectID;
-	VLC->modh->identifiers.registerObject ("artifact." + objectID, art->id);
+	VLC->modh->identifiers.registerObject(scope, "artifact", name, object->id);
 }
 
-CArtifact * CArtHandler::loadArtifact(const JsonNode & node)
+CArtifact * CArtHandler::loadFromJson(const JsonNode & node)
 {
 	CArtifact * art;
 
@@ -586,7 +572,7 @@ void CArtHandler::initAllowedArtifactsList(const std::vector<bool> &allowed)
 	}
 }
 
-std::vector<bool> CArtHandler::getDefaultAllowedArtifacts() const
+std::vector<bool> CArtHandler::getDefaultAllowed() const
 {
 	std::vector<bool> allowedArtifacts;
 	allowedArtifacts.resize(127, true);

+ 11 - 13
lib/CArtHandler.h

@@ -5,6 +5,7 @@
 #include "../lib/ConstTransitivePtr.h"
 #include "JsonNode.h"
 #include "GameConstants.h"
+#include "IHandlerBase.h"
 
 /*
  * CArtHandler.h, part of VCMI engine
@@ -185,8 +186,10 @@ public:
 	}
 };
 
-class DLL_LINKAGE CArtHandler //handles artifacts
+class DLL_LINKAGE CArtHandler : public IHandlerBase //handles artifacts
 {
+	CArtifact * loadFromJson(const JsonNode & node);
+
 	void addSlot(CArtifact * art, const std::string & slotID);
 	void loadSlots(CArtifact * art, const JsonNode & node);
 	void loadClass(CArtifact * art, const JsonNode & node);
@@ -205,12 +208,6 @@ public:
 	std::set<ArtifactID> bigArtifacts; // Artifacts that cannot be moved to backpack, e.g. war machines.
 	std::set<ArtifactID> growingArtifacts;
 
-	void load(bool onlyTxt = false);
-	/// load artifact from json structure
-	void load(std::string objectID, const JsonNode & node);
-	/// load one artifact from json config
-	CArtifact * loadArtifact(const JsonNode & node);
-
 	void addBonuses(CArtifact *art, const JsonNode &bonusList);
 
 	void fillList(std::vector<CArtifact*> &listToBeFilled, CArtifact::EartClass artifactClass); //fills given empty list with allowed artifacts of gibven class. No side effects
@@ -230,15 +227,16 @@ public:
 	void makeItCreatureArt (ArtifactID aid, bool onlyCreature = true);
 	void makeItCommanderArt (CArtifact * a, bool onlyCommander = true);
 	void makeItCommanderArt (ArtifactID aid, bool onlyCommander = true);
+
 	CArtHandler();
 	~CArtHandler();
 
-	/**
-	 * Gets a list of default allowed artifacts.
-	 *
-	 * @return a list of allowed artifacts, the index is the artifact id
-	 */
-	std::vector<bool> getDefaultAllowedArtifacts() const;
+	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+
+	void loadObject(std::string scope, std::string name, const JsonNode & data) override;
+	void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
+
+	std::vector<bool> getDefaultAllowed() const override;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 2 - 1
lib/CBonusTypeHandler.cpp

@@ -119,6 +119,8 @@ CBonusTypeHandler::CBonusTypeHandler()
 	
 	BONUS_LIST;
 	#undef BONUS_NAME
+
+	load();
 }
 
 CBonusTypeHandler::~CBonusTypeHandler()
@@ -262,7 +264,6 @@ void CBonusTypeHandler::load()
 {
 	const JsonNode gameConf(ResourceID("config/gameConfig.json"));
 	const JsonNode config(JsonUtils::assembleFromFiles(gameConf["bonuses"].convertTo<std::vector<std::string> >()));
-	
 	load(config);
 }
 

+ 1 - 0
lib/CBonusTypeHandler.h

@@ -11,6 +11,7 @@
 #pragma once 
 
 #include "IBonusTypeHandler.h"
+#include "IHandlerBase.h"
 #include "HeroBonus.h"
 
 

+ 39 - 38
lib/CCreatureHandler.cpp

@@ -78,7 +78,7 @@ bool CCreature::isUndead() const
  */
 bool CCreature::isGood () const
 {
-	return VLC->townh->factions[faction].alignment == EAlignment::GOOD;
+	return VLC->townh->factions[faction]->alignment == EAlignment::GOOD;
 }
 
 /**
@@ -87,7 +87,7 @@ bool CCreature::isGood () const
  */
 bool CCreature::isEvil () const
 {
-	return VLC->townh->factions[faction].alignment == EAlignment::EVIL;
+	return VLC->townh->factions[faction]->alignment == EAlignment::EVIL;
 }
 
 si32 CCreature::maxAmount(const std::vector<si32> &res) const //how many creatures can be bought
@@ -129,7 +129,7 @@ std::string CCreature::nodeName() const
 
 bool CCreature::isItNativeTerrain(int terrain) const
 {
-	return VLC->townh->factions[faction].nativeTerrain == terrain;
+	return VLC->townh->factions[faction]->nativeTerrain == terrain;
 }
 
 static void AddAbility(CCreature *cre, const JsonVector &ability_vec)
@@ -263,16 +263,18 @@ void CCreatureHandler::loadBonuses(JsonNode & creature, std::string bonuses)
 	}
 }
 
-void CCreatureHandler::load()
+std::vector<JsonNode> CCreatureHandler::loadLegacyData(size_t dataSize)
 {
+	creatures.resize(dataSize);
 	std::vector<JsonNode> h3Data;
+	h3Data.reserve(dataSize);
 
 	CLegacyConfigParser parser("DATA/ZCRTRAIT.TXT");
 
 	parser.endLine(); // header
 	parser.endLine();
 
-	do
+	for (size_t i=0; i<dataSize; i++)
 	{
 		//loop till non-empty line
 		while (parser.isNextEntryEmpty())
@@ -314,40 +316,51 @@ void CCreatureHandler::load()
 
 		h3Data.push_back(data);
 	}
-	while (parser.endLine());
 
 	loadAnimationInfo(h3Data);
 
-	const JsonNode gameConf(ResourceID("config/gameConfig.json"));
-	JsonNode config(JsonUtils::assembleFromFiles(gameConf["creatures"].convertTo<std::vector<std::string> >()));
+	return h3Data;
+}
 
-	creatures.resize(GameConstants::CREATURES_COUNT);
+void CCreatureHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
+{
+	auto object = loadFromJson(data);
+	object->idNumber = CreatureID(creatures.size());
 
-	BOOST_FOREACH(auto & node, config.Struct())
-	{
-		int numeric = node.second["id"].Float();
+	creatures.push_back(object);
 
-		JsonUtils::merge(h3Data[numeric], node.second);
+	VLC->modh->identifiers.registerObject(scope, "creature", name, object->idNumber);
 
-		//JsonUtils::validate(h3Data[numeric], "vcmi:creature", node.first);
+	BOOST_FOREACH(auto node, data["extraNames"].Vector())
+	{
+		VLC->modh->identifiers.registerObject(scope, "creature", node.String(), object->idNumber);
+	}
+}
 
-		creatures[numeric] = loadCreature(h3Data[numeric]);
-		creatures[numeric]->idNumber = CreatureID(numeric);
+void CCreatureHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
+{
+	auto object = loadFromJson(data);
+	object->idNumber = CreatureID(index);
 
-		VLC->modh->identifiers.registerObject ("creature." + node.first, numeric);
+	assert(creatures[index] == nullptr); // ensure that this id was not loaded before
+	creatures[index] = object;
 
-		// Alternative names, if any
-		BOOST_FOREACH(const JsonNode &name, h3Data[numeric]["extraNames"].Vector())
-			VLC->modh->identifiers.registerObject ("creature." + name.String(), numeric);
+	VLC->modh->identifiers.registerObject(scope, "creature", name, object->idNumber);
+	BOOST_FOREACH(auto node, data["extraNames"].Vector())
+	{
+		VLC->modh->identifiers.registerObject(scope, "creature", node.String(), object->idNumber);
 	}
+}
 
-	for (size_t i=0; i < creatures.size(); i++)
+std::vector<bool> CCreatureHandler::getDefaultAllowed() const
+{
+	std::vector<bool> ret;
+
+	BOOST_FOREACH(const CCreature * crea, creatures)
 	{
-		if (creatures[i] == nullptr)
-			logGlobal->warnStream() << "Warning: creature with id " << i << " is missing!";
+		ret.push_back(crea ? !crea->special : false);
 	}
-
-	loadCrExpBon();
+	return ret;
 }
 
 void CCreatureHandler::loadCrExpBon()
@@ -508,19 +521,7 @@ void CCreatureHandler::loadUnitAnimInfo(JsonNode & graphics, CLegacyConfigParser
 		graphics.Struct().erase("missile");
 }
 
-void CCreatureHandler::load(std::string creatureID, const JsonNode & node)
-{
-	CCreature * creature = loadCreature(node);
-	creature->nameRef = creatureID;
-	creature->idNumber = CreatureID(creatures.size());
-
-	creatures.push_back(creature);
-    logGlobal->traceStream() << "Added creature: " << creatureID;
-
-	VLC->modh->identifiers.registerObject ("creature." + creature->nameRef, creature->idNumber);
-}
-
-CCreature * CCreatureHandler::loadCreature(const JsonNode & node)
+CCreature * CCreatureHandler::loadFromJson(const JsonNode & node)
 {
 	CCreature * cre = new CCreature();
 

+ 33 - 22
lib/CCreatureHandler.h

@@ -6,6 +6,7 @@
 #include "ResourceSet.h"
 #include "GameConstants.h"
 #include "JsonNode.h"
+#include "IHandlerBase.h"
 
 /*
  * CCreatureHandler.h, part of VCMI engine
@@ -132,28 +133,18 @@ public:
 	CCreature();
 };
 
-class DLL_LINKAGE CCreatureHandler
+class DLL_LINKAGE CCreatureHandler : public IHandlerBase
 {
 private:
 	CBonusSystemNode allCreatures;
 	CBonusSystemNode creaturesOfLevel[GameConstants::CREATURES_PER_TOWN + 1];//index 0 is used for creatures of unknown tier or outside <1-7> range
 
+	/// load one creature from json config
+	CCreature * loadFromJson(const JsonNode & node);
+
 	void loadJsonAnimation(CCreature * creature, const JsonNode & graphics);
 	void loadStackExperience(CCreature * creature, const JsonNode &input);
 	void loadCreatureJson(CCreature * creature, const JsonNode & config);
-public:
-	std::set<CreatureID> doubledCreatures; //they get double week
-	std::vector<ConstTransitivePtr<CCreature> > creatures; //creature ID -> creature info.
-
-	//stack exp
-	std::vector<std::vector<ui32> > expRanks; // stack experience needed for certain rank, index 0 for other tiers (?)
-	std::vector<ui32> maxExpPerBattle; //%, tiers same as above
-	si8 expAfterUpgrade;//multiplier in %
-
-	//Commanders
-	BonusList commanderLevelPremy; //bonus values added with each level-up
-	std::vector< std::vector <ui8> > skillLevels; //how much of a bonus will be given to commander with every level. SPELL_POWER also gives CASTS and RESISTANCE
-	std::vector <std::pair <Bonus, std::pair <ui8, ui8> > > skillRequirements; // first - Bonus, second - which two skills are needed to use it
 
 	/// loading functions
 
@@ -164,29 +155,49 @@ public:
 	void loadCommanders();
 	/// load creature from json structure
 	void load(std::string creatureID, const JsonNode & node);
-	/// load one creature from json config
-	CCreature * loadCreature(const JsonNode & node);
-	/// generates tier-specific bonus tree entries
-	void buildBonusTreeForTiers();
 	/// read cranim.txt file from H3
 	void loadAnimationInfo(std::vector<JsonNode> & h3Data);
 	/// read one line from cranim.txt
 	void loadUnitAnimInfo(JsonNode & unit, CLegacyConfigParser &parser);
-	/// load all creatures from H3 files
-	void loadCrExpBon();
 	/// parse crexpbon.txt file from H3
 	void loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser &parser);
 	/// help function for parsing CREXPBON.txt
 	int stringToNumber(std::string & s);
 
-	CCreatureHandler();
-	~CCreatureHandler();
+public:
+	std::set<CreatureID> doubledCreatures; //they get double week
+	std::vector<ConstTransitivePtr<CCreature> > creatures; //creature ID -> creature info.
+
+	//stack exp
+	std::vector<std::vector<ui32> > expRanks; // stack experience needed for certain rank, index 0 for other tiers (?)
+	std::vector<ui32> maxExpPerBattle; //%, tiers same as above
+	si8 expAfterUpgrade;//multiplier in %
+
+	//Commanders
+	BonusList commanderLevelPremy; //bonus values added with each level-up
+	std::vector< std::vector <ui8> > skillLevels; //how much of a bonus will be given to commander with every level. SPELL_POWER also gives CASTS and RESISTANCE
+	std::vector <std::pair <Bonus, std::pair <ui8, ui8> > > skillRequirements; // first - Bonus, second - which two skills are needed to use it
 
 	void deserializationFix();
 	CreatureID pickRandomMonster(const boost::function<int()> &randGen = 0, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any
 	void addBonusForTier(int tier, Bonus *b); //tier must be <1-7>
 	void addBonusForAllCreatures(Bonus *b);
 
+	CCreatureHandler();
+	~CCreatureHandler();
+
+	/// load all creatures from H3 files
+	void loadCrExpBon();
+	/// generates tier-specific bonus tree entries
+	void buildBonusTreeForTiers();
+
+	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+
+	void loadObject(std::string scope, std::string name, const JsonNode & data) override;
+	void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
+
+	std::vector<bool> getDefaultAllowed() const override;
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		//TODO: should be optimized, not all these informations needs to be serialized (same for ccreature)

+ 12 - 1
lib/CDefObjInfoHandler.cpp

@@ -46,8 +46,10 @@ void CGDefInfo::fetchInfoFromMSK()
 	}
 }
 
-void CDefObjInfoHandler::load()
+CDefObjInfoHandler::CDefObjInfoHandler()
 {
+	VLC->dobjinfo = this;
+
 	auto textFile = CResourceHandler::get()->loadData(ResourceID("DATA/ZOBJCTS.TXT"));
 
 	std::istringstream inp(std::string((char*)textFile.first.get(), textFile.second));
@@ -132,8 +134,17 @@ void CDefObjInfoHandler::load()
 		//coverageMap calculating
 		nobj->fetchInfoFromMSK();
 
+		auto dest = nobj->id.toDefObjInfo();
+		if (dest.find(nobj->subid) != dest.end() && dest[nobj->subid] != nullptr)
+		{
+			// there is just too many of these. Note that this data is almost unused
+			// exceptions are: town(village-capitol) and creation of new objects (holes, creatures, heroes, etc)
+			//logGlobal->warnStream() << "Warning: overwriting def info for " << dest[nobj->subid]->name << " with " << nobj->name;
+			dest[nobj->subid].dellNull(); // do not leak
+		}
 
 		nobj->id.toDefObjInfo()[nobj->subid] = nobj;
+
 	}
 
 	for (int i = 0; i < 8 ; i++)

+ 1 - 1
lib/CDefObjInfoHandler.h

@@ -54,7 +54,7 @@ public:
 	bmap<TFaction, ConstTransitivePtr<CGDefInfo> > capitols;
 	bmap<TFaction, ConstTransitivePtr<CGDefInfo> > villages;
 
-	void load();
+	CDefObjInfoHandler();
 	~CDefObjInfoHandler();
 
 	template <typename Handler> void serialize(Handler &h, const int version)

+ 18 - 16
lib/CGameState.cpp

@@ -381,7 +381,7 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor pl
 
 	if(player>=PlayerColor::PLAYER_LIMIT)
 	{
-        logGlobal->errorStream() << "Cannot pick hero for " << town->typeID << ". Wrong owner!";
+        logGlobal->errorStream() << "Cannot pick hero for " << town->faction->index << ". Wrong owner!";
 		return NULL;
 	}
 
@@ -392,7 +392,7 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor pl
 		for(auto i=available.begin(); i!=available.end(); i++)
 		{
 			if(pavailable.find(i->first)->second & 1<<player.getNum()
-				&& i->second->type->heroClass->faction == town->typeID)
+				&& i->second->type->heroClass->faction == town->faction->index)
 			{
 				pool.push_back(i->second); //get all available heroes
 			}
@@ -413,11 +413,11 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor pl
 
 		for(auto i=available.begin(); i!=available.end(); i++)
 		{
-			if ((!bannedClass && (pavailable.find(i->first)->second & (1<<player.getNum()))) ||
-				i->second->type->heroClass != bannedClass)
+			if (pavailable.find(i->first)->second & (1<<player.getNum()) &&    // hero is available
+			    ( !bannedClass || i->second->type->heroClass != bannedClass) ) // and his class is not same as other hero
 			{
 				pool.push_back(i->second);
-				sum += i->second->type->heroClass->selectionProbability[town->typeID]; //total weight
+				sum += i->second->type->heroClass->selectionProbability[town->faction->index]; //total weight
 			}
 		}
 		if(!pool.size() || sum == 0)
@@ -429,7 +429,7 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor pl
 		r = rand()%sum;
 		for (ui32 i=0; i<pool.size(); i++)
 		{
-			r -= pool[i]->type->heroClass->selectionProbability[town->typeID];
+			r -= pool[i]->type->heroClass->selectionProbability[town->faction->index];
 			if(r < 0)
 			{
 				ret = pool[i];
@@ -549,9 +549,11 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
 			}
 			if(f<0)
 			{
-				auto iter = VLC->townh->towns.begin();
-				std::advance(iter, ran()%VLC->townh->towns.size());
-				f = iter->first;
+				do
+				{
+					f = ran()%VLC->townh->factions.size();
+				}
+				while (VLC->townh->factions[f]->town == nullptr); // find playable faction
 			}
 			return std::make_pair(Obj::TOWN,f);
 		}
@@ -619,7 +621,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
 			dwl->info = nullptr;
 
 			std::pair<Obj, int> result(Obj::NO_OBJ, -1);
-			CreatureID cid = VLC->townh->towns[faction].creatures[level][0];
+			CreatureID cid = VLC->townh->factions[faction]->town->creatures[level][0];
 
 			//golem factory is not in list of cregens but can be placed as random object
 			static const CreatureID factoryCreatures[] = {CreatureID::STONE_GOLEM, CreatureID::IRON_GOLEM,
@@ -656,7 +658,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
 		if(cur->ID==Obj::TOWN) //town - set def
 		{
 			CGTownInstance *t = dynamic_cast<CGTownInstance*>(cur);
-			t->town = &VLC->townh->towns[t->subID];
+			t->town = VLC->townh->factions[t->subID]->town;
 			if(t->hasCapitol())
 				t->defInfo = VLC->dobjinfo->capitols[t->subID];
 			else if(t->hasFort())
@@ -685,7 +687,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
 		cur->ID = ran.first;
 		cur->subID = ran.second;
 		//FIXME: copy-pasted from above
-		t->town = &VLC->townh->towns[t->subID];
+		t->town = VLC->townh->factions[t->subID]->town;
 		if(t->hasCapitol())
 			t->defInfo = VLC->dobjinfo->capitols[t->subID];
 		else if(t->hasFort())
@@ -1394,8 +1396,8 @@ void CGameState::init(StartInfo * si)
 			break;
 		case PlayerSettings::RESOURCE:
 			{
-				int res = VLC->townh->towns[scenarioOps->playerInfos[k->first].castle].primaryRes;
-				if(res == 127)
+				int res = VLC->townh->factions[scenarioOps->playerInfos[k->first].castle]->town->primaryRes;
+				if(res == Res::WOOD_AND_ORE)
 				{
 					k->second.resources[Res::WOOD] += 5 + ran()%6;
 					k->second.resources[Res::ORE] += 5 + ran()%6;
@@ -1443,7 +1445,7 @@ void CGameState::init(StartInfo * si)
 						map->towns[g]->pos == pi.posOfMainTown + int3(2, 0, 0))
 					{
 						map->towns[g]->builtBuildings.insert(
-							CBuildingHandler::campToERMU(chosenBonus->info1, map->towns[g]->town->typeID, map->towns[g]->builtBuildings));
+							CBuildingHandler::campToERMU(chosenBonus->info1, map->towns[g]->subID, map->towns[g]->builtBuildings));
 						break;
 					}
 				}
@@ -1459,7 +1461,7 @@ void CGameState::init(StartInfo * si)
 	{
 		CGTownInstance * vti =(map->towns[i]);
 		if(!vti->town)
-			vti->town = &VLC->townh->towns[vti->subID];
+			vti->town = VLC->townh->factions[vti->subID]->town;
 		if (vti->name.length()==0) // if town hasn't name we draw it
 			vti->name = vti->town->names[ran()%vti->town->names.size()];
 

+ 1 - 6
lib/CGeneralTextHandler.cpp

@@ -149,7 +149,7 @@ void CGeneralTextHandler::readToVector(std::string sourceName, std::vector<std::
 	while (parser.endLine());
 }
 
-void CGeneralTextHandler::load()
+CGeneralTextHandler::CGeneralTextHandler()
 {
 	readToVector("DATA/VCDESC.TXT",   victoryConditions);
 	readToVector("DATA/LCDESC.TXT",   lossCondtions);
@@ -327,8 +327,3 @@ void CGeneralTextHandler::load()
 		threat.push_back(buffer);
 	}
 }
-
-CGeneralTextHandler::CGeneralTextHandler()
-{
-
-}

+ 0 - 1
lib/CGeneralTextHandler.h

@@ -105,6 +105,5 @@ public:
 	std::vector < std::vector <std::string> > campaignRegionNames;
 
 	void readToVector(std::string sourceName, std::vector<std::string> & dest);
-	void load();
 	CGeneralTextHandler();
 };

+ 125 - 146
lib/CHeroHandler.cpp

@@ -42,7 +42,7 @@ SecondarySkill CHeroClass::chooseSecSkill(const std::set<SecondarySkill> & possi
 
 EAlignment::EAlignment CHeroClass::getAlignment() const
 {
-	return EAlignment::EAlignment(VLC->townh->factions[faction].alignment);
+	return EAlignment::EAlignment(VLC->townh->factions[faction]->alignment);
 }
 
 std::vector<BattleHex> CObstacleInfo::getBlocked(BattleHex hex) const
@@ -78,16 +78,61 @@ bool CObstacleInfo::isAppropriate(ETerrainType terrainType, int specialBattlefie
 	return vstd::contains(allowedTerrains, terrainType);
 }
 
-void CHeroClassHandler::load()
+CHeroClass *CHeroClassHandler::loadFromJson(const JsonNode & node)
 {
+	CHeroClass * heroClass = new CHeroClass();
+
+	heroClass->imageBattleFemale = node["animation"]["battle"]["female"].String();
+	heroClass->imageBattleMale   = node["animation"]["battle"]["male"].String();
+	heroClass->imageMapFemale    = node["animation"]["map"]["female"].String();
+	heroClass->imageMapMale      = node["animation"]["map"]["male"].String();
+
+	heroClass->name = node["name"].String();
+
+	BOOST_FOREACH(const std::string & pSkill, PrimarySkill::names)
+	{
+		heroClass->primarySkillInitial.push_back(node["primarySkills"][pSkill].Float());
+		heroClass->primarySkillLowLevel.push_back(node["lowLevelChance"][pSkill].Float());
+		heroClass->primarySkillHighLevel.push_back(node["highLevelChance"][pSkill].Float());
+	}
+
+	BOOST_FOREACH(const std::string & secSkill, NSecondarySkill::names)
+	{
+		heroClass->secSkillProbability.push_back(node["secondarySkills"][secSkill].Float());
+	}
+
+	BOOST_FOREACH(auto & tavern, node["tavern"].Struct())
+	{
+		int value = tavern.second.Float();
+
+		VLC->modh->identifiers.requestIdentifier("faction." + tavern.first,
+		[=](si32 factionID)
+		{
+			heroClass->selectionProbability[factionID] = value;
+		});
+	}
+
+	VLC->modh->identifiers.requestIdentifier("faction." + node["faction"].String(),
+	[=](si32 factionID)
+	{
+		heroClass->faction = factionID;
+	});
+
+	return heroClass;
+}
+
+std::vector<JsonNode> CHeroClassHandler::loadLegacyData(size_t dataSize)
+{
+	heroClasses.resize(GameConstants::F_NUMBER * 2);
+	std::vector<JsonNode> h3Data;
+	h3Data.reserve(dataSize);
+
 	CLegacyConfigParser parser("DATA/HCTRAITS.TXT");
 
 	parser.endLine(); // header
 	parser.endLine();
 
-	std::vector<JsonNode> h3Data;
-
-	do
+	for (size_t i=0; i<dataSize; i++)
 	{
 		JsonNode entry;
 
@@ -110,85 +155,36 @@ void CHeroClassHandler::load()
 		for(size_t i = 0; i < GameConstants::F_NUMBER; i++)
 			entry["tavern"][ETownType::names[i]].Float() = parser.readNumber();
 
+		parser.endLine();
 		h3Data.push_back(entry);
 	}
-	while (parser.endLine() && !parser.isNextEntryEmpty());
-
-	JsonNode classConf = JsonNode(ResourceID("config/heroClasses.json"));
-	heroClasses.resize(GameConstants::F_NUMBER * 2);
-
-	BOOST_FOREACH(auto & node, classConf.Struct())
-	{
-		int numeric = node.second["id"].Float();
-		JsonNode & classData = h3Data[numeric];
-		JsonUtils::merge(classData, node.second);
-
-		//JsonUtils::validate(classData, "vcmi:heroClass", node.first);
-		heroClasses[numeric] = loadClass(classData);
-		heroClasses[numeric]->id = numeric;
-
-		VLC->modh->identifiers.registerObject ("heroClass." + node.first, numeric);
-	}
-
-	for (size_t i=0; i < heroClasses.size(); i++)
-	{
-		if (heroClasses[i] == nullptr)
-            logGlobal->warnStream() << "Warning: class with id " << i << " is missing!";
-	}
+	return h3Data;
 }
 
-void CHeroClassHandler::load(std::string objectID, const JsonNode & input)
+void CHeroClassHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
 {
-	CHeroClass * heroClass = loadClass(input);
-	heroClass->identifier = objectID;
-	heroClass->id = heroClasses.size();
+	auto object = loadFromJson(data);
+	object->id = heroClasses.size();
 
-	heroClasses.push_back(heroClass);
-    logGlobal->traceStream() << "Added hero class: " << objectID;
-	VLC->modh->identifiers.registerObject("heroClass." + heroClass->identifier, heroClass->id);
+	heroClasses.push_back(object);
+
+	VLC->modh->identifiers.registerObject(scope, "heroClass", name, object->id);
 }
 
-CHeroClass *CHeroClassHandler::loadClass(const JsonNode & node)
+void CHeroClassHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
 {
-	CHeroClass * heroClass = new CHeroClass;
+	auto object = loadFromJson(data);
+	object->id = index;
 
-	heroClass->imageBattleFemale = node["animation"]["battle"]["female"].String();
-	heroClass->imageBattleMale   = node["animation"]["battle"]["male"].String();
-	heroClass->imageMapFemale    = node["animation"]["map"]["female"].String();
-	heroClass->imageMapMale      = node["animation"]["map"]["male"].String();
+	assert(heroClasses[index] == nullptr); // ensure that this id was not loaded before
+	heroClasses[index] = object;
 
-	heroClass->name = node["name"].String();
-
-	BOOST_FOREACH(const std::string & pSkill, PrimarySkill::names)
-	{
-		heroClass->primarySkillInitial.push_back(node["primarySkills"][pSkill].Float());
-		heroClass->primarySkillLowLevel.push_back(node["lowLevelChance"][pSkill].Float());
-		heroClass->primarySkillHighLevel.push_back(node["highLevelChance"][pSkill].Float());
-	}
-
-	BOOST_FOREACH(const std::string & secSkill, NSecondarySkill::names)
-	{
-		heroClass->secSkillProbability.push_back(node["secondarySkills"][secSkill].Float());
-	}
-
-	BOOST_FOREACH(auto & tavern, node["tavern"].Struct())
-	{
-		int value = tavern.second.Float();
-
-		VLC->modh->identifiers.requestIdentifier("faction." + tavern.first,
-		[=](si32 factionID)
-		{
-			heroClass->selectionProbability[factionID] = value;
-		});
-	}
-
-	VLC->modh->identifiers.requestIdentifier("faction." + node["faction"].String(),
-	[=](si32 factionID)
-	{
-		heroClass->faction = factionID;
-	});
+	VLC->modh->identifiers.registerObject(scope, "heroClass", name, object->id);
+}
 
-	return heroClass;
+std::vector<bool> CHeroClassHandler::getDefaultAllowed() const
+{
+	return std::vector<bool>(heroClasses.size(), true);
 }
 
 CHeroClassHandler::~CHeroClassHandler()
@@ -207,19 +203,19 @@ CHeroHandler::~CHeroHandler()
 
 CHeroHandler::CHeroHandler()
 {
-}
-
-void CHeroHandler::load(std::string objectID, const JsonNode & input)
-{
-	CHero * hero = loadHero(input);
-	hero->ID = heroes.size();
+	VLC->heroh = this;
 
-	heroes.push_back(hero);
-    logGlobal->traceStream() << "Added hero: " << objectID;
-	VLC->modh->identifiers.registerObject("hero." + objectID, hero->ID);
+	for (int i = 0; i < GameConstants::SKILL_QUANTITY; ++i)
+	{
+		VLC->modh->identifiers.registerObject("core", "skill", NSecondarySkill::names[i], i);
+	}
+	loadObstacles();
+	loadTerrains();
+	loadBallistics();
+	loadExperience();
 }
 
-CHero * CHeroHandler::loadHero(const JsonNode & node)
+CHero * CHeroHandler::loadFromJson(const JsonNode & node)
 {
 	CHero * hero = new CHero;
 
@@ -332,22 +328,6 @@ void CHeroHandler::loadHeroSpecialty(CHero * hero, const JsonNode & node)
 	}
 }
 
-void CHeroHandler::load()
-{
-	VLC->heroh = this;
-
-	for (int i = 0; i < GameConstants::SKILL_QUANTITY; ++i)
-	{
-		VLC->modh->identifiers.registerObject("skill." + NSecondarySkill::names[i], i);
-	}
-	classes.load();
-	loadHeroes();
-	loadObstacles();
-	loadTerrains();
-	loadBallistics();
-	loadExperience();
-}
-
 void CHeroHandler::loadExperience()
 {
 	expPerLevel.push_back(0);
@@ -406,8 +386,39 @@ static std::string genRefName(std::string input)
 	return input;
 }
 
-void CHeroHandler::loadHeroes()
+void CHeroHandler::loadBallistics()
+{
+	CLegacyConfigParser ballParser("DATA/BALLIST.TXT");
+
+	ballParser.endLine(); //header
+	ballParser.endLine();
+
+	do
+	{
+		ballParser.readString();
+		ballParser.readString();
+
+		CHeroHandler::SBallisticsLevelInfo bli;
+		bli.keep   = ballParser.readNumber();
+		bli.tower  = ballParser.readNumber();
+		bli.gate   = ballParser.readNumber();
+		bli.wall   = ballParser.readNumber();
+		bli.shots  = ballParser.readNumber();
+		bli.noDmg  = ballParser.readNumber();
+		bli.oneDmg = ballParser.readNumber();
+		bli.twoDmg = ballParser.readNumber();
+		bli.sum    = ballParser.readNumber();
+		ballistics.push_back(bli);
+	}
+	while (ballParser.endLine());
+}
+
+std::vector<JsonNode> CHeroHandler::loadLegacyData(size_t dataSize)
 {
+	heroes.resize(dataSize);
+	std::vector<JsonNode> h3Data;
+	h3Data.reserve(dataSize);
+
 	CLegacyConfigParser specParser("DATA/HEROSPEC.TXT");
 	CLegacyConfigParser bioParser("DATA/HEROBIOS.TXT");
 	CLegacyConfigParser parser("DATA/HOTRAITS.TXT");
@@ -418,8 +429,6 @@ void CHeroHandler::loadHeroes()
 	specParser.endLine(); //ignore header
 	specParser.endLine();
 
-	std::vector<JsonNode> h3Data;
-
 	for (int i=0; i<GameConstants::HEROES_QUANTITY; i++)
 	{
 		JsonNode heroData;
@@ -447,58 +456,28 @@ void CHeroHandler::loadHeroes()
 
 		h3Data.push_back(heroData);
 	}
+	return h3Data;
+}
 
-	// Load heroes information
-	heroes.resize(GameConstants::HEROES_QUANTITY);
-
-	const JsonNode gameConf(ResourceID("config/gameConfig.json"));
-	JsonNode config(JsonUtils::assembleFromFiles(gameConf["heroes"].convertTo<std::vector<std::string> >()));
-
-	BOOST_FOREACH(auto &entry, config.Struct())
-	{
-		ui32 identifier = entry.second["id"].Float();
-		JsonUtils::merge(h3Data[identifier], entry.second);
-
-		//JsonUtils::validate(h3Data[identifier], "vcmi:hero", entry.first);
-		CHero * hero = loadHero(h3Data[identifier]);
-		hero->ID = identifier;
-		heroes[identifier] = hero;
+void CHeroHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
+{
+	auto object = loadFromJson(data);
+	object->ID = heroes.size();
 
-		VLC->modh->identifiers.registerObject("hero." + entry.first, identifier);
-	}
+	heroes.push_back(object);
 
-	for (size_t i=0; i < heroes.size(); i++)
-	{
-		if (heroes[i] == nullptr)
-            logGlobal->warnStream() << "Warning: hero with id " << i << " is missing!";
-	}
+	VLC->modh->identifiers.registerObject(scope, "hero", name, object->ID);
 }
 
-void CHeroHandler::loadBallistics()
+void CHeroHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
 {
-	CLegacyConfigParser ballParser("DATA/BALLIST.TXT");
+	auto object = loadFromJson(data);
+	object->ID = index;
 
-	ballParser.endLine(); //header
-	ballParser.endLine();
+	assert(heroes[index] == nullptr); // ensure that this id was not loaded before
+	heroes[index] = object;
 
-	do
-	{
-		ballParser.readString();
-		ballParser.readString();
-
-		CHeroHandler::SBallisticsLevelInfo bli;
-		bli.keep   = ballParser.readNumber();
-		bli.tower  = ballParser.readNumber();
-		bli.gate   = ballParser.readNumber();
-		bli.wall   = ballParser.readNumber();
-		bli.shots  = ballParser.readNumber();
-		bli.noDmg  = ballParser.readNumber();
-		bli.oneDmg = ballParser.readNumber();
-		bli.twoDmg = ballParser.readNumber();
-		bli.sum    = ballParser.readNumber();
-		ballistics.push_back(bli);
-	}
-	while (ballParser.endLine());
+	VLC->modh->identifiers.registerObject(scope, "hero", name, object->ID);
 }
 
 ui32 CHeroHandler::level (ui64 experience) const
@@ -531,7 +510,7 @@ void CHeroHandler::loadTerrains()
 		terrCosts.push_back(config[name]["moveCost"].Float());
 }
 
-std::vector<bool> CHeroHandler::getDefaultAllowedHeroes() const
+std::vector<bool> CHeroHandler::getDefaultAllowed() const
 {
 	// Look Data/HOTRAITS.txt for reference
 	std::vector<bool> allowedHeroes;

+ 21 - 31
lib/CHeroHandler.h

@@ -3,6 +3,7 @@
 #include "../lib/ConstTransitivePtr.h"
 #include "GameConstants.h"
 #include "HeroBonus.h"
+#include "IHandlerBase.h"
 
 /*
  * CHeroHandler.h, part of VCMI engine
@@ -149,19 +150,18 @@ struct DLL_LINKAGE CObstacleInfo
 	}
 };
 
-class DLL_LINKAGE CHeroClassHandler
+class DLL_LINKAGE CHeroClassHandler : public IHandlerBase
 {
+	CHeroClass *loadFromJson(const JsonNode & node);
 public:
 	std::vector< ConstTransitivePtr<CHeroClass> > heroClasses;
 
-	/// load from H3 config
-	void load();
+	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
 
-	/// load any number of classes from json
-	void load(std::string objectID, const JsonNode & classes);
+	void loadObject(std::string scope, std::string name, const JsonNode & data) override;
+	void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
 
-	/// load one class from json
-	CHeroClass * loadClass(const JsonNode & node);
+	std::vector<bool> getDefaultAllowed() const;
 
 	~CHeroClassHandler();
 
@@ -171,7 +171,7 @@ public:
 	}
 };
 
-class DLL_LINKAGE CHeroHandler
+class DLL_LINKAGE CHeroHandler : public IHandlerBase
 {
 	/// expPerLEvel[i] is amount of exp needed to reach level i;
 	/// consists of 201 values. Any higher levels require experience larger that ui64 can hold
@@ -181,6 +181,15 @@ class DLL_LINKAGE CHeroHandler
 	void loadHeroArmy(CHero * hero, const JsonNode & node);
 	void loadHeroSkills(CHero * hero, const JsonNode & node);
 	void loadHeroSpecialty(CHero * hero, const JsonNode & node);
+
+	void loadExperience();
+	void loadBallistics();
+	void loadTerrains();
+	void loadObstacles();
+
+	/// Load single hero from json
+	CHero * loadFromJson(const JsonNode & node);
+
 public:
 	CHeroClassHandler classes;
 
@@ -208,34 +217,15 @@ public:
 	ui32 level(ui64 experience) const; //calculates level corresponding to given experience amount
 	ui64 reqExp(ui32 level) const; //calculates experience required for given level
 
-	/// Load multiple heroes from json
-	void load(std::string objectID, const JsonNode & heroes);
-
-	/// Load single hero from json
-	CHero * loadHero(const JsonNode & node);
+	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
 
-	/// Load everything (calls functions below + classes.load())
-	void load();
-
-	void loadHeroes();
-	void loadExperience();
-	void loadBallistics();
-	void loadTerrains();
-	void loadObstacles();
+	void loadObject(std::string scope, std::string name, const JsonNode & data) override;
+	void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
 
 	CHeroHandler(); //c-tor
 	~CHeroHandler(); //d-tor
 
-	/**
-	 * Gets a list of default allowed heroes.
-	 *
-	 * TODO Proposal for hero modding: Replace hero id with a unique machine readable hero name and
-	 * create a JSON config file or merge it with a existing config file which describes which heroes can be used for
-	 * random map generation / map editor(default map settings). (Gelu, ... should be excluded)
-	 *
-	 * @return a list of allowed heroes, the index is the hero id and the value either 0 for not allowed or 1 for allowed
-	 */
-	std::vector<bool> getDefaultAllowedHeroes() const;
+	std::vector<bool> getDefaultAllowed() const;
 
 	/**
 	 * Gets a list of default allowed abilities. OH3 abilities/skills are all allowed by default.

+ 1 - 0
lib/CMakeLists.txt

@@ -70,6 +70,7 @@ set(lib_HEADERS
 		GameConstants.h
 		StringConstants.h
 		IGameEventsReceiver.h
+		IHandlerBase.h
 		int3.h
 		Interprocess.h
 		NetPacks.h

+ 199 - 46
lib/CModHandler.cpp

@@ -11,6 +11,8 @@
 #include "CHeroHandler.h"
 #include "CObjectHandler.h"
 #include "StringConstants.h"
+#include "CStopWatch.h"
+#include "IHandlerBase.h"
 
 /*
  * CModHandler.cpp, part of VCMI engine
@@ -46,7 +48,8 @@ void CIdentifierStorage::requestIdentifier(std::string name, const boost::functi
 {
 	checkIdentifier(name);
 
-	auto iter = registeredObjects.find(name);
+	// old version with immediate callback posibility. Can't be used for some cases
+/*	auto iter = registeredObjects.find(name);
 
 	if (iter != registeredObjects.end())
 		callback(iter->second); //already registered - trigger callback immediately
@@ -56,19 +59,24 @@ void CIdentifierStorage::requestIdentifier(std::string name, const boost::functi
             logGlobal->warnStream() << "incorrect primSkill name requested";
 
 		missingObjects[name].push_back(callback); // queue callback
-	}
+	}*/
+
+	missingObjects[name].push_back(callback); // queue callback
 }
 
-void CIdentifierStorage::registerObject(std::string name, si32 identifier)
+void CIdentifierStorage::registerObject(std::string scope, std::string type, std::string name, si32 identifier)
 {
-	checkIdentifier(name);
+	//TODO: use scope
+	std::string fullID = type + '.' + name;
+	checkIdentifier(fullID);
 
 	// do not allow to register same object twice
-	assert(registeredObjects.find(name) == registeredObjects.end());
+	assert(registeredObjects.find(fullID) == registeredObjects.end());
 
-	registeredObjects[name] = identifier;
+	registeredObjects[fullID] = identifier;
 
-	auto iter = missingObjects.find(name);
+	// old version with immediate callback posibility. Can't be used for some cases
+	/*auto iter = missingObjects.find(fullID);
 	if (iter != missingObjects.end())
 	{
 		//call all awaiting callbacks
@@ -77,11 +85,26 @@ void CIdentifierStorage::registerObject(std::string name, si32 identifier)
 			function(identifier);
 		}
 		missingObjects.erase(iter);
-	}
+	}*/
 }
 
-void CIdentifierStorage::finalize() const
+void CIdentifierStorage::finalize()
 {
+	for (auto it = missingObjects.begin(); it!= missingObjects.end();)
+	{
+		auto object = registeredObjects.find(it->first);
+		if (object != registeredObjects.end())
+		{
+			BOOST_FOREACH(auto function, it->second)
+			{
+				function(object->second);
+			}
+			it = missingObjects.erase(it);
+		}
+		else
+			it++;
+	}
+
 	// print list of missing objects and crash
 	// in future should try to do some cleanup (like returning all id's as 0)
 	if (!missingObjects.empty())
@@ -99,15 +122,115 @@ void CIdentifierStorage::finalize() const
 	assert(missingObjects.empty());
 }
 
+CContentHandler::ContentTypeHandler::ContentTypeHandler(IHandlerBase * handler, size_t size, std::string objectName):
+    handler(handler),
+    objectName(objectName),
+    originalData(handler->loadLegacyData(size))
+{
+}
+
+void CContentHandler::ContentTypeHandler::preloadModData(std::string modName, std::vector<std::string> fileList)
+{
+	JsonNode data = JsonUtils::assembleFromFiles(fileList);
+
+	ModInfo & modInfo = modData[modName];
+
+	BOOST_FOREACH(auto entry, data.Struct())
+	{
+		size_t colon = entry.first.find(':');
+
+		if (colon == std::string::npos)
+		{
+			// normal object, local to this mod
+			modInfo.modData[entry.first].swap(entry.second);
+		}
+		else
+		{
+			std::string remoteName = entry.first.substr(0, colon);
+			std::string objectName = entry.first.substr(colon + 1);
+
+			// patching this mod? Send warning and continue - this situation can be handled normally
+			if (remoteName == modName)
+				logGlobal->warnStream() << "Redundant namespace definition for " << objectName;
+
+			JsonNode & remoteConf = modData[remoteName].patches[objectName];
+
+			JsonUtils::merge(remoteConf, entry.second);
+		}
+	}
+}
+
+void CContentHandler::ContentTypeHandler::loadMod(std::string modName)
+{
+	ModInfo & modInfo = modData[modName];
+
+	// apply patches
+	if (!modInfo.patches.isNull())
+		JsonUtils::merge(modInfo.modData, modInfo.patches);
+
+	BOOST_FOREACH(auto entry, modInfo.modData.Struct())
+	{
+		const std::string & name = entry.first;
+		JsonNode & data = entry.second;
+
+		if (vstd::contains(data.Struct(), "index") && !data["index"].isNull())
+		{
+			// try to add H3 object data
+			size_t index = data["index"].Float();
+
+			if (originalData.size() > index)
+			{
+				JsonUtils::merge(originalData[index], data);
+				JsonUtils::validate(originalData[index], "vcmi:" + objectName, name);
+				handler->loadObject(modName, name, originalData[index], index);
+
+				originalData[index].clear(); // do not use same data twice (same ID)
+
+				continue;
+			}
+		}
+		// normal new object
+		JsonUtils::validate(data, "vcmi:" + objectName, name);
+		handler->loadObject(modName, name, data);
+	}
+}
+
+CContentHandler::CContentHandler()
+{
+	handlers.insert(std::make_pair("heroClasses", ContentTypeHandler(&VLC->heroh->classes, GameConstants::F_NUMBER * 2, "heroClass")));
+	handlers.insert(std::make_pair("artifacts", ContentTypeHandler(VLC->arth, GameConstants::ARTIFACTS_QUANTITY, "artifact")));
+	handlers.insert(std::make_pair("creatures", ContentTypeHandler(VLC->creh, GameConstants::CREATURES_COUNT, "creature")));
+	handlers.insert(std::make_pair("factions", ContentTypeHandler(VLC->townh, GameConstants::F_NUMBER, "faction")));
+	handlers.insert(std::make_pair("heroes", ContentTypeHandler(VLC->heroh, GameConstants::HEROES_QUANTITY, "hero")));
+
+	//TODO: spells, bonuses, something else?
+}
+
+void CContentHandler::preloadModData(std::string modName, JsonNode modConfig)
+{
+	BOOST_FOREACH(auto & handler, handlers)
+	{
+		handler.second.preloadModData(modName, modConfig[handler.first].convertTo<std::vector<std::string> >());
+	}
+}
+
+void CContentHandler::loadMod(std::string modName)
+{
+	BOOST_FOREACH(auto & handler, handlers)
+	{
+		handler.second.loadMod(modName);
+	}
+}
+
 CModHandler::CModHandler()
 {
 	for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i)
 	{
-		identifiers.registerObject("resource." + GameConstants::RESOURCE_NAMES[i], i);
+		identifiers.registerObject("core", "resource", GameConstants::RESOURCE_NAMES[i], i);
 	}
 
 	for(int i=0; i<GameConstants::PRIMARY_SKILLS; ++i)
-		identifiers.registerObject("primSkill." + PrimarySkill::names[i], i);
+		identifiers.registerObject("core", "primSkill", PrimarySkill::names[i], i);
 
 	loadConfigFromFile ("defaultMods");
 }
@@ -190,8 +313,12 @@ bool CModHandler::checkDependencies(const std::vector <TModID> & input) const
 
 std::vector <TModID> CModHandler::resolveDependencies(std::vector <TModID> input) const
 {
-	// Algorithm may not be the fastest one but VCMI does not needs any speed here
-	// Unless user have dozens of mods with complex dependencies this cide should be fine
+	// Topological sort algorithm
+	// May not be the fastest one but VCMI does not needs any speed here
+	// Unless user have dozens of mods with complex dependencies this code should be fine
+
+	// first - sort input to have input strictly based on name (and not on hashmap or anything else)
+	boost::range::sort(input);
 
 	std::vector <TModID> output;
 	output.reserve(input.size());
@@ -211,17 +338,20 @@ std::vector <TModID> CModHandler::resolveDependencies(std::vector <TModID> input
 
 	while (!input.empty())
 	{
+		std::set <TModID> toResolve; // list of mods resolved on this iteration
+
 		for (auto it = input.begin(); it != input.end();)
 		{
 			if (isResolved(allMods.at(*it)))
 			{
-				resolvedMods.insert(*it);
+				toResolve.insert(*it);
 				output.push_back(*it);
 				it = input.erase(it);
 				continue;
 			}
 			it++;
 		}
+		resolvedMods.insert(toResolve.begin(), toResolve.end());
 	}
 
 	return output;
@@ -238,8 +368,6 @@ void CModHandler::initialize(std::vector<std::string> availableMods)
 	else
 		modConfig = JsonNode(ResourceID(confName));
 
-	CResourceHandler::get()->createResource("config/modSettings.json");
-
 	const JsonNode & modList = modConfig["activeMods"];
 	JsonNode resultingList;
 
@@ -312,28 +440,48 @@ void CModHandler::handleData(Handler handler, const JsonNode & source, std::stri
 	}
 }
 
-void CModHandler::loadActiveMods()
+void CModHandler::loadGameContent()
 {
+	CStopWatch timer, totalTime;
+
+	CContentHandler content;
+	logGlobal->infoStream() << "\tInitializing content hander: " << timer.getDiff() << " ms";
+
+	// first - load virtual "core" mod tht contains all data
+	// TODO? move all data into real mods? RoE, AB, SoD, WoG
+	content.preloadModData("core", JsonNode(ResourceID("config/gameConfig.json")));
+	logGlobal->infoStream() << "\tParsing original game data: " << timer.getDiff() << " ms";
+
 	BOOST_FOREACH(const TModID & modName, activeMods)
 	{
-        logGlobal->infoStream() << "\t\tLoading mod " << allMods[modName].name;
+		logGlobal->infoStream() << "\t\t" << allMods[modName].name;
 
 		std::string modFileName = "mods/" + modName + "/mod.json";
 
 		const JsonNode config = JsonNode(ResourceID(modFileName));
 		JsonUtils::validate(config, "vcmi:mod", modName);
 
-		handleData(VLC->townh, config, "factions", "vcmi:faction");
-		handleData(VLC->creh, config, "creatures", "vcmi:creature");
-		handleData(VLC->arth, config, "artifacts", "vcmi:artifact");
-		//todo: spells
+		content.preloadModData(modName, config);
+	}
+	logGlobal->infoStream() << "\tParsing mod data: " << timer.getDiff() << " ms";
+
+	content.loadMod("core");
+	logGlobal->infoStream() << "\tLoading original game data: " << timer.getDiff() << " ms";
 
-		handleData(&VLC->heroh->classes, config,"heroClasses", "vcmi:heroClass");
-		handleData(VLC->heroh, config, "heroes", "vcmi:hero");
+	BOOST_FOREACH(const TModID & modName, activeMods)
+	{
+		content.loadMod(modName);
+		logGlobal->infoStream() << "\t\t" << allMods[modName].name;
 	}
+	logGlobal->infoStream() << "\tLoading mod data: " << timer.getDiff() << "ms";
+
+	logGlobal->infoStream() << "\tDone loading data";
 
+	VLC->creh->loadCrExpBon();
 	VLC->creh->buildBonusTreeForTiers(); //do that after all new creatures are loaded
 	identifiers.finalize();
+
+	logGlobal->infoStream() << "\tAll game content loaded in " << totalTime.getDiff() << " ms";
 }
 
 void CModHandler::reload()
@@ -380,37 +528,42 @@ void CModHandler::reload()
 		const CGDefInfo * baseInfo = VLC->dobjinfo->gobjs[Obj::TOWN].begin()->second;
 		auto & townInfos = VLC->dobjinfo->gobjs[Obj::TOWN];
 
-		BOOST_FOREACH(auto & town, VLC->townh->towns)
+		BOOST_FOREACH(auto & faction, VLC->townh->factions)
 		{
-			auto & cientInfo = town.second.clientInfo;
-
-			if (!vstd::contains(VLC->dobjinfo->gobjs[Obj::TOWN], town.first)) // no obj info for this type
+			TFaction index = faction->index;
+			CTown * town = faction->town;
+			if (town)
 			{
-				CGDefInfo * info = new CGDefInfo(*baseInfo);
-				info->subid = town.first;
+				auto & cientInfo = town->clientInfo;
 
-				townInfos[town.first] = info;
-			}
-			townInfos[town.first]->name = cientInfo.advMapCastle;
+				if (!vstd::contains(VLC->dobjinfo->gobjs[Obj::TOWN], index)) // no obj info for this type
+				{
+					CGDefInfo * info = new CGDefInfo(*baseInfo);
+					info->subid = index;
 
-			VLC->dobjinfo->villages[town.first] = new CGDefInfo(*townInfos[town.first]);
-			VLC->dobjinfo->villages[town.first]->name = cientInfo.advMapVillage;
+					townInfos[index] = info;
+				}
+				townInfos[index]->name = cientInfo.advMapCastle;
 
-			VLC->dobjinfo->capitols[town.first] = new CGDefInfo(*townInfos[town.first]);
-			VLC->dobjinfo->capitols[town.first]->name = cientInfo.advMapCapitol;
+				VLC->dobjinfo->villages[index] = new CGDefInfo(*townInfos[index]);
+				VLC->dobjinfo->villages[index]->name = cientInfo.advMapVillage;
 
-			for (int i = 0; i < town.second.dwellings.size(); ++i)
-			{
-				const CGDefInfo * baseInfo = VLC->dobjinfo->gobjs[Obj::CREATURE_GENERATOR1][i]; //get same blockmap as first dwelling of tier i
+				VLC->dobjinfo->capitols[index] = new CGDefInfo(*townInfos[index]);
+				VLC->dobjinfo->capitols[index]->name = cientInfo.advMapCapitol;
 
-				BOOST_FOREACH (auto cre, town.second.creatures[i]) //both unupgraded and upgraded get same dwelling
+				for (int i = 0; i < town->dwellings.size(); ++i)
 				{
-					CGDefInfo * info = new CGDefInfo(*baseInfo);
-					info->subid = cre;
-					info->name = town.second.dwellings[i];
-					VLC->dobjinfo->gobjs[Obj::CREATURE_GENERATOR1][cre] = info;
+					const CGDefInfo * baseInfo = VLC->dobjinfo->gobjs[Obj::CREATURE_GENERATOR1][i]; //get same blockmap as first dwelling of tier i
+
+					BOOST_FOREACH (auto cre, town->creatures[i]) //both unupgraded and upgraded get same dwelling
+					{
+						CGDefInfo * info = new CGDefInfo(*baseInfo);
+						info->subid = cre;
+						info->name = town->dwellings[i];
+						VLC->dobjinfo->gobjs[Obj::CREATURE_GENERATOR1][cre] = info;
 
-					VLC->objh->cregens[cre] = cre; //map of dwelling -> creature id
+						VLC->objh->cregens[cre] = cre; //map of dwelling -> creature id
+					}
 				}
 			}
 		}

+ 49 - 4
lib/CModHandler.h

@@ -3,6 +3,7 @@
 #include "filesystem/CResourceLoader.h"
 
 #include "VCMI_Lib.h"
+#include "JsonNode.h"
 
 /*
  * CModHandler.h, part of VCMI engine
@@ -18,6 +19,7 @@ class CModHandler;
 class CModIndentifier;
 class CModInfo;
 class JsonNode;
+class IHandlerBase;
 
 /// class that stores all object identifiers strings and maps them to numeric ID's
 /// if possible, objects ID's should be in format <type>.<name>, camelCase e.g. "creature.grandElf"
@@ -26,17 +28,60 @@ class CIdentifierStorage
 	std::map<std::string, si32 > registeredObjects;
 	std::map<std::string, std::vector<boost::function<void(si32)> > > missingObjects;
 
-	//Check if identifier can be valid (camelCase, point as separator)
+	/// Check if identifier can be valid (camelCase, point as separator)
 	void checkIdentifier(std::string & ID);
 public:
 	/// request identifier for specific object name. If ID is not yet resolved callback will be queued
 	/// and will be called later
 	void requestIdentifier(std::string name, const boost::function<void(si32)> & callback);
 	/// registers new object, calls all associated callbacks
-	void registerObject(std::string name, si32 identifier);
+	void registerObject(std::string scope, std::string type, std::string name, si32 identifier);
 
 	/// called at the very end of loading to check for any missing ID's
-	void finalize() const;
+	void finalize();
+};
+
+/// class used to load all game data into handlers. Used only during loading
+class CContentHandler
+{
+	/// internal type to handle loading of one data type (e.g. artifacts, creatures)
+	class ContentTypeHandler
+	{
+		struct ModInfo
+		{
+			/// mod data from this mod and for this mod
+			JsonNode modData;
+			/// mod data for this mod from other mods (patches)
+			JsonNode patches;
+		};
+
+		/// handler to which all data will be loaded
+		IHandlerBase * handler;
+
+		std::string objectName;
+
+		/// contains all loaded H3 data
+		std::vector<JsonNode> originalData;
+		std::map<std::string, ModInfo> modData;
+
+	public:
+		ContentTypeHandler(IHandlerBase * handler, size_t size, std::string objectName);
+
+		/// local version of methods in ContentHandler
+		void preloadModData(std::string modName, std::vector<std::string> fileList);
+		void loadMod(std::string modName);
+	};
+
+	std::map<std::string, ContentTypeHandler> handlers;
+public:
+	/// fully initialize object. Will cause reading of H3 config files
+	CContentHandler();
+
+	/// preloads all data from fileList as data from modName
+	void preloadModData(std::string modName, JsonNode modConfig);
+
+	/// actually loads data in mod
+	void loadMod(std::string modName);
 };
 
 typedef std::string TModID;
@@ -99,7 +144,7 @@ public:
 	std::vector<std::string> getActiveMods();
 
 	/// load content from all available mods
-	void loadActiveMods();
+	void loadGameContent();
 
 	/// actions that should be triggered on map restart
 	/// TODO: merge into appropriate handlers?

+ 29 - 24
lib/CObjectHandler.cpp

@@ -213,7 +213,7 @@ static void readBankLevel(const JsonNode &level, BankConfig &bc)
 	bc.easiest = level["easiest"].Float();
 }
 
-void CObjectHandler::load()
+CObjectHandler::CObjectHandler()
 {
     logGlobal->traceStream() << "\t\tReading cregens ";
 
@@ -614,7 +614,7 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainTile &fro
 		bool nativeArmy = true;
 		BOOST_FOREACH(auto stack, stacks)
 		{
-			int nativeTerrain = VLC->townh->factions[stack.second->type->faction].nativeTerrain;
+			int nativeTerrain = VLC->townh->factions[stack.second->type->faction]->nativeTerrain;
 
             if (nativeTerrain != -1 && nativeTerrain != from.terType)
 			{
@@ -813,7 +813,7 @@ void CGHeroInstance::initHero()
 
 	if (VLC->modh->modules.COMMANDERS && !commander)
 	{
-		commander = new CCommanderInstance (VLC->townh->factions[type->heroClass->faction].commander);
+		commander = new CCommanderInstance (VLC->townh->factions[type->heroClass->faction]->commander);
 		commander->setArmyObj (castToArmyObj()); //TODO: separate function for setting commanders
 		commander->giveStackExp (exp); //after our exp is set
 	}
@@ -1672,9 +1672,9 @@ void CGDwelling::initObj()
 			creatures[0].second.push_back(crid);
 			if (subID >= VLC->generaltexth->creGens.size()) //very messy workaround
 			{
-				TFaction faction = VLC->creh->creatures[subID]->faction;
-				assert (VLC->townh->towns[faction].dwellingNames.size());
-				hoverName = VLC->townh->towns[faction].dwellingNames[VLC->creh->creatures[subID]->level - 1];
+				auto & dwellingNames = VLC->townh->factions[crs->faction]->town->dwellingNames;
+				assert (!dwellingNames.empty());
+				hoverName = dwellingNames[VLC->creh->creatures[subID]->level - 1];
 			}
 			else
 				hoverName = VLC->generaltexth->creGens[subID];
@@ -2201,7 +2201,7 @@ void CGTownInstance::initObj()
 ///initialize town structures
 {
 	blockVisit = true;
-	hoverName = name + ", " + VLC->townh->factions[town->typeID].name;
+	hoverName = name + ", " + town->faction->name;
 
 	if (subID == ETownType::DUNGEON)
 		creatures.resize(GameConstants::CREATURES_PER_TOWN+1);//extra dwelling for Dungeon
@@ -2355,7 +2355,7 @@ void CGTownInstance::removeCapitols (PlayerColor owner) const
 
 int CGTownInstance::getBoatType() const
 {
-	switch (VLC->townh->factions[town->typeID].alignment)
+	switch (town->faction->alignment)
 	{
 	case EAlignment::EVIL : return 0;
 	case EAlignment::GOOD : return 1;
@@ -2431,7 +2431,7 @@ std::vector<int> CGTownInstance::availableItemsIds(EMarketMode::EMarketMode mode
 
 std::string CGTownInstance::nodeName() const
 {
-	return "Town (" + (town ? VLC->townh->factions[town->typeID].name : "unknown") + ") of " +  name;
+	return "Town (" + (town ? town->faction->name : "unknown") + ") of " +  name;
 }
 
 void CGTownInstance::deserializationFix()
@@ -2448,6 +2448,8 @@ void CGTownInstance::deserializationFix()
 
 void CGTownInstance::recreateBuildingsBonuses()
 {
+	static TPropagatorPtr playerProp(new CPropagatorNodeType(PLAYER));
+
 	BonusList bl;
 	getExportedBonusList().getBonuses(bl, Selector::sourceType(Bonus::TOWN_STRUCTURE));
 	BOOST_FOREACH(Bonus *b, bl)
@@ -2459,13 +2461,13 @@ void CGTownInstance::recreateBuildingsBonuses()
 
 	if(subID == ETownType::CASTLE) //castle
 	{
-		addBonusIfBuilt(BuildingID::LIGHTHOUSE, Bonus::SEA_MOVEMENT, +500, make_shared<CPropagatorNodeType>(PLAYER));
-		addBonusIfBuilt(BuildingID::GRAIL,      Bonus::MORALE, +2, make_shared<CPropagatorNodeType>(PLAYER)); //colossus
+		addBonusIfBuilt(BuildingID::LIGHTHOUSE, Bonus::SEA_MOVEMENT, +500, playerProp);
+		addBonusIfBuilt(BuildingID::GRAIL,      Bonus::MORALE, +2, playerProp); //colossus
 	}
 	else if(subID == ETownType::RAMPART) //rampart
 	{
 		addBonusIfBuilt(BuildingID::FOUNTAIN_OF_FORTUNE, Bonus::LUCK, +2); //fountain of fortune
-		addBonusIfBuilt(BuildingID::GRAIL, Bonus::LUCK, +2, make_shared<CPropagatorNodeType>(PLAYER)); //guardian spirit
+		addBonusIfBuilt(BuildingID::GRAIL, Bonus::LUCK, +2, playerProp); //guardian spirit
 	}
 	else if(subID == ETownType::TOWER) //tower
 	{
@@ -2478,8 +2480,8 @@ void CGTownInstance::recreateBuildingsBonuses()
 	else if(subID == ETownType::NECROPOLIS) //necropolis
 	{
 		addBonusIfBuilt(BuildingID::COVER_OF_DARKNESS,    Bonus::DARKNESS, +20);
-		addBonusIfBuilt(BuildingID::NECROMANCY_AMPLIFIER, Bonus::SECONDARY_SKILL_PREMY, +10, make_shared<CPropagatorNodeType>(PLAYER), SecondarySkill::NECROMANCY); //necromancy amplifier
-		addBonusIfBuilt(BuildingID::GRAIL, Bonus::SECONDARY_SKILL_PREMY, +20, make_shared<CPropagatorNodeType>(PLAYER), SecondarySkill::NECROMANCY); //Soul prison
+		addBonusIfBuilt(BuildingID::NECROMANCY_AMPLIFIER, Bonus::SECONDARY_SKILL_PREMY, +10, playerProp, SecondarySkill::NECROMANCY); //necromancy amplifier
+		addBonusIfBuilt(BuildingID::GRAIL, Bonus::SECONDARY_SKILL_PREMY, +20, playerProp, SecondarySkill::NECROMANCY); //Soul prison
 	}
 	else if(subID == ETownType::DUNGEON) //Dungeon
 	{
@@ -2504,10 +2506,11 @@ void CGTownInstance::recreateBuildingsBonuses()
 
 bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, int subtype /*= -1*/)
 {
-	return addBonusIfBuilt(building, type, val, TPropagatorPtr(), subtype);
+	static auto emptyPropagator = TPropagatorPtr();
+	return addBonusIfBuilt(building, type, val, emptyPropagator, subtype);
 }
 
-bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr prop, int subtype /*= -1*/)
+bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype /*= -1*/)
 {
 	if(hasBuilt(building))
 	{
@@ -2595,7 +2598,7 @@ const CArmedInstance * CGTownInstance::getUpperArmy() const
 
 bool CGTownInstance::hasBuilt(BuildingID buildingID, int townID) const
 {
-	if (townID == town->typeID || townID == ETownType::ANY)
+	if (townID == town->faction->index || townID == ETownType::ANY)
 		return hasBuilt(buildingID);
 	return false;
 }
@@ -2675,7 +2678,7 @@ void CGVisitableOPH::initObj()
 		case 2:
 			treePrice[Res::GEMS] = 10;
 			break;
-		default:
+		default:
 			break;
 		}
 	}
@@ -2968,8 +2971,8 @@ void CGVisitableOPH::blockingDialogAnswered(const CGHeroInstance *hero, ui32 ans
 	case Obj::SCHOOL_OF_WAR:
 		schoolSelected(id, answer);
 
-	default:
-		assert(0);
+	default:
+		assert(0);
 		break;
 	}
 }
@@ -3100,9 +3103,11 @@ const std::string & CGCreature::getHoverText() const
 {
 	if(stacks.empty())
 	{
+		static const std::string errorValue("!!!INVALID_STACK!!!");
+
 		//should not happen... 
 		logGlobal->errorStream() << "Invalid stack at tile " << pos << ": subID=" << subID << "; id=" << id;
-		return "!!!INVALID_STACK!!!";
+		return errorValue; // references to temporary are illegal - use pre-constructed string
 	}
 
 	MetaString ms;
@@ -6980,7 +6985,7 @@ void CArmedInstance::randomizeArmy(int type)
 		{
 			int level = (randID-VLC->creh->creatures.size()) / 2 -1;
 			bool upgrade = !(randID % 2);
-			j->second->setType(VLC->townh->towns[type].creatures[level][upgrade]);
+			j->second->setType(VLC->townh->factions[type]->town->creatures[level][upgrade]);
 			randID = -1;
 		}
 
@@ -7035,7 +7040,7 @@ void CArmedInstance::updateMoraleBonusFromArmy()
 
 		BOOST_FOREACH(TFaction f, factions)
 		{
-			if (VLC->townh->factions[f].alignment != EAlignment::EVIL)
+			if (VLC->townh->factions[f]->alignment != EAlignment::EVIL)
 				mixableFactions++;
 		}
 		if (mixableFactions > 0)
@@ -7397,7 +7402,7 @@ GrowthInfo::Entry::Entry(const std::string &format, int _count)
 GrowthInfo::Entry::Entry(int subID, BuildingID building, int _count)
 	: count(_count)
 {
-	description = boost::str(boost::format("%s %+d") % VLC->townh->towns[subID].buildings[building]->Name() % count);
+	description = boost::str(boost::format("%s %+d") % VLC->townh->factions[subID]->town->buildings[building]->Name() % count);
 }
 
 CTownAndVisitingHero::CTownAndVisitingHero()

+ 3 - 2
lib/CObjectHandler.h

@@ -622,7 +622,7 @@ public:
 	std::string nodeName() const override;
 	void deserializationFix();
 	void recreateBuildingsBonuses();
-	bool addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr prop, int subtype = -1); //returns true if building is built and bonus has been added
+	bool addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr &prop, int subtype = -1); //returns true if building is built and bonus has been added
 	bool addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, int subtype = -1); //convienence version of above
 	void setVisitingHero(CGHeroInstance *h);
 	void setGarrisonedHero(CGHeroInstance *h);
@@ -1403,7 +1403,8 @@ public:
 	std::map <ui32, std::string> creBanksNames; //[crebank index] -> name of this creature bank
 	std::vector<ui32> resVals; //default values of resources in gold
 
-	void load();
+	CObjectHandler();
+
 	int bankObjToIndex (const CGObjectInstance * obj);
 
 	template <typename Handler> void serialize(Handler &h, const int version)

+ 6 - 10
lib/CSpellHandler.cpp

@@ -246,10 +246,10 @@ void CSpell::getEffects(std::vector<Bonus>& lst, const int level) const
 	}
 	lst.reserve(lst.size() + effects[level].size());
 
-	BOOST_FOREACH (Bonus b, effects[level])
+	BOOST_FOREACH (Bonus *b, effects[level])
 	{
 		//TODO: value, add value
-		lst.push_back(b);
+		lst.push_back(Bonus(*b));
 	}
 }
 
@@ -344,10 +344,6 @@ bool DLL_LINKAGE isInScreenRange(const int3 &center, const int3 &pos)
 		return false;
 }
 
-CSpellHandler::CSpellHandler()
-{
-}
-
 CSpell * CSpellHandler::loadSpell(CLegacyConfigParser & parser, const SpellID id)
 {
 	CSpell * spell = new CSpell; //new currently being read spell
@@ -397,7 +393,7 @@ CSpell * CSpellHandler::loadSpell(CLegacyConfigParser & parser, const SpellID id
 	return spell;
 }
 
-void CSpellHandler::load()
+CSpellHandler::CSpellHandler()
 {
 	CLegacyConfigParser parser("DATA/SPTRAITS.TXT");
 
@@ -449,7 +445,7 @@ void CSpellHandler::load()
 		s->counteredSpells = spell.second["counters"].convertTo<std::vector<SpellID> >();
 
 		s->identifier = spell.first;
-		VLC->modh->identifiers.registerObject("spell." + spell.first, spellID);
+		VLC->modh->identifiers.registerObject("core", "spell", spell.first, spellID);
 
 		const JsonNode & flags_node = spell.second["flags"];
 		if (!flags_node.isNull())
@@ -495,7 +491,7 @@ void CSpellHandler::load()
 				if (!a.empty())
 					b->additionalInfo = a[i];
 
-				s->effects[i].push_back(*b);
+				s->effects[i].push_back(b);
 			}
 
 		}
@@ -537,7 +533,7 @@ void CSpellHandler::load()
 	}
 }
 
-std::vector<bool> CSpellHandler::getDefaultAllowedSpells() const
+std::vector<bool> CSpellHandler::getDefaultAllowed() const
 {
 	std::vector<bool> allowedSpells;
 	allowedSpells.resize(GameConstants::SPELLS_QUANTITY, true);

+ 2 - 4
lib/CSpellHandler.h

@@ -96,7 +96,7 @@ private:
 
 	ETargetType targetType;
 
-	std::vector<Bonus> effects [4];
+	std::vector<Bonus *> effects [4];
 	std::vector<Bonus::BonusType> immunities; //any of these grants immunity
 	std::vector<Bonus::BonusType> limiters; //all of them are required to be affected
 
@@ -168,14 +168,12 @@ public:
 	CSpellHandler();
 	std::vector< ConstTransitivePtr<CSpell> > spells;
 
-	void load();
-
 	/**
 	 * Gets a list of default allowed spells. OH3 spells are all allowed by default.
 	 *
 	 * @return a list of allowed spells, the index is the spell id and the value either 0 for not allowed or 1 for allowed
 	 */
-	std::vector<bool> getDefaultAllowedSpells() const;
+	std::vector<bool> getDefaultAllowed() const;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 104 - 118
lib/CTownHandler.cpp

@@ -37,18 +37,18 @@ BuildingID CBuilding::getBase() const
 {
 	const CBuilding * build = this;
 	while (build->upgrade >= 0)
-		build = VLC->townh->towns[build->tid].buildings[build->upgrade];
+		build = build->town->buildings[build->upgrade];
 
 	return build->bid;
 }
 
 si32 CBuilding::getDistance(BuildingID buildID) const
 {
-	const CBuilding * build = VLC->townh->towns[tid].buildings[buildID];
+	const CBuilding * build = town->buildings[buildID];
 	int distance = 0;
 	while (build->upgrade >= 0 && build != this)
 	{
-		build = VLC->townh->towns[build->tid].buildings[build->upgrade];
+		build = build->town->buildings[build->upgrade];
 		distance++;
 	}
 	if (build == this)
@@ -76,28 +76,31 @@ JsonNode readBuilding(CLegacyConfigParser & parser)
 	return ret;
 }
 
-void CTownHandler::loadLegacyData(JsonNode & dest)
+std::vector<JsonNode> CTownHandler::loadLegacyData(size_t dataSize)
 {
+	std::vector<JsonNode> dest(dataSize);
+	factions.resize(dataSize);
+
+	auto getBuild = [&](size_t town, size_t building) -> JsonNode &
+	{
+		return dest[town]["town"]["buildings"][EBuildingType::names[building]];
+	};
+
 	CLegacyConfigParser parser("DATA/BUILDING.TXT");
-	dest.Vector().resize(GameConstants::F_NUMBER);
 
 	parser.endLine(); // header
 	parser.endLine();
 
 	//Unique buildings
-	for (size_t town=0; town<GameConstants::F_NUMBER; town++)
+	for (size_t town=0; town<dataSize; town++)
 	{
-		JsonVector & buildList = dest.Vector()[town]["buildings"].Vector();
-
-		buildList.resize( 30 ); //prepare vector for first set of buildings
-
 		parser.endLine(); //header
 		parser.endLine();
 
 		int buildID = 17;
 		do
 		{
-			buildList[buildID] = readBuilding(parser);
+			getBuild(town, buildID) = readBuilding(parser);
 			buildID++;
 		}
 		while (!parser.isNextEntryEmpty());
@@ -113,8 +116,8 @@ void CTownHandler::loadLegacyData(JsonNode & dest)
 	{
 		JsonNode building = readBuilding(parser);
 
-		for (size_t town=0; town<GameConstants::F_NUMBER; town++)
-			dest.Vector()[town]["buildings"].Vector()[buildID] = building;
+		for (size_t town=0; town<dataSize; town++)
+			getBuild(town, buildID) = building;
 
 		buildID++;
 	}
@@ -124,16 +127,15 @@ void CTownHandler::loadLegacyData(JsonNode & dest)
 	parser.endLine();
 
 	//Dwellings
-	for (size_t town=0; town<GameConstants::F_NUMBER; town++)
+	for (size_t town=0; town<dataSize; town++)
 	{
 		parser.endLine(); //header
 		parser.endLine();
 
-		do
+		for (size_t i=0; i<14; i++)
 		{
-			dest.Vector()[town]["buildings"].Vector().push_back(readBuilding(parser));
+			getBuild(town, 30+i) = readBuilding(parser);
 		}
-		while (!parser.isNextEntryEmpty());
 	}
 	{
 		CLegacyConfigParser parser("DATA/BLDGNEUT.TXT");
@@ -144,11 +146,10 @@ void CTownHandler::loadLegacyData(JsonNode & dest)
 			std::string descr = parser.readString();
 			parser.endLine();
 
-			for(int j=0; j<GameConstants::F_NUMBER; j++)
+			for(int j=0; j<dataSize; j++)
 			{
-				JsonVector & buildings = dest.Vector()[j]["buildings"].Vector();
-				buildings[building]["name"].String() = name;
-				buildings[building]["description"].String() = descr;
+				getBuild(j, building)["name"].String() = name;
+				getBuild(j, building)["description"].String() = descr;
 			}
 		}
 		parser.endLine(); // silo
@@ -160,53 +161,49 @@ void CTownHandler::loadLegacyData(JsonNode & dest)
 		std::string descr = parser.readString();
 		parser.endLine();
 
-		for(int town=0; town<GameConstants::F_NUMBER; town++)
+		for(int town=0; town<dataSize; town++)
 		{
-			JsonVector & buildings = dest.Vector()[town]["buildings"].Vector();
-			buildings[20]["name"].String() = name;
-			buildings[20]["description"].String() = descr;
+			getBuild(town, 20)["name"].String() = name;
+			getBuild(town, 20)["description"].String() = descr;
 		}
 
 		//blacksmith
-		for(int town=0; town<GameConstants::F_NUMBER; town++)
+		for(int town=0; town<dataSize; town++)
 		{
-			JsonVector & buildings = dest.Vector()[town]["buildings"].Vector();
-			buildings[16]["name"].String() =  parser.readString();
-			buildings[16]["description"].String() = parser.readString();
+			getBuild(town, 16)["name"].String() =  parser.readString();
+			getBuild(town, 16)["description"].String() = parser.readString();
 			parser.endLine();
 		}
 	}
 	{
 		CLegacyConfigParser parser("DATA/BLDGSPEC.TXT");
 
-		for(int town=0; town<GameConstants::F_NUMBER; town++)
+		for(int town=0; town<dataSize; town++)
 		{
-			JsonVector & buildings = dest.Vector()[town]["buildings"].Vector();
 			for(int build=0; build<9; build++)
 			{
-				buildings[17+build]["name"].String() =  parser.readString();
-				buildings[17+build]["description"].String() = parser.readString();
+				getBuild(town, 17 + build)["name"].String() =  parser.readString();
+				getBuild(town, 17 + build)["description"].String() = parser.readString();
 				parser.endLine();
 			}
-			buildings[26]["name"].String() =  parser.readString(); // Grail
-			buildings[26]["description"].String() = parser.readString();
+			getBuild(town, 26)["name"].String() =  parser.readString(); // Grail
+			getBuild(town, 26)["description"].String() = parser.readString();
 			parser.endLine();
 
-			buildings[15]["name"].String() =  parser.readString(); // Resource silo
-			buildings[15]["description"].String() = parser.readString();
+			getBuild(town, 15)["name"].String() =  parser.readString(); // Resource silo
+			getBuild(town, 15)["description"].String() = parser.readString();
 			parser.endLine();
 		}
 	}
 	{
 		CLegacyConfigParser parser("DATA/DWELLING.TXT");
 
-		for(int town=0; town<GameConstants::F_NUMBER; town++)
+		for(int town=0; town<dataSize; town++)
 		{
-			JsonVector & buildings = dest.Vector()[town]["buildings"].Vector();
 			for(int build=0; build<14; build++)
 			{
-				buildings[30+build]["name"].String() =  parser.readString();
-				buildings[30+build]["description"].String() = parser.readString();
+				getBuild(town, 30 + build)["name"].String() =  parser.readString();
+				getBuild(town, 30 + build)["description"].String() = parser.readString();
 				parser.endLine();
 			}
 		}
@@ -217,22 +214,20 @@ void CTownHandler::loadLegacyData(JsonNode & dest)
 		size_t townID=0;
 		do
 		{
-			JsonNode & town = dest.Vector()[townID];
-
-			town["name"].String() = typeParser.readString();
-
+			dest[townID]["name"].String() = typeParser.readString();
 
 			for (int i=0; i<NAMES_PER_TOWN; i++)
 			{
 				JsonNode name;
 				name.String() = nameParser.readString();
-				town["names"].Vector().push_back(name);
+				dest[townID]["town"]["names"].Vector().push_back(name);
 				nameParser.endLine();
 			}
 			townID++;
 		}
 		while (typeParser.endLine());
 	}
+	return dest;
 }
 
 void CTownHandler::loadBuilding(CTown &town, const JsonNode & source)
@@ -243,7 +238,7 @@ void CTownHandler::loadBuilding(CTown &town, const JsonNode & source)
 
 	ret->mode = static_cast<CBuilding::EBuildMode>(boost::find(modes, source["mode"].String()) - modes);
 
-	ret->tid = town.typeID;
+	ret->town = &town;
 	ret->bid = BuildingID(source["id"].Float());
 	ret->name = source["name"].String();
 	ret->description = source["description"].String();
@@ -265,9 +260,21 @@ void CTownHandler::loadBuilding(CTown &town, const JsonNode & source)
 
 void CTownHandler::loadBuildings(CTown &town, const JsonNode & source)
 {
-	BOOST_FOREACH(const JsonNode &node, source.Vector())
+	if (source.getType() == JsonNode::DATA_VECTOR)
 	{
-		loadBuilding(town, node);
+		BOOST_FOREACH(auto &node, source.Vector())
+		{
+			if (!node.isNull())
+				loadBuilding(town, node);
+		}
+	}
+	else
+	{
+		BOOST_FOREACH(auto &node, source.Struct())
+		{
+			if (!node.second.isNull())
+				loadBuilding(town, node.second);
+		}
 	}
 }
 
@@ -304,9 +311,21 @@ void CTownHandler::loadStructure(CTown &town, const JsonNode & source)
 
 void CTownHandler::loadStructures(CTown &town, const JsonNode & source)
 {
-	BOOST_FOREACH(const JsonNode &node, source.Vector())
+	if (source.getType() == JsonNode::DATA_VECTOR)
 	{
-		loadStructure(town, node);
+		BOOST_FOREACH(auto &node, source.Vector())
+		{
+			if (!node.isNull())
+				loadStructure(town, node);
+		}
+	}
+	else
+	{
+		BOOST_FOREACH(auto &node, source.Struct())
+		{
+			if (!node.second.isNull())
+				loadStructure(town, node.second);
+		}
 	}
 }
 
@@ -415,7 +434,7 @@ void CTownHandler::loadTown(CTown &town, const JsonNode & source)
 {
 	auto resIter = boost::find(GameConstants::RESOURCE_NAMES, source["primaryResource"].String());
 	if (resIter == boost::end(GameConstants::RESOURCE_NAMES))
-		town.primaryRes = 127; //Wood + Ore
+		town.primaryRes = Res::WOOD_AND_ORE; //Wood + Ore
 	else
 		town.primaryRes = resIter - boost::begin(GameConstants::RESOURCE_NAMES);
 
@@ -462,7 +481,7 @@ void CTownHandler::loadTown(CTown &town, const JsonNode & source)
 
 		VLC->modh->identifiers.requestIdentifier("heroClass." + node.first, [=, &town](si32 classID)
 		{
-			VLC->heroh->classes.heroClasses[classID]->selectionProbability[town.typeID] = chance;
+			VLC->heroh->classes.heroClasses[classID]->selectionProbability[town.faction->index] = chance;
 		});
 	}
 
@@ -472,7 +491,7 @@ void CTownHandler::loadTown(CTown &town, const JsonNode & source)
 
 		VLC->modh->identifiers.requestIdentifier("spell." + node.first, [=, &town](si32 spellID)
 		{
-			SpellID(spellID).toSpell()->probabilities[town.typeID] = chance;
+			SpellID(spellID).toSpell()->probabilities[town.faction->index] = chance;
 		});
 	}
 
@@ -506,101 +525,68 @@ void CTownHandler::loadPuzzle(CFaction &faction, const JsonNode &source)
 	assert(faction.puzzleMap.size() == GameConstants::PUZZLE_MAP_PIECES);
 }
 
-void CTownHandler::load(std::string townID, const JsonNode &source)
+CFaction * CTownHandler::loadFromJson(const JsonNode &source)
 {
-	int id;
+	CFaction * faction = new CFaction();
 
-	if (source["index"].isNull())
-		id = factions.rbegin()->first + 1;
-	else
-		id = source["index"].Float();
-
-	CFaction & faction = factions[id];
-
-	faction.factionID = id;
-	faction.name = source["name"].String();
+	faction->name = source["name"].String();
 
 	VLC->modh->identifiers.requestIdentifier ("creature." + source["commander"].String(),
 		[=](si32 commanderID)
 		{
-			factions[id].commander = CreatureID(commanderID);
+			faction->commander = CreatureID(commanderID);
 		});
 
-	faction.creatureBg120 = source["creatureBackground"]["120px"].String();
-	faction.creatureBg130 = source["creatureBackground"]["130px"].String();
+	faction->creatureBg120 = source["creatureBackground"]["120px"].String();
+	faction->creatureBg130 = source["creatureBackground"]["130px"].String();
 
-	faction.nativeTerrain = ETerrainType(vstd::find_pos(GameConstants::TERRAIN_NAMES,
+	faction->nativeTerrain = ETerrainType(vstd::find_pos(GameConstants::TERRAIN_NAMES,
 		source["nativeTerrain"].String()));
 	int alignment = vstd::find_pos(EAlignment::names, source["alignment"].String());
 	if (alignment == -1)
-		faction.alignment = EAlignment::NEUTRAL;
+		faction->alignment = EAlignment::NEUTRAL;
 	else
-		faction.alignment = static_cast<EAlignment::EAlignment>(alignment);
+		faction->alignment = static_cast<EAlignment::EAlignment>(alignment);
 
 	if (!source["town"].isNull())
 	{
-		towns[id].typeID = id;
-		loadTown(towns[id], source["town"]);
+		faction->town = new CTown;
+		faction->town->faction = faction;
+		loadTown(*faction->town, source["town"]);
 	}
 	if (!source["puzzleMap"].isNull())
-		loadPuzzle(faction, source["puzzleMap"]);
+		loadPuzzle(*faction, source["puzzleMap"]);
 
-    logGlobal->traceStream() << "Added faction: " << townID;
-	VLC->modh->identifiers.registerObject(std::string("faction.") + townID, faction.factionID);
+	return faction;
 }
 
-void CTownHandler::load()
+void CTownHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
 {
-	JsonNode gameConf(ResourceID("config/gameConfig.json"));
-	JsonNode buildingsConf = JsonUtils::assembleFromFiles(gameConf["factions"].convertTo<std::vector<std::string> >());
+	auto object = loadFromJson(data);
+	object->index = factions.size();
 
-	JsonNode legacyConfig;
-	loadLegacyData(legacyConfig);
+	factions.push_back(object);
 
-	// semi-manually merge legacy config with towns json
-
-	for (size_t i=0; i< legacyConfig.Vector().size(); i++)
-	{
-		JsonNode & legacyFaction = legacyConfig.Vector()[i];
-		JsonNode & outputFaction = buildingsConf[ETownType::names[i]];
+	VLC->modh->identifiers.registerObject(scope, "faction", name, object->index);
+}
 
-		if (outputFaction["name"].isNull())
-			outputFaction["name"] = legacyFaction["name"];
+void CTownHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
+{
+	auto object = loadFromJson(data);
+	object->index = index;
 
-		if (!outputFaction["town"].isNull())
-		{
-			if (outputFaction["town"]["names"].isNull())
-				outputFaction["town"]["names"] = legacyFaction["names"];
+	assert(factions[index] == nullptr); // ensure that this id was not loaded before
+	factions[index] = object;
 
-			JsonNode & outputBuildings = outputFaction["town"]["buildings"];
-			JsonVector & legacyBuildings = legacyFaction["buildings"].Vector();
-			BOOST_FOREACH(JsonNode & building, outputBuildings.Vector())
-			{
-				if (vstd::contains(building.Struct(), "id") &&
-				    legacyBuildings.size() > building["id"].Float() )
-				{
-					//find same buildings in legacy and json configs
-					JsonNode & legacyBuilding = legacyBuildings[building["id"].Float()];
-
-					if (!legacyBuilding.isNull()) //merge if h3 config was found for this building
-						JsonUtils::merge(building, legacyBuilding);
-				}
-			}
-		}
-	}
-	BOOST_FOREACH(auto & entry, buildingsConf.Struct())
-	{
-		//JsonUtils::validate(entry.second, "vcmi:faction", entry.first);
-		load(entry.first, entry.second);
-	}
+	VLC->modh->identifiers.registerObject(scope, "faction", name, object->index);
 }
 
-std::set<TFaction> CTownHandler::getDefaultAllowedFactions() const
+std::vector<bool> CTownHandler::getDefaultAllowed() const
 {
-	std::set<TFaction> allowedFactions;
-	BOOST_FOREACH(auto town, towns)
+	std::vector<bool> allowedFactions;
+	BOOST_FOREACH(auto town, factions)
 	{
-		allowedFactions.insert(town.first);
+		allowedFactions.push_back(town->town != nullptr);
 	}
 	return allowedFactions;
 }

+ 54 - 66
lib/CTownHandler.h

@@ -4,6 +4,7 @@
 #include "ResourceSet.h"
 #include "int3.h"
 #include "GameConstants.h"
+#include "IHandlerBase.h"
 
 /*
  * CTownHandler.h, part of VCMI engine
@@ -17,6 +18,7 @@
 
 class CLegacyConfigParser;
 class JsonNode;
+class CTown;
 
 /// a typical building encountered in every castle ;]
 /// this is structure available to both client and server
@@ -28,7 +30,7 @@ class DLL_LINKAGE CBuilding
 	std::string description;
 
 public:
-	TFaction tid; //town ID
+	CTown * town; // town this building belongs to
 	BuildingID bid; //structure ID
 	TResources resources;
 
@@ -54,7 +56,7 @@ public:
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & tid & bid & resources & name & description & requirements & upgrade & mode;
+		h & town & bid & resources & name & description & requirements & upgrade & mode;
 	}
 
 	friend class CTownHandler;
@@ -79,10 +81,48 @@ struct DLL_LINKAGE CStructure
 	}
 };
 
+struct DLL_LINKAGE SPuzzleInfo
+{
+	ui16 number; //type of puzzle
+	si16 x, y; //position
+	ui16 whenUncovered; //determines the sequnce of discovering (the lesser it is the sooner puzzle will be discovered)
+	std::string filename; //file with graphic of this puzzle
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & number & x & y & whenUncovered & filename;
+	}
+};
+
+class CFaction
+{
+public:
+	std::string name; //town name, by default - from TownName.txt
+
+	TFaction index;
+
+	ETerrainType nativeTerrain;
+	EAlignment::EAlignment alignment;
+
+	CreatureID commander;
+
+	CTown * town; //NOTE: can be null
+
+	std::string creatureBg120;
+	std::string creatureBg130;
+
+	std::vector<SPuzzleInfo> puzzleMap;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & name & index & nativeTerrain & creatureBg120 & creatureBg130 & puzzleMap;
+	}
+};
+
 class DLL_LINKAGE CTown
 {
 public:
-	TFaction typeID;//same as CFaction::factionID
+	CFaction * faction;
 
 	std::vector<std::string> names; //names of the town instances
 
@@ -148,48 +188,12 @@ public:
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & names & typeID & creatures & dwellings & dwellingNames & buildings & hordeLvl & mageLevel
+		h & names & faction & creatures & dwellings & dwellingNames & buildings & hordeLvl & mageLevel
 			& primaryRes & warMachine & clientInfo & moatDamage;
 	}
 };
 
-struct DLL_LINKAGE SPuzzleInfo
-{
-	ui16 number; //type of puzzle
-	si16 x, y; //position
-	ui16 whenUncovered; //determines the sequnce of discovering (the lesser it is the sooner puzzle will be discovered)
-	std::string filename; //file with graphic of this puzzle
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & number & x & y & whenUncovered & filename;
-	}
-};
-
-class CFaction
-{
-public:
-	std::string name; //town name, by default - from TownName.txt
-
-	TFaction factionID;
-
-	ETerrainType nativeTerrain;
-	EAlignment::EAlignment alignment;
-
-	CreatureID commander;
-
-	std::string creatureBg120;
-	std::string creatureBg130;
-
-	std::vector<SPuzzleInfo> puzzleMap;
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & name & factionID & nativeTerrain & creatureBg120 & creatureBg130 & puzzleMap;
-	}
-};
-
-class DLL_LINKAGE CTownHandler
+class DLL_LINKAGE CTownHandler : public IHandlerBase
 {
 	/// loads CBuilding's into town
 	void loadBuilding(CTown &town, const JsonNode & source);
@@ -209,38 +213,22 @@ class DLL_LINKAGE CTownHandler
 
 	void loadPuzzle(CFaction & faction, const JsonNode & source);
 
-	/// load all available data from h3 txt(s) into json structure using format similar to vcmi configs
-	/// returns 2d array [townID] [buildID] of buildings
-	void loadLegacyData(JsonNode & dest);
+	CFaction * loadFromJson(const JsonNode & data);
 
 public:
-	std::map<TFaction, CTown> towns;
-	std::map<TFaction, CFaction> factions;
+	std::vector<ConstTransitivePtr<CFaction> > factions;
 
 	CTownHandler(); //c-tor, set pointer in VLC to this
 
-	/// main loading function for mods, accepts merged JSON source and add all entries from it into game
-	/// all entries in JSON should be checked for validness before using this function
-	void load(std::string townID, const JsonNode & source);
-
-	/// "entry point" for loading of OH3 town.
-	/// reads legacy txt's from H3 + vcmi json, merges them
-	/// and loads resulting structure to game using loadTowns method
-	void load();
-
-	/**
-	 * Gets a list of default allowed factions. OH3 factions are in the range of 0 to 8.
-	 *
-	 * TODO Proposal for town modding: Replace faction id with a unique machine readable town name
-	 * and create a JSON config file or merge it with other configs which describes which
-	 * towns can be used for random map generation / map editor(default map settings).
-	 *
-	 * @return a list of allowed factions, the index which is unique is the faction id
-	 */
-	std::set<TFaction> getDefaultAllowedFactions() const;
+	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+
+	void loadObject(std::string scope, std::string name, const JsonNode & data) override;
+	void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
+
+	std::vector<bool> getDefaultAllowed() const override;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & towns & factions;
+		h & factions;
 	}
 };

+ 5 - 1
lib/GameConstants.h

@@ -209,10 +209,14 @@ class PlayerColor : public BaseForID<PlayerColor, ui8>
 {
 	INSTID_LIKE_CLASS_COMMON(PlayerColor, ui8)
 
+	enum EPlayerColor
+	{
+		PLAYER_LIMIT_I = 8
+	};
+
 	DLL_LINKAGE static const PlayerColor CANNOT_DETERMINE; //253
 	DLL_LINKAGE static const PlayerColor UNFLAGGABLE; //254 - neutral objects (pandora, banks)
 	DLL_LINKAGE static const PlayerColor NEUTRAL; //255
-	DLL_LINKAGE static const int PLAYER_LIMIT_I = 8; //player limit per map
 	DLL_LINKAGE static const PlayerColor PLAYER_LIMIT; //player limit per map
 
 	DLL_LINKAGE bool isValidPlayer() const; //valid means < PLAYER_LIMIT (especially non-neutral)

+ 1 - 1
lib/HeroBonus.cpp

@@ -1158,7 +1158,7 @@ Bonus::Bonus()
 	valType = ADDITIVE_VALUE;
 	effectRange = NO_LIMIT;
 	val = 0;
-	source = OTHER;	
+	source = OTHER;
 }
 
 Bonus::~Bonus()

+ 2 - 3
lib/IGameCallback.cpp

@@ -256,7 +256,7 @@ template DLL_LINKAGE void CPrivilagedInfoCallback::loadCommonState<CLoadIntegrit
 template DLL_LINKAGE void CPrivilagedInfoCallback::loadCommonState<CLoadFile>(CLoadFile&);
 template DLL_LINKAGE void CPrivilagedInfoCallback::saveCommonState<CSaveFile>(CSaveFile&) const;
 
-inline TerrainTile * CNonConstInfoCallback::getTile( int3 pos )
+TerrainTile * CNonConstInfoCallback::getTile( int3 pos )
 {
 	if(!gs->map->isInTheMap(pos))
 		return NULL;
@@ -274,7 +274,7 @@ const CTown * CGameInfoCallback::getNativeTown(PlayerColor color) const
 {
 	const PlayerSettings *ps = getPlayerSettings(color);
 	ERROR_RET_VAL_IF(!ps, "There is no such player!", NULL);
-	return &VLC->townh->towns[ps->castle];
+	return VLC->townh->factions[ps->castle]->town;
 }
 
 const CGObjectInstance * CGameInfoCallback::getObjByQuestIdentifier(int identifier) const
@@ -900,7 +900,6 @@ CGHeroInstance *CNonConstInfoCallback::getHero(ObjectInstanceID objid)
 
 CGTownInstance *CNonConstInfoCallback::getTown(ObjectInstanceID objid)
 {
-
 	return const_cast<CGTownInstance*>(CGameInfoCallback::getTown(objid));
 }
 

+ 40 - 0
lib/IHandlerBase.h

@@ -0,0 +1,40 @@
+#pragma once
+
+/*
+ * IHandlerBase.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+class JsonNode;
+
+/// base class for all handlers that can be accessed from mod system
+class DLL_LINKAGE IHandlerBase
+{
+	// there also should be private member with such signature:
+	// Object * loadFromJson(const JsonNode & json);
+	// where Object is type of data loaded by handler
+	// primary used in loadObject methods
+
+public:
+	/// loads all original game data in vector of json nodes
+	/// dataSize - is number of items that must be loaded (normally - constant from GameConstants)
+	virtual std::vector<JsonNode> loadLegacyData(size_t dataSize) = 0;
+
+	/// loads single object into game. Scope is namespace of this object, same as name of source mod
+	virtual void loadObject(std::string scope, std::string name, const JsonNode & data) = 0;
+	virtual void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) = 0;
+
+	/**
+	 * Gets a list of objects that are allowed by default on maps
+	 *
+	 * @return a list of allowed objects, the index is the object id
+	 */
+	virtual std::vector<bool> getDefaultAllowed() const = 0;
+
+	virtual ~IHandlerBase(){}
+};

+ 4 - 4
lib/JsonNode.cpp

@@ -1125,8 +1125,8 @@ bool JsonValidator::validate(const JsonNode &root, std::string schemaName, std::
 
 	if (!errors.empty())
 	{
-        logGlobal->warnStream() << "Data in " << name << " is invalid!";
-        logGlobal->warnStream() << errors;
+		logGlobal->warnStream() << "Data in " << name << " is invalid!";
+		logGlobal->warnStream() << errors;
 	}
 
 	return errors.empty();
@@ -1162,7 +1162,7 @@ Bonus * JsonUtils::parseBonus (const JsonVector &ability_vec) //TODO: merge with
 template <typename T>
 const T & parseByMap(const std::map<std::string, T> & map, const JsonNode * val, std::string err)
 {
-	static T defaultValue;
+	static T defaultValue = T();
 	if (!val->isNull())
 	{
 		std::string type = val->String();
@@ -1179,7 +1179,7 @@ const T & parseByMap(const std::map<std::string, T> & map, const JsonNode * val,
 	}
 	else
 		return defaultValue;
-};
+}
 
 void JsonUtils::resolveIdentifier (si32 &var, const JsonNode &node, std::string name)
 {

+ 3 - 1
lib/ResourceSet.h

@@ -22,7 +22,9 @@ namespace Res
 
 	enum ERes
 	{
-		WOOD = 0, MERCURY, ORE, SULFUR, CRYSTAL, GEMS, GOLD, MITHRIL
+		WOOD = 0, MERCURY, ORE, SULFUR, CRYSTAL, GEMS, GOLD, MITHRIL,
+
+		WOOD_AND_ORE = 127 // special case for town bonus resource
 	};
 
 	//class to be representing a vector of resource

+ 16 - 0
lib/StringConstants.h

@@ -59,6 +59,22 @@ namespace NSecondarySkill
 	};
 }
 
+namespace EBuildingType
+{
+	const std::string names [44] =
+	{
+		"mageGuild1",       "mageGuild2",       "mageGuild3",       "mageGuild4",       "mageGuild5",
+		"tavern",           "shipyard",         "fort",             "citadel",          "castle",
+		"villageHall",      "townHall",         "cityHall",         "capitol",          "marketplace",
+		"resourceSilo",     "blacksmith",       "special1",         "horde1",           "horde1Upgr",
+		"ship",             "special2",         "special3",         "special4",         "horde2",
+		"horde2Upgr",       "grail",            "extraTownHall",    "extraCityHall",    "extraCapitol",
+		"dwellingLvl1",     "dwellingLvl2",     "dwellingLvl3",     "dwellingLvl4",     "dwellingLvl5",
+		"dwellingLvl6",     "dwellingLvl7",     "dwellingUpLvl1",   "dwellingUpLvl2",   "dwellingUpLvl3",
+		"dwellingUpLvl4",   "dwellingUpLvl5",   "dwellingUpLvl6",   "dwellingUpLvl7"
+	};
+}
+
 namespace ETownType
 {
 	const std::string names [GameConstants::F_NUMBER] =

+ 9 - 7
lib/VCMI_Lib.cpp

@@ -78,19 +78,18 @@ void LibClasses::loadFilesystem()
 
 static void logHandlerLoaded(const std::string& name, CStopWatch &timer)
 {
-   logGlobal->infoStream()<<"\t" << name << " handler: "<<timer.getDiff();
+   logGlobal->infoStream()<<"\t\t" << name << " handler: "<<timer.getDiff();
 };
 
 template <class Handler> void createHandler(Handler *&handler, const std::string &name, CStopWatch &timer)
 {
 	handler = new Handler();
-	handler->load();
 	logHandlerLoaded(name, timer);
 } 
 
 void LibClasses::init()
 {
-	CStopWatch pomtime;
+	CStopWatch pomtime, totalTime;
 
 	createHandler(bth, "Bonus type", pomtime);
 	
@@ -110,7 +109,9 @@ void LibClasses::init()
 
 	createHandler(spellh, "Spell", pomtime);
 
-	modh->loadActiveMods();
+	logGlobal->infoStream()<<"\tInitializing handers: "<< totalTime.getDiff();
+
+	modh->loadGameContent();
 	modh->reload();
 	//FIXME: make sure that everything is ok after game restart
 	//TODO: This should be done every time mod config changes
@@ -155,9 +156,10 @@ LibClasses::LibClasses()
 
 void LibClasses::callWhenDeserializing()
 {
-	generaltexth = new CGeneralTextHandler;
-	generaltexth->load();
-	arth->load(true);
+	// FIXME: check if any of these are needed
+	//generaltexth = new CGeneralTextHandler;
+	//generaltexth->load();
+	//arth->load(true);
 	//modh->recreateHandlers();
 	//modh->loadConfigFromFile ("defaultMods"); //TODO: remember last saved config
 }

+ 2 - 2
lib/VCMI_Lib.h

@@ -27,14 +27,14 @@ class CBonusTypeHandler;
 class DLL_LINKAGE LibClasses
 {
 	CBonusTypeHandler * bth;
-	
+
 	void callWhenDeserializing(); //should be called only by serialize !!!
 	void makeNull(); //sets all handler pointers to null
 public:
 	bool IS_AI_ENABLED; //VLC is the only object visible from both CMT and GeniusAI
 	
 	const IBonusTypeHandler * getBth() const;
-	
+
 	CArtHandler * arth;
 	CHeroHandler * heroh;
 	CCreatureHandler * creh;

+ 7 - 4
lib/mapping/CMap.cpp

@@ -18,7 +18,10 @@ PlayerInfo::PlayerInfo(): canHumanPlay(false), canComputerPlay(false),
 	aiTactic(EAiTactic::RANDOM), isFactionRandom(false), mainHeroPortrait(-1), hasMainTown(false),
 	generateHeroAtMainTown(false), team(255), generateHero(false), p7(0), hasHero(false), customHeroID(-1), powerPlaceholders(-1)
 {
-	allowedFactions = VLC->townh->getDefaultAllowedFactions();
+	auto allowed = VLC->townh->getDefaultAllowed();
+	for (size_t i=0; i<allowed.size(); i++)
+		if (allowed[i])
+			allowedFactions.insert(i);
 }
 
 si8 PlayerInfo::defaultCastle() const
@@ -136,7 +139,7 @@ bool TerrainTile::isWater() const
 CMapHeader::CMapHeader() : version(EMapFormat::SOD), height(72), width(72),
 	twoLevel(true), difficulty(1), levelLimit(0), howManyTeams(0), areAnyPlayers(false)
 {
-	allowedHeroes = VLC->heroh->getDefaultAllowedHeroes();
+	allowedHeroes = VLC->heroh->getDefaultAllowed();
 	players.resize(PlayerColor::PLAYER_LIMIT_I);
 }
 
@@ -148,8 +151,8 @@ CMapHeader::~CMapHeader()
 CMap::CMap() : checksum(0), grailRadious(0), terrain(nullptr)
 {
 	allowedAbilities = VLC->heroh->getDefaultAllowedAbilities();
-	allowedArtifact = VLC->arth->getDefaultAllowedArtifacts();
-	allowedSpell = VLC->spellh->getDefaultAllowedSpells();
+	allowedArtifact = VLC->arth->getDefaultAllowed();
+	allowedSpell = VLC->spellh->getDefaultAllowed();
 }
 
 CMap::~CMap()

+ 1 - 1
lib/mapping/CMapEditManager.h

@@ -16,7 +16,7 @@
 
 class CGObjectInstance;
 class CTerrainViewPatternConfig;
-class TerrainViewPattern;
+struct TerrainViewPattern;
 
 namespace ETerrainGroup
 {

+ 2 - 2
lib/rmg/CMapGenerator.cpp

@@ -160,7 +160,7 @@ void CMapGenOptions::setMonsterStrength(EMonsterStrength::EMonsterStrength value
 void CMapGenOptions::resetPlayersMap()
 {
 	players.clear();
-	int realPlayersCnt = playersCnt == RANDOM_SIZE ? PlayerColor::PLAYER_LIMIT_I : playersCnt;
+	int realPlayersCnt = playersCnt == RANDOM_SIZE ? static_cast<int>(PlayerColor::PLAYER_LIMIT_I) : playersCnt;
 	int realCompOnlyPlayersCnt = compOnlyPlayersCnt == RANDOM_SIZE ? (PlayerColor::PLAYER_LIMIT_I - realPlayersCnt) : compOnlyPlayersCnt;
 	for(int color = 0; color < (realPlayersCnt + realCompOnlyPlayersCnt); ++color)
 	{
@@ -337,7 +337,7 @@ si32 CMapGenOptions::CPlayerSettings::getStartingTown() const
 
 void CMapGenOptions::CPlayerSettings::setStartingTown(si32 value)
 {
-	if(value >= -1 && value < static_cast<int>(VLC->townh->towns.size()))
+	if(value >= -1 && value < static_cast<int>(VLC->townh->factions.size()))
 	{
 		startingTown = value;
 	}

+ 14 - 3
server/CGameHandler.cpp

@@ -1271,7 +1271,7 @@ void CGameHandler::newTurn()
 		{
 			if(t->hasBuilt(BuildingID::RESOURCE_SILO)) //there is resource silo
 			{
-				if(t->town->primaryRes == 127) //we'll give wood and ore
+				if(t->town->primaryRes == Res::WOOD_AND_ORE) //we'll give wood and ore
 				{
 					n.res[player][Res::WOOD] ++;
 					n.res[player][Res::ORE] ++;
@@ -4739,11 +4739,12 @@ bool CGameHandler::complain( const std::string &problem )
 
 void CGameHandler::showGarrisonDialog( ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits, const boost::function<void()> &cb )
 {
-	PlayerColor player = getOwner(hid);
+	//PlayerColor player = getOwner(hid);
 	auto upperArmy = dynamic_cast<const CArmedInstance*>(getObj(upobj));
 	auto lowerArmy = dynamic_cast<const CArmedInstance*>(getObj(hid));
 	
-	assert(upperArmy, lowerArmy);
+	assert(lowerArmy);
+	assert(upperArmy);
 
 	auto garrisonQuery = make_shared<CGarrisonDialogQuery>(upperArmy, lowerArmy);
 	queries.addQuery(garrisonQuery);
@@ -4789,6 +4790,16 @@ bool CGameHandler::isAllowedExchange( ObjectInstanceID id1, ObjectInstanceID id2
 				return true;
 		}
 
+		if (o1->ID == Obj::HERO && o2->ID == Obj::HERO)
+		{
+			const CGHeroInstance *h1 = static_cast<const CGHeroInstance*>(o1);
+			const CGHeroInstance *h2 = static_cast<const CGHeroInstance*>(o2);
+
+			// two heroes in same town (garrisoned and visiting)
+			if (h1->visitedTown != nullptr && h2->visitedTown != nullptr && h1->visitedTown == h2->visitedTown)
+				return true;
+		}
+
 		//Ongoing garrison exchange
 		if(auto dialog = std::dynamic_pointer_cast<CGarrisonDialogQuery>(queries.topQuery(o1->tempOwner)))
 		{

+ 1 - 1
server/CQuery.cpp

@@ -1,7 +1,7 @@
 #include "StdInc.h"
 #include "CQuery.h"
 #include "CGameHandler.h"
-#include "..\lib\BattleState.h"
+#include "../lib/BattleState.h"
 
 boost::mutex Queries::mx;
 

+ 4 - 4
server/CQuery.h

@@ -1,7 +1,7 @@
 #pragma once
-#include "..\lib\GameConstants.h"
-#include "..\lib\int3.h"
-#include "..\lib\NetPacks.h"
+#include "../lib/GameConstants.h"
+#include "../lib/int3.h"
+#include "../lib/NetPacks.h"
 
 class CGObjectInstance;
 class CGHeroInstance;
@@ -174,4 +174,4 @@ public:
 	std::vector<shared_ptr<CQuery>> allQueries();
 	//void removeQuery
 
-};
+};