소스 검색

Merge pull request #5814 from Laserlicht/mage_guild

Mage guild configurable
Ivan Savenko 6 달 전
부모
커밋
e31f4367a4

+ 23 - 10
client/windows/CCastleInterface.cpp

@@ -1194,7 +1194,10 @@ void CCastleBuildings::enterTownHall()
 void CCastleBuildings::openMagesGuild()
 {
 	auto mageGuildBackground = GAME->interface()->castleInt->town->getTown()->clientInfo.guildBackground;
-	ENGINE->windows().createAndPushWindow<CMageGuildScreen>(GAME->interface()->castleInt, mageGuildBackground);
+	assert(mageGuildBackground.size() == 1 || mageGuildBackground.size() == GAME->interface()->castleInt->town->getTown()->mageLevel);
+	auto selectedMageGuildBackground = mageGuildBackground.size() == 1 ? mageGuildBackground[0] : mageGuildBackground[town->mageGuildLevel() - 1];
+
+	ENGINE->windows().createAndPushWindow<CMageGuildScreen>(GAME->interface()->castleInt, selectedMageGuildBackground);
 }
 
 void CCastleBuildings::openTownHall()
@@ -2114,7 +2117,14 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner, const ImagePath & i
 {
 	OBJECT_CONSTRUCTION;
 
-	window = std::make_shared<CPicture>(owner->town->getTown()->clientInfo.guildWindow, 332, 76);
+	auto guildWindow = owner->town->getTown()->clientInfo.guildWindow;
+	assert(guildWindow.size() == 1 || guildWindow.size() == GAME->interface()->castleInt->town->getTown()->mageLevel);
+	auto selectedGuildWindow = guildWindow.size() == 1 ? guildWindow[0] : guildWindow[owner->town->mageGuildLevel() - 1];
+
+	auto windowPosition = owner->town->getTown()->clientInfo.guildWindowPosition;
+	if(windowPosition == Point(0, 0)) // TODO: remove legacy for compatibility
+		windowPosition = Point(332, 76);
+	window = std::make_shared<CPicture>(selectedGuildWindow, windowPosition.x, windowPosition.y);
 
 	resdatabar = std::make_shared<CMinorResDataBar>();
 	resdatabar->moveBy(pos.topLeft(), true);
@@ -2135,20 +2145,23 @@ void CMageGuildScreen::updateSpells(ObjectInstanceID tID)
 		return;
 
 	OBJECT_CONSTRUCTION;
-	static const std::vector<std::vector<Point> > positions =
-	{
-		{Point(222,445), Point(312,445), Point(402,445), Point(520,445), Point(610,445), Point(700,445)},
-		{Point(48,53),   Point(48,147),  Point(48,241),  Point(48,335),  Point(48,429)},
-		{Point(570,82),  Point(672,82),  Point(570,157), Point(672,157)},
-		{Point(183,42),  Point(183,148), Point(183,253)},
-		{Point(491,325), Point(591,325)}
-	};
 
 	spells.clear();
 	emptyScrolls.clear();
 
 	const CGTownInstance * town = GAME->interface()->cb->getTown(townId);
 
+	auto positions = town->getTown()->clientInfo.guildSpellPositions;
+	if(!positions.size()) // TODO: remove legacy for compatibility
+		positions =
+		{
+			{Point(222,445), Point(312,445), Point(402,445), Point(520,445), Point(610,445), Point(700,445)},
+			{Point(48,53),   Point(48,147),  Point(48,241),  Point(48,335),  Point(48,429)},
+			{Point(570,82),  Point(672,82),  Point(570,157), Point(672,157)},
+			{Point(183,42),  Point(183,148), Point(183,253)},
+			{Point(491,325), Point(591,325)}
+		};
+
 	for(uint32_t i=0; i<town->getTown()->mageLevel; i++)
 	{
 		uint32_t spellCount = town->spellsAtLevel(i+1,false); //spell at level with -1 hmmm?

+ 9 - 2
config/factions/castle.json

@@ -122,9 +122,9 @@
 			"musicTheme" : [ "music/CstleTown" ],
 			"defaultTavern" : 5,
 			"tavernVideo" : "TAVERN.BIK",
-			"guildBackground" : "TPMAGE.bmp",
+			"guildBackground" : [ "TPMAGE.bmp" ],
 			"townBackground": "TBCSBACK.bmp",
-			"guildWindow": "TPMAGECS.bmp",
+			"guildWindow": [ "TPMAGECS.bmp" ],
 			"buildingsIcons": "HALLCSTL.DEF",
 			"hallBackground": "TPTHBKCS.BMP",
 			"hallSlots":
@@ -147,6 +147,13 @@
 			],
 			"horde" : [ 2, -1 ],
 			"mageGuild" : 4,
+			"guildSpellPositions" : [
+				[ { "x": 222, "y": 445 }, { "x": 312, "y": 445 }, { "x": 402, "y": 445 }, { "x": 520, "y": 445 }, { "x": 610, "y": 445 }, { "x": 700, "y": 445 } ],
+				[ { "x":  48, "y":  53 }, { "x":  48, "y": 147 }, { "x":  48, "y": 241 }, { "x":  48, "y": 335 }, { "x":  48, "y": 429 } ],
+				[ { "x": 570, "y":  82 }, { "x": 672, "y":  82 }, { "x": 570, "y": 157 }, { "x": 672, "y": 157 } ],
+				[ { "x": 183, "y":  42 }, { "x": 183, "y": 148 }, { "x": 183, "y": 253 } ]
+			],
+			"guildWindowPosition": { "x": 332, "y": 76 },
 			"moatAbility" : "castleMoat",
 			// primaryResource not specified so town get both Wood and Ore for resource bonus
 

+ 10 - 2
config/factions/conflux.json

@@ -126,9 +126,9 @@
 			"musicTheme" : [ "music/ElemTown" ],
 			"defaultTavern" : 5,
 			"tavernVideo" : "TAVERN.BIK",
-			"guildBackground" : "TPMAGE.bmp",
+			"guildBackground" : [ "TPMAGE.bmp" ],
 			"townBackground": "TBELBACK.bmp",
-			"guildWindow": "TPMAGEEL.bmp",
+			"guildWindow": [ "TPMAGEEL.bmp" ],
 			"buildingsIcons": "HALLELEM.DEF",
 			"hallBackground": "TPTHBKFR.BMP",
 			"hallSlots":
@@ -151,6 +151,14 @@
 			],
 			"horde" : [ 0, -1 ],
 			"mageGuild" : 5,
+			"guildSpellPositions" : [
+				[ { "x": 222, "y": 445 }, { "x": 312, "y": 445 }, { "x": 402, "y": 445 }, { "x": 520, "y": 445 }, { "x": 610, "y": 445 }, { "x": 700, "y": 445 } ],
+				[ { "x":  48, "y":  53 }, { "x":  48, "y": 147 }, { "x":  48, "y": 241 }, { "x":  48, "y": 335 }, { "x":  48, "y": 429 } ],
+				[ { "x": 570, "y":  82 }, { "x": 672, "y":  82 }, { "x": 570, "y": 157 }, { "x": 672, "y": 157 } ],
+				[ { "x": 183, "y":  42 }, { "x": 183, "y": 148 }, { "x": 183, "y": 253 } ],
+				[ { "x": 491, "y": 325 }, { "x": 591, "y": 325 } ]
+			],
+			"guildWindowPosition": { "x": 332, "y": 76 },
 			"primaryResource" : "mercury",
 			"moatAbility" : "castleMoat",
 

+ 10 - 2
config/factions/dungeon.json

@@ -122,9 +122,9 @@
 			"musicTheme" : [ "music/Dungeon" ],
 			"defaultTavern" : 5,
 			"tavernVideo" : "TAVERN.BIK",
-			"guildBackground" : "TPMAGE.bmp",
+			"guildBackground" : [ "TPMAGE.bmp" ],
 			"townBackground": "TBDNBACK.bmp",
-			"guildWindow": "TPMAGEDN.bmp",
+			"guildWindow": [ "TPMAGEDN.bmp" ],
 			"buildingsIcons": "HALLDUNG.DEF",
 			"hallBackground": "TPTHBKDG.BMP",
 			"hallSlots":
@@ -147,6 +147,14 @@
 			],
 			"horde" : [ 0, -1 ],
 			"mageGuild" : 5,
+			"guildSpellPositions" : [
+				[ { "x": 222, "y": 445 }, { "x": 312, "y": 445 }, { "x": 402, "y": 445 }, { "x": 520, "y": 445 }, { "x": 610, "y": 445 }, { "x": 700, "y": 445 } ],
+				[ { "x":  48, "y":  53 }, { "x":  48, "y": 147 }, { "x":  48, "y": 241 }, { "x":  48, "y": 335 }, { "x":  48, "y": 429 } ],
+				[ { "x": 570, "y":  82 }, { "x": 672, "y":  82 }, { "x": 570, "y": 157 }, { "x": 672, "y": 157 } ],
+				[ { "x": 183, "y":  42 }, { "x": 183, "y": 148 }, { "x": 183, "y": 253 } ],
+				[ { "x": 491, "y": 325 }, { "x": 591, "y": 325 } ]
+			],
+			"guildWindowPosition": { "x": 332, "y": 76 },
 			"primaryResource" : "sulfur",
 			"moatAbility" : "dungeonMoat",
 

+ 8 - 2
config/factions/fortress.json

@@ -122,9 +122,9 @@
 			"musicTheme" : [ "music/FortressTown" ],
 			"defaultTavern" : 5,
 			"tavernVideo" : "TAVERN.BIK",
-			"guildBackground" : "TPMAGE.bmp",
+			"guildBackground" : [ "TPMAGE.bmp" ],
 			"townBackground": "TBFRBACK.bmp",
-			"guildWindow": "TPMAGEFR.bmp",
+			"guildWindow": [ "TPMAGEFR.bmp" ],
 			"buildingsIcons": "HALLFORT.DEF",
 			"hallBackground": "TPTHBKFR.BMP",
 			"hallSlots":
@@ -147,6 +147,12 @@
 			],
 			"horde" : [ 0, -1 ],
 			"mageGuild" : 3,
+			"guildSpellPositions" : [
+				[ { "x": 222, "y": 445 }, { "x": 312, "y": 445 }, { "x": 402, "y": 445 }, { "x": 520, "y": 445 }, { "x": 610, "y": 445 }, { "x": 700, "y": 445 } ],
+				[ { "x":  48, "y":  53 }, { "x":  48, "y": 147 }, { "x":  48, "y": 241 }, { "x":  48, "y": 335 }, { "x":  48, "y": 429 } ],
+				[ { "x": 570, "y":  82 }, { "x": 672, "y":  82 }, { "x": 570, "y": 157 }, { "x": 672, "y": 157 } ]
+			],
+			"guildWindowPosition": { "x": 332, "y": 76 },
 			"moatAbility" : "fortressMoat",
 			// primaryResource not specified so town get both Wood and Ore for resource bonus
 

+ 10 - 2
config/factions/inferno.json

@@ -123,9 +123,9 @@
 			"musicTheme" : [ "music/InfernoTown" ],
 			"defaultTavern" : 5,
 			"tavernVideo" : "TAVERN.BIK",
-			"guildBackground" : "TPMAGE.bmp",
+			"guildBackground" : [ "TPMAGE.bmp" ],
 			"townBackground": "TBINBACK.bmp",
-			"guildWindow": "TPMAGEIN.bmp",
+			"guildWindow": [ "TPMAGEIN.bmp" ],
 			"buildingsIcons": "HALLINFR.DEF",
 			"hallBackground": "TPTHBKIN.BMP",
 			"hallSlots":
@@ -148,6 +148,14 @@
 			],
 			"horde" : [ 0, 2 ],
 			"mageGuild" : 5,
+			"guildSpellPositions" : [
+				[ { "x": 222, "y": 445 }, { "x": 312, "y": 445 }, { "x": 402, "y": 445 }, { "x": 520, "y": 445 }, { "x": 610, "y": 445 }, { "x": 700, "y": 445 } ],
+				[ { "x":  48, "y":  53 }, { "x":  48, "y": 147 }, { "x":  48, "y": 241 }, { "x":  48, "y": 335 }, { "x":  48, "y": 429 } ],
+				[ { "x": 570, "y":  82 }, { "x": 672, "y":  82 }, { "x": 570, "y": 157 }, { "x": 672, "y": 157 } ],
+				[ { "x": 183, "y":  42 }, { "x": 183, "y": 148 }, { "x": 183, "y": 253 } ],
+				[ { "x": 491, "y": 325 }, { "x": 591, "y": 325 } ]
+			],
+			"guildWindowPosition": { "x": 332, "y": 76 },
 			"primaryResource" : "mercury",
 			"moatAbility" : "infernoMoat",
 

+ 10 - 2
config/factions/necropolis.json

@@ -127,9 +127,9 @@
 			"musicTheme" : [ "music/NecroTown" ],
 			"defaultTavern" : 5,
 			"tavernVideo" : "TAVERN.BIK",
-			"guildBackground" : "TPMAGE.bmp",
+			"guildBackground" : [ "TPMAGE.bmp" ],
 			"townBackground": "TBNCBACK.bmp",
-			"guildWindow": "TPMAGENC.bmp",
+			"guildWindow": [ "TPMAGENC.bmp" ],
 			"buildingsIcons": "HALLNECR.DEF",
 			"hallBackground": "TPTHBKNC.BMP",
 			"hallSlots":
@@ -152,6 +152,14 @@
 			],
 			"horde" : [ 0, -1 ],
 			"mageGuild" : 5,
+			"guildSpellPositions" : [
+				[ { "x": 222, "y": 445 }, { "x": 312, "y": 445 }, { "x": 402, "y": 445 }, { "x": 520, "y": 445 }, { "x": 610, "y": 445 }, { "x": 700, "y": 445 } ],
+				[ { "x":  48, "y":  53 }, { "x":  48, "y": 147 }, { "x":  48, "y": 241 }, { "x":  48, "y": 335 }, { "x":  48, "y": 429 } ],
+				[ { "x": 570, "y":  82 }, { "x": 672, "y":  82 }, { "x": 570, "y": 157 }, { "x": 672, "y": 157 } ],
+				[ { "x": 183, "y":  42 }, { "x": 183, "y": 148 }, { "x": 183, "y": 253 } ],
+				[ { "x": 491, "y": 325 }, { "x": 591, "y": 325 } ]
+			],
+			"guildWindowPosition": { "x": 332, "y": 76 },
 			"moatAbility" : "necropolisMoat",
 			// primaryResource not specified so town get both Wood and Ore for resource bonus
 

+ 10 - 2
config/factions/rampart.json

@@ -126,9 +126,9 @@
 			"musicTheme" : [ "music/Rampart" ],
 			"defaultTavern" : 5,
 			"tavernVideo" : "TAVERN.BIK",
-			"guildBackground" : "TPMAGE.bmp",
+			"guildBackground" : [ "TPMAGE.bmp" ],
 			"townBackground": "TBRMBACK.bmp",
-			"guildWindow": "TPMAGERM.bmp",
+			"guildWindow": [ "TPMAGERM.bmp" ],
 			"buildingsIcons": "HALLRAMP.DEF",
 			"hallBackground": "TPTHBKRM.BMP",
 			"hallSlots":
@@ -151,6 +151,14 @@
 			],
 			"horde" : [ 1, 4 ],
 			"mageGuild" : 5,
+			"guildSpellPositions" : [
+				[ { "x": 222, "y": 445 }, { "x": 312, "y": 445 }, { "x": 402, "y": 445 }, { "x": 520, "y": 445 }, { "x": 610, "y": 445 }, { "x": 700, "y": 445 } ],
+				[ { "x":  48, "y":  53 }, { "x":  48, "y": 147 }, { "x":  48, "y": 241 }, { "x":  48, "y": 335 }, { "x":  48, "y": 429 } ],
+				[ { "x": 570, "y":  82 }, { "x": 672, "y":  82 }, { "x": 570, "y": 157 }, { "x": 672, "y": 157 } ],
+				[ { "x": 183, "y":  42 }, { "x": 183, "y": 148 }, { "x": 183, "y": 253 } ],
+				[ { "x": 491, "y": 325 }, { "x": 591, "y": 325 } ]
+			],
+			"guildWindowPosition": { "x": 332, "y": 76 },
 			"primaryResource" : "crystal",
 			"moatAbility" : "rampartMoat",
 

+ 8 - 2
config/factions/stronghold.json

@@ -120,9 +120,9 @@
 			"musicTheme" : [ "music/Stronghold" ],
 			"defaultTavern" : 5,
 			"tavernVideo" : "TAVERN.BIK",
-			"guildBackground" : "TPMAGE.bmp",
+			"guildBackground" : [ "TPMAGE.bmp" ],
 			"townBackground": "TBSTBACK.bmp",
-			"guildWindow": "TPMAGEST.bmp",
+			"guildWindow": [ "TPMAGEST.bmp" ],
 			"buildingsIcons": "HALLSTRN.DEF",
 			"hallBackground": "TPTHBKTW.BMP",
 			"hallSlots":
@@ -145,6 +145,12 @@
 			],
 			"horde" : [ 0, -1 ],
 			"mageGuild" : 3,
+			"guildSpellPositions" : [
+				[ { "x": 222, "y": 445 }, { "x": 312, "y": 445 }, { "x": 402, "y": 445 }, { "x": 520, "y": 445 }, { "x": 610, "y": 445 }, { "x": 700, "y": 445 } ],
+				[ { "x":  48, "y":  53 }, { "x":  48, "y": 147 }, { "x":  48, "y": 241 }, { "x":  48, "y": 335 }, { "x":  48, "y": 429 } ],
+				[ { "x": 570, "y":  82 }, { "x": 672, "y":  82 }, { "x": 570, "y": 157 }, { "x": 672, "y": 157 } ]
+			],
+			"guildWindowPosition": { "x": 332, "y": 76 },
 			"moatAbility" : "strongholdMoat",
 			// primaryResource not specified so town get both Wood and Ore for resource bonus
 

+ 10 - 2
config/factions/tower.json

@@ -121,9 +121,9 @@
 			"musicTheme" : [ "music/TowerTown" ],
 			"defaultTavern" : 5,
 			"tavernVideo" : "TAVERN.BIK",
-			"guildBackground" : "TPMAGE.bmp",
+			"guildBackground" : [ "TPMAGE.bmp" ],
 			"townBackground": "TBTWBACK.bmp",
-			"guildWindow": "TPMAGETW.bmp",
+			"guildWindow": [ "TPMAGETW.bmp" ],
 			"buildingsIcons": "HALLTOWR.DEF",
 			"hallBackground": "TPTHBKTW.BMP",
 			"hallSlots":
@@ -147,6 +147,14 @@
 			"horde" : [ 1, -1 ],
 			"primaryResource" : "gems",
 			"mageGuild" : 5,
+			"guildSpellPositions" : [
+				[ { "x": 222, "y": 445 }, { "x": 312, "y": 445 }, { "x": 402, "y": 445 }, { "x": 520, "y": 445 }, { "x": 610, "y": 445 }, { "x": 700, "y": 445 } ],
+				[ { "x":  48, "y":  53 }, { "x":  48, "y": 147 }, { "x":  48, "y": 241 }, { "x":  48, "y": 335 }, { "x":  48, "y": 429 } ],
+				[ { "x": 570, "y":  82 }, { "x": 672, "y":  82 }, { "x": 570, "y": 157 }, { "x": 672, "y": 157 } ],
+				[ { "x": 183, "y":  42 }, { "x": 183, "y": 148 }, { "x": 183, "y": 253 } ],
+				[ { "x": 491, "y": 325 }, { "x": 591, "y": 325 } ]
+			],
+			"guildWindowPosition": { "x": 332, "y": 76 },
 			"moatAbility" : "towerMoat",
 
 			"buildings" :

+ 44 - 6
config/schemas/faction.json

@@ -166,13 +166,51 @@
 					"format" : "imageFile"
 				},
 				"guildWindow" : {
-					"type" : "string",
-					"description" : "Image with small view on town from mage guild"
+					"type" : "array",
+					"description" : "Image with small view on town from mage guild (each array element for different mage guild level; if one element only this will be always selected)",
+					"minItems" : 1,
+					"items" : { 
+						"type" : "string",
+						"format" : "imageFile"
+					}
 				},
 				"guildBackground" : {
-					"type" : "string",
-					"description" : "Image with background of mage guild",
-					"format" : "imageFile"
+					"type" : "array",
+					"description" : "Image with background of mage guild (each array element for different mage guild level; if one element only this will be always selected)",
+					"minItems" : 1,
+					"items" : { 
+						"type" : "string",
+						"format" : "imageFile"
+					}
+				},
+				"guildWindowPosition" : { 
+					"type" : "array",
+					"items" : {
+						"type" : "object",
+						"additionalProperties" : false,
+						"properties" : {
+							"x" :     { "type" : "number", "description" : "X coordinate on screen" },
+							"y" :     { "type" : "number", "description" : "Y coordinate on screen" }
+						}
+					}
+				},
+				"guildSpellPositions" : {
+					"type" : "array",
+					"description" : "Positions of spells in mage guild",
+					"items" : { 
+						"type" : "array",
+						"items" : { 
+							"type" : "array",
+							"items" : {
+								"type" : "object",
+								"additionalProperties" : false,
+								"properties" : {
+									"x" :     { "type" : "number", "description" : "X coordinate on screen" },
+									"y" :     { "type" : "number", "description" : "Y coordinate on screen" }
+								}
+							}
+						}
+					}
 				},
 				"hallBackground" : {
 					"type" : "string",
@@ -259,7 +297,7 @@
 						"properties" : {
 							"index" : { "type" : "number", "description" : "Order in which images will be opened" },
 							"x" :     { "type" : "number", "description" : "X coordinate on screen" },
-							"y" :     { "type" : "number", "description" : "X coordinate on screen" }
+							"y" :     { "type" : "number", "description" : "Y coordinate on screen" }
 						}
 					}
 				},

+ 17 - 5
docs/modders/Entities_Format/Faction_Format.md

@@ -177,11 +177,11 @@ Each town requires a set of buildings (Around 30-45 buildings)
 	// Background scenery for town screen, size must be 800x374
 	"townBackground": "",
 
-	// Small scenery for window in mage guild screen
-	"guildWindow": "",
+	// Small scenery for window in mage guild screen; each element of array is for seperate mage guild level image (if only one element, then this will always used)
+	"guildWindow": [""],
 
-	// Background image for window in mage guild screen
-	"guildBackground" : "",
+	// Background image for window in mage guild screen; each element of array is for seperate mage guild level image (if only one element, then this will always used)
+	"guildBackground" : [""],
 
 	// Video for tavern window
 	"tavernVideo" : "",
@@ -250,7 +250,19 @@ Each town requires a set of buildings (Around 30-45 buildings)
 	"primaryResource" : "gems", 
 
 	// maximum level of mage guild
-	"mageGuild" : 4,
+	"mageGuild" : 5,
+
+	// Coordinates of spell images in mage guild screen. Should contain the maximum level of mage guild amount of elements. Example are HoMM3 defaults:
+	"guildSpellPositions" : [
+		[ { "x": 222, "y": 445 }, { "x": 312, "y": 445 }, { "x": 402, "y": 445 }, { "x": 520, "y": 445 }, { "x": 610, "y": 445 }, { "x": 700, "y": 445 } ],
+		[ { "x":  48, "y":  53 }, { "x":  48, "y": 147 }, { "x":  48, "y": 241 }, { "x":  48, "y": 335 }, { "x":  48, "y": 429 } ],
+		[ { "x": 570, "y":  82 }, { "x": 672, "y":  82 }, { "x": 570, "y": 157 }, { "x": 672, "y": 157 } ],
+		[ { "x": 183, "y":  42 }, { "x": 183, "y": 148 }, { "x": 183, "y": 253 } ],
+		[ { "x": 491, "y": 325 }, { "x": 591, "y": 325 } ]
+	],
+
+	// Coordinates of window image in mage guild screen. Example is HoMM3 default:
+	"guildWindowPosition": { "x": 332, "y": 76 },
 
 	// Identifier of spell that will create effects for town moat during siege
 	"moatAbility" : "castleMoat"

+ 4 - 2
lib/entities/faction/CTown.h

@@ -89,8 +89,10 @@ public:
 		VideoPath tavernVideo;
 		std::vector<AudioPath> musicTheme;
 		ImagePath townBackground;
-		ImagePath guildBackground;
-		ImagePath guildWindow;
+		std::vector<ImagePath> guildBackground;
+		std::vector<ImagePath> guildWindow;
+		Point guildWindowPosition;
+		std::vector<std::vector<Point>> guildSpellPositions;
 		AnimationPath buildingsIcons;
 		ImagePath hallBackground;
 		/// vector[row][column] = list of buildings in this slot

+ 24 - 13
lib/entities/faction/CTownHandler.cpp

@@ -576,23 +576,34 @@ void CTownHandler::loadClientData(CTown &town, const JsonNode & source) const
 	readIcon(source["icons"]["fort"]["normal"], info.iconSmall[1][0], info.iconLarge[1][0]);
 	readIcon(source["icons"]["fort"]["built"], info.iconSmall[1][1], info.iconLarge[1][1]);
 
-	if (source["musicTheme"].isVector())
-	{
-		for (auto const & entry : source["musicTheme"].Vector())
-			info.musicTheme.push_back(AudioPath::fromJson(entry));
-	}
-	else
-	{
-		info.musicTheme.push_back(AudioPath::fromJson(source["musicTheme"]));
-	}
-
 	info.hallBackground = ImagePath::fromJson(source["hallBackground"]);
 	info.townBackground = ImagePath::fromJson(source["townBackground"]);
-	info.guildWindow = ImagePath::fromJson(source["guildWindow"]);
 	info.buildingsIcons = AnimationPath::fromJson(source["buildingsIcons"]);
-
-	info.guildBackground = ImagePath::fromJson(source["guildBackground"]);
 	info.tavernVideo = VideoPath::fromJson(source["tavernVideo"]);
+	info.guildWindowPosition  = Point(source["guildWindowPosition"]["x"].Integer(), source["guildWindowPosition"]["y"].Integer());
+
+	info.guildSpellPositions.clear();
+	for(auto & level : source["guildSpellPositions"].Vector())
+	{
+		std::vector<Point> points;
+		for(auto & item : level.Vector())
+			points.push_back(Point(item["x"].Integer(), item["y"].Integer()));
+		info.guildSpellPositions.push_back(points);
+	}
+
+	auto loadStringOrVector = [](auto & target, auto & node, auto fromJsonFunc){
+		if(node.isVector())
+		{
+			target.clear();
+			for(auto & background : node.Vector())
+				target.push_back(fromJsonFunc(background));
+		}
+		else
+			target = {fromJsonFunc(node)};
+	};
+	loadStringOrVector(info.musicTheme, source["musicTheme"], AudioPath::fromJson);
+	loadStringOrVector(info.guildBackground, source["guildBackground"], ImagePath::fromJson);
+	loadStringOrVector(info.guildWindow, source["guildWindow"], ImagePath::fromJson);
 
 	loadTownHall(town,   source["hallSlots"]);
 	loadStructures(town, source["structures"]);