Browse Source

- Rewrote Kingdom Overview window - all should be stable now
- New classes for GUI - lists and tabs
- finishing work on Json config in animations

Ivan Savenko 14 years ago
parent
commit
35a528e062

+ 168 - 0
Sprites/PortraitsLarge.json

@@ -0,0 +1,168 @@
+{
+	"images" :
+	[
+		{ "frame" : 0, "file" : "HPL000KN.bmp"},
+		{ "frame" : 1, "file" : "HPL001KN.bmp"},
+		{ "frame" : 2, "file" : "HPL002KN.bmp"},
+		{ "frame" : 3, "file" : "HPL003KN.bmp"},
+		{ "frame" : 4, "file" : "HPL004KN.bmp"},
+		{ "frame" : 5, "file" : "HPL005KN.bmp"},
+		{ "frame" : 6, "file" : "HPL006KN.bmp"},
+		{ "frame" : 7, "file" : "HPL007KN.bmp"},
+		{ "frame" : 8, "file" : "HPL008CL.bmp"},
+		{ "frame" : 9, "file" : "HPL009CL.bmp"},
+		{ "frame" : 10, "file" : "HPL010CL.bmp"},
+		{ "frame" : 11, "file" : "HPL011CL.bmp"},
+		{ "frame" : 12, "file" : "HPL012CL.bmp"},
+		{ "frame" : 13, "file" : "HPL013CL.bmp"},
+		{ "frame" : 14, "file" : "HPL014CL.bmp"},
+		{ "frame" : 15, "file" : "HPL015CL.bmp"},
+		{ "frame" : 16, "file" : "HPL016RN.bmp"},
+		{ "frame" : 17, "file" : "HPL017RN.bmp"},
+		{ "frame" : 18, "file" : "HPL018RN.bmp"},
+		{ "frame" : 19, "file" : "HPL019RN.bmp"},
+		{ "frame" : 20, "file" : "HPL020RN.bmp"},
+		{ "frame" : 21, "file" : "HPL021RN.bmp"},
+		{ "frame" : 22, "file" : "HPL022RN.bmp"},
+		{ "frame" : 23, "file" : "HPL023RN.bmp"},
+		{ "frame" : 24, "file" : "HPL024DR.bmp"},
+		{ "frame" : 25, "file" : "HPL025DR.bmp"},
+		{ "frame" : 26, "file" : "HPL026DR.bmp"},
+		{ "frame" : 27, "file" : "HPL027DR.bmp"},
+		{ "frame" : 28, "file" : "HPL028DR.bmp"},
+		{ "frame" : 29, "file" : "HPL029DR.bmp"},
+		{ "frame" : 30, "file" : "HPL030DR.bmp"},
+		{ "frame" : 31, "file" : "HPL031DR.bmp"},
+		{ "frame" : 32, "file" : "HPL032AL.bmp"},
+		{ "frame" : 33, "file" : "HPL033AL.bmp"},
+		{ "frame" : 34, "file" : "HPL034AL.bmp"},
+		{ "frame" : 35, "file" : "HPL035AL.bmp"},
+		{ "frame" : 36, "file" : "HPL036AL.bmp"},
+		{ "frame" : 37, "file" : "HPL037AL.bmp"},
+		{ "frame" : 38, "file" : "HPL038AL.bmp"},
+		{ "frame" : 39, "file" : "HPL039AL.bmp"},
+		{ "frame" : 40, "file" : "HPL040WZ.bmp"},
+		{ "frame" : 41, "file" : "HPL041WZ.bmp"},
+		{ "frame" : 42, "file" : "HPL042WZ.bmp"},
+		{ "frame" : 43, "file" : "HPL043WZ.bmp"},
+		{ "frame" : 44, "file" : "HPL044WZ.bmp"},
+		{ "frame" : 45, "file" : "HPL045WZ.bmp"},
+		{ "frame" : 46, "file" : "HPL046WZ.bmp"},
+		{ "frame" : 47, "file" : "HPL047WZ.bmp"},
+		{ "frame" : 48, "file" : "HPL048HR.bmp"},
+		{ "frame" : 49, "file" : "HPL049HR.bmp"},
+		{ "frame" : 50, "file" : "HPL050HR.bmp"},
+		{ "frame" : 51, "file" : "HPL051HR.bmp"},
+		{ "frame" : 52, "file" : "HPL052HR.bmp"},
+		{ "frame" : 53, "file" : "HPL053HR.bmp"},
+		{ "frame" : 54, "file" : "HPL054HR.bmp"},
+		{ "frame" : 55, "file" : "HPL055HR.bmp"},
+		{ "frame" : 56, "file" : "HPL056DM.bmp"},
+		{ "frame" : 57, "file" : "HPL057DM.bmp"},
+		{ "frame" : 58, "file" : "HPL058DM.bmp"},
+		{ "frame" : 59, "file" : "HPL059DM.bmp"},
+		{ "frame" : 60, "file" : "HPL060DM.bmp"},
+		{ "frame" : 61, "file" : "HPL061DM.bmp"},
+		{ "frame" : 62, "file" : "HPL062DM.bmp"},
+		{ "frame" : 63, "file" : "HPL063DM.bmp"},
+		{ "frame" : 64, "file" : "HPL064DK.bmp"},
+		{ "frame" : 65, "file" : "HPL065DK.bmp"},
+		{ "frame" : 66, "file" : "HPL066DK.bmp"},
+		{ "frame" : 67, "file" : "HPL067DK.bmp"},
+		{ "frame" : 68, "file" : "HPL068DK.bmp"},
+		{ "frame" : 69, "file" : "HPL069DK.bmp"},
+		{ "frame" : 70, "file" : "HPL070DK.bmp"},
+		{ "frame" : 71, "file" : "HPL071DK.bmp"},
+		{ "frame" : 72, "file" : "HPL072NC.bmp"},
+		{ "frame" : 73, "file" : "HPL073NC.bmp"},
+		{ "frame" : 74, "file" : "HPL074NC.bmp"},
+		{ "frame" : 75, "file" : "HPL075NC.bmp"},
+		{ "frame" : 76, "file" : "HPL076NC.bmp"},
+		{ "frame" : 77, "file" : "HPL077NC.bmp"},
+		{ "frame" : 78, "file" : "HPL078NC.bmp"},
+		{ "frame" : 79, "file" : "HPL079NC.bmp"},
+		{ "frame" : 80, "file" : "HPL080OV.bmp"},
+		{ "frame" : 81, "file" : "HPL081OV.bmp"},
+		{ "frame" : 82, "file" : "HPL082OV.bmp"},
+		{ "frame" : 83, "file" : "HPL083OV.bmp"},
+		{ "frame" : 84, "file" : "HPL084OV.bmp"},
+		{ "frame" : 85, "file" : "HPL085OV.bmp"},
+		{ "frame" : 86, "file" : "HPL086OV.bmp"},
+		{ "frame" : 87, "file" : "HPL087OV.bmp"},
+		{ "frame" : 88, "file" : "HPL088WL.bmp"},
+		{ "frame" : 89, "file" : "HPL089WL.bmp"},
+		{ "frame" : 90, "file" : "HPL090WL.bmp"},
+		{ "frame" : 91, "file" : "HPL091WL.bmp"},
+		{ "frame" : 92, "file" : "HPL092WL.bmp"},
+		{ "frame" : 93, "file" : "HPL093WL.bmp"},
+		{ "frame" : 94, "file" : "HPL094WL.bmp"},
+		{ "frame" : 95, "file" : "HPL095WL.bmp"},
+		{ "frame" : 96, "file" : "HPL096BR.bmp"},
+		{ "frame" : 97, "file" : "HPL097BR.bmp"},
+		{ "frame" : 98, "file" : "HPL098BR.bmp"},
+		{ "frame" : 99, "file" : "HPL099BR.bmp"},
+		{ "frame" : 100, "file" : "HPL100BR.bmp"},
+		{ "frame" : 101, "file" : "HPL101BR.bmp"},
+		{ "frame" : 102, "file" : "HPL102BR.bmp"},
+		{ "frame" : 103, "file" : "HPL103BR.bmp"},
+		{ "frame" : 104, "file" : "HPL104BM.bmp"},
+		{ "frame" : 105, "file" : "HPL105BM.bmp"},
+		{ "frame" : 106, "file" : "HPL106BM.bmp"},
+		{ "frame" : 107, "file" : "HPL107BM.bmp"},
+		{ "frame" : 108, "file" : "HPL108BM.bmp"},
+		{ "frame" : 109, "file" : "HPL109BM.bmp"},
+		{ "frame" : 110, "file" : "HPL110BM.bmp"},
+		{ "frame" : 111, "file" : "HPL111BM.bmp"},
+		{ "frame" : 112, "file" : "HPL112BS.bmp"},
+		{ "frame" : 113, "file" : "HPL113BS.bmp"},
+		{ "frame" : 114, "file" : "HPL114BS.bmp"},
+		{ "frame" : 115, "file" : "HPL115BS.bmp"},
+		{ "frame" : 116, "file" : "HPL116BS.bmp"},
+		{ "frame" : 117, "file" : "HPL117BS.bmp"},
+		{ "frame" : 118, "file" : "HPL118BS.bmp"},
+		{ "frame" : 119, "file" : "HPL119BS.bmp"},
+		{ "frame" : 120, "file" : "HPL120WH.bmp"},
+		{ "frame" : 121, "file" : "HPL121WH.bmp"},
+		{ "frame" : 122, "file" : "HPL122WH.bmp"},
+		{ "frame" : 123, "file" : "HPL123WH.bmp"},
+		{ "frame" : 124, "file" : "HPL124WH.bmp"},
+		{ "frame" : 125, "file" : "HPL125WH.bmp"},
+		{ "frame" : 126, "file" : "HPL126WH.bmp"},
+		{ "frame" : 127, "file" : "HPL127WH.bmp"},
+		{ "frame" : 128, "file" : "HPL000PL.bmp"},
+		{ "frame" : 129, "file" : "HPL001PL.bmp"},
+		{ "frame" : 130, "file" : "HPL002PL.bmp"},
+		{ "frame" : 131, "file" : "HPL003PL.bmp"},
+		{ "frame" : 132, "file" : "HPL004PL.bmp"},
+		{ "frame" : 133, "file" : "HPL005PL.bmp"},
+		{ "frame" : 134, "file" : "HPL006PL.bmp"},
+		{ "frame" : 135, "file" : "HPL007PL.bmp"},
+		{ "frame" : 136, "file" : "HPL000EL.bmp"},
+		{ "frame" : 137, "file" : "HPL001EL.bmp"},
+		{ "frame" : 138, "file" : "HPL002EL.bmp"},
+		{ "frame" : 139, "file" : "HPL003EL.bmp"},
+		{ "frame" : 140, "file" : "HPL004EL.bmp"},
+		{ "frame" : 141, "file" : "HPL005EL.bmp"},
+		{ "frame" : 142, "file" : "HPL006EL.bmp"},
+		{ "frame" : 143, "file" : "HPL007EL.bmp"},
+		{ "frame" : 144, "file" : "HPL130KN.bmp"},
+		{ "frame" : 145, "file" : "HPL000SH.bmp"},
+		{ "frame" : 146, "file" : "HPL128QC.bmp"},
+		{ "frame" : 147, "file" : "HPL003SH.bmp"},
+		{ "frame" : 148, "file" : "HPL004SH.bmp"},
+		{ "frame" : 149, "file" : "HPL005SH.bmp"},
+		{ "frame" : 150, "file" : "HPL006SH.bmp"},
+		{ "frame" : 151, "file" : "HPL007SH.bmp"},
+		{ "frame" : 152, "file" : "HPL009SH.bmp"},
+		{ "frame" : 153, "file" : "HPL008SH.bmp"},
+		{ "frame" : 154, "file" : "HPL001SH.bmp"},
+		{ "frame" : 155, "file" : "HPL131DM.bmp"},
+		{ "frame" : 156, "file" : "HPL129MK.bmp"},
+		{ "frame" : 157, "file" : "HPL002SH.bmp"},
+		{ "frame" : 158, "file" : "HPL132Wl.bmp"},
+		{ "frame" : 159, "file" : "HPL133Nc.bmp"},
+		{ "frame" : 160, "file" : "HPL134Nc.bmp"},
+		{ "frame" : 161, "file" : "HPL135Wi.bmp"},
+		{ "frame" : 162, "file" : "HPL136Wi.bmp"}
+	]
+}

+ 168 - 0
Sprites/PortraitsSmall.json

@@ -0,0 +1,168 @@
+{
+	"images" :
+	[
+		{ "frame" : 0, "file" : "HPS000KN.bmp"},
+		{ "frame" : 1, "file" : "HPS001KN.bmp"},
+		{ "frame" : 2, "file" : "HPS002KN.bmp"},
+		{ "frame" : 3, "file" : "HPS003KN.bmp"},
+		{ "frame" : 4, "file" : "HPS004KN.bmp"},
+		{ "frame" : 5, "file" : "HPS005KN.bmp"},
+		{ "frame" : 6, "file" : "HPS006KN.bmp"},
+		{ "frame" : 7, "file" : "HPS007KN.bmp"},
+		{ "frame" : 8, "file" : "HPS008CL.bmp"},
+		{ "frame" : 9, "file" : "HPS009CL.bmp"},
+		{ "frame" : 10, "file" : "HPS010CL.bmp"},
+		{ "frame" : 11, "file" : "HPS011CL.bmp"},
+		{ "frame" : 12, "file" : "HPS012CL.bmp"},
+		{ "frame" : 13, "file" : "HPS013CL.bmp"},
+		{ "frame" : 14, "file" : "HPS014CL.bmp"},
+		{ "frame" : 15, "file" : "HPS015CL.bmp"},
+		{ "frame" : 16, "file" : "HPS016RN.bmp"},
+		{ "frame" : 17, "file" : "HPS017RN.bmp"},
+		{ "frame" : 18, "file" : "HPS018RN.bmp"},
+		{ "frame" : 19, "file" : "HPS019RN.bmp"},
+		{ "frame" : 20, "file" : "HPS020RN.bmp"},
+		{ "frame" : 21, "file" : "HPS021RN.bmp"},
+		{ "frame" : 22, "file" : "HPS022RN.bmp"},
+		{ "frame" : 23, "file" : "HPS023RN.bmp"},
+		{ "frame" : 24, "file" : "HPS024DR.bmp"},
+		{ "frame" : 25, "file" : "HPS025DR.bmp"},
+		{ "frame" : 26, "file" : "HPS026DR.bmp"},
+		{ "frame" : 27, "file" : "HPS027DR.bmp"},
+		{ "frame" : 28, "file" : "HPS028DR.bmp"},
+		{ "frame" : 29, "file" : "HPS029DR.bmp"},
+		{ "frame" : 30, "file" : "HPS030DR.bmp"},
+		{ "frame" : 31, "file" : "HPS031DR.bmp"},
+		{ "frame" : 32, "file" : "HPS032AL.bmp"},
+		{ "frame" : 33, "file" : "HPS033AL.bmp"},
+		{ "frame" : 34, "file" : "HPS034AL.bmp"},
+		{ "frame" : 35, "file" : "HPS035AL.bmp"},
+		{ "frame" : 36, "file" : "HPS036AL.bmp"},
+		{ "frame" : 37, "file" : "HPS037AL.bmp"},
+		{ "frame" : 38, "file" : "HPS038AL.bmp"},
+		{ "frame" : 39, "file" : "HPS039AL.bmp"},
+		{ "frame" : 40, "file" : "HPS040WZ.bmp"},
+		{ "frame" : 41, "file" : "HPS041WZ.bmp"},
+		{ "frame" : 42, "file" : "HPS042WZ.bmp"},
+		{ "frame" : 43, "file" : "HPS043WZ.bmp"},
+		{ "frame" : 44, "file" : "HPS044WZ.bmp"},
+		{ "frame" : 45, "file" : "HPS045WZ.bmp"},
+		{ "frame" : 46, "file" : "HPS046WZ.bmp"},
+		{ "frame" : 47, "file" : "HPS047WZ.bmp"},
+		{ "frame" : 48, "file" : "HPS048HR.bmp"},
+		{ "frame" : 49, "file" : "HPS049HR.bmp"},
+		{ "frame" : 50, "file" : "HPS050HR.bmp"},
+		{ "frame" : 51, "file" : "HPS051HR.bmp"},
+		{ "frame" : 52, "file" : "HPS052HR.bmp"},
+		{ "frame" : 53, "file" : "HPS053HR.bmp"},
+		{ "frame" : 54, "file" : "HPS054HR.bmp"},
+		{ "frame" : 55, "file" : "HPS055HR.bmp"},
+		{ "frame" : 56, "file" : "HPS056DM.bmp"},
+		{ "frame" : 57, "file" : "HPS057DM.bmp"},
+		{ "frame" : 58, "file" : "HPS058DM.bmp"},
+		{ "frame" : 59, "file" : "HPS059DM.bmp"},
+		{ "frame" : 60, "file" : "HPS060DM.bmp"},
+		{ "frame" : 61, "file" : "HPS061DM.bmp"},
+		{ "frame" : 62, "file" : "HPS062DM.bmp"},
+		{ "frame" : 63, "file" : "HPS063DM.bmp"},
+		{ "frame" : 64, "file" : "HPS064DK.bmp"},
+		{ "frame" : 65, "file" : "HPS065DK.bmp"},
+		{ "frame" : 66, "file" : "HPS066DK.bmp"},
+		{ "frame" : 67, "file" : "HPS067DK.bmp"},
+		{ "frame" : 68, "file" : "HPS068DK.bmp"},
+		{ "frame" : 69, "file" : "HPS069DK.bmp"},
+		{ "frame" : 70, "file" : "HPS070DK.bmp"},
+		{ "frame" : 71, "file" : "HPS071DK.bmp"},
+		{ "frame" : 72, "file" : "HPS072NC.bmp"},
+		{ "frame" : 73, "file" : "HPS073NC.bmp"},
+		{ "frame" : 74, "file" : "HPS074NC.bmp"},
+		{ "frame" : 75, "file" : "HPS075NC.bmp"},
+		{ "frame" : 76, "file" : "HPS076NC.bmp"},
+		{ "frame" : 77, "file" : "HPS077NC.bmp"},
+		{ "frame" : 78, "file" : "HPS078NC.bmp"},
+		{ "frame" : 79, "file" : "HPS079NC.bmp"},
+		{ "frame" : 80, "file" : "HPS080OV.bmp"},
+		{ "frame" : 81, "file" : "HPS081OV.bmp"},
+		{ "frame" : 82, "file" : "HPS082OV.bmp"},
+		{ "frame" : 83, "file" : "HPS083OV.bmp"},
+		{ "frame" : 84, "file" : "HPS084OV.bmp"},
+		{ "frame" : 85, "file" : "HPS085OV.bmp"},
+		{ "frame" : 86, "file" : "HPS086OV.bmp"},
+		{ "frame" : 87, "file" : "HPS087OV.bmp"},
+		{ "frame" : 88, "file" : "HPS088WL.bmp"},
+		{ "frame" : 89, "file" : "HPS089WL.bmp"},
+		{ "frame" : 90, "file" : "HPS090WL.bmp"},
+		{ "frame" : 91, "file" : "HPS091WL.bmp"},
+		{ "frame" : 92, "file" : "HPS092WL.bmp"},
+		{ "frame" : 93, "file" : "HPS093WL.bmp"},
+		{ "frame" : 94, "file" : "HPS094WL.bmp"},
+		{ "frame" : 95, "file" : "HPS095WL.bmp"},
+		{ "frame" : 96, "file" : "HPS096BR.bmp"},
+		{ "frame" : 97, "file" : "HPS097BR.bmp"},
+		{ "frame" : 98, "file" : "HPS098BR.bmp"},
+		{ "frame" : 99, "file" : "HPS099BR.bmp"},
+		{ "frame" : 100, "file" : "HPS100BR.bmp"},
+		{ "frame" : 101, "file" : "HPS101BR.bmp"},
+		{ "frame" : 102, "file" : "HPS102BR.bmp"},
+		{ "frame" : 103, "file" : "HPS103BR.bmp"},
+		{ "frame" : 104, "file" : "HPS104BM.bmp"},
+		{ "frame" : 105, "file" : "HPS105BM.bmp"},
+		{ "frame" : 106, "file" : "HPS106BM.bmp"},
+		{ "frame" : 107, "file" : "HPS107BM.bmp"},
+		{ "frame" : 108, "file" : "HPS108BM.bmp"},
+		{ "frame" : 109, "file" : "HPS109BM.bmp"},
+		{ "frame" : 110, "file" : "HPS110BM.bmp"},
+		{ "frame" : 111, "file" : "HPS111BM.bmp"},
+		{ "frame" : 112, "file" : "HPS112BS.bmp"},
+		{ "frame" : 113, "file" : "HPS113BS.bmp"},
+		{ "frame" : 114, "file" : "HPS114BS.bmp"},
+		{ "frame" : 115, "file" : "HPS115BS.bmp"},
+		{ "frame" : 116, "file" : "HPS116BS.bmp"},
+		{ "frame" : 117, "file" : "HPS117BS.bmp"},
+		{ "frame" : 118, "file" : "HPS118BS.bmp"},
+		{ "frame" : 119, "file" : "HPS119BS.bmp"},
+		{ "frame" : 120, "file" : "HPS120WH.bmp"},
+		{ "frame" : 121, "file" : "HPS121WH.bmp"},
+		{ "frame" : 122, "file" : "HPS122WH.bmp"},
+		{ "frame" : 123, "file" : "HPS123WH.bmp"},
+		{ "frame" : 124, "file" : "HPS124WH.bmp"},
+		{ "frame" : 125, "file" : "HPS125WH.bmp"},
+		{ "frame" : 126, "file" : "HPS126WH.bmp"},
+		{ "frame" : 127, "file" : "HPS127WH.bmp"},
+		{ "frame" : 128, "file" : "HPS000PL.bmp"},
+		{ "frame" : 129, "file" : "HPS001PL.bmp"},
+		{ "frame" : 130, "file" : "HPS002PL.bmp"},
+		{ "frame" : 131, "file" : "HPS003PL.bmp"},
+		{ "frame" : 132, "file" : "HPS004PL.bmp"},
+		{ "frame" : 133, "file" : "HPS005PL.bmp"},
+		{ "frame" : 134, "file" : "HPS006PL.bmp"},
+		{ "frame" : 135, "file" : "HPS007PL.bmp"},
+		{ "frame" : 136, "file" : "HPS000EL.bmp"},
+		{ "frame" : 137, "file" : "HPS001EL.bmp"},
+		{ "frame" : 138, "file" : "HPS002EL.bmp"},
+		{ "frame" : 139, "file" : "HPS003EL.bmp"},
+		{ "frame" : 140, "file" : "HPS004EL.bmp"},
+		{ "frame" : 141, "file" : "HPS005EL.bmp"},
+		{ "frame" : 142, "file" : "HPS006EL.bmp"},
+		{ "frame" : 143, "file" : "HPS007EL.bmp"},
+		{ "frame" : 144, "file" : "HPS130KN.bmp"},
+		{ "frame" : 145, "file" : "HPS000SH.bmp"},
+		{ "frame" : 146, "file" : "HPS128QC.bmp"},
+		{ "frame" : 147, "file" : "HPS003SH.bmp"},
+		{ "frame" : 148, "file" : "HPS004SH.bmp"},
+		{ "frame" : 149, "file" : "HPS005SH.bmp"},
+		{ "frame" : 150, "file" : "HPS006SH.bmp"},
+		{ "frame" : 151, "file" : "HPS007SH.bmp"},
+		{ "frame" : 152, "file" : "HPS009SH.bmp"},
+		{ "frame" : 153, "file" : "HPS008SH.bmp"},
+		{ "frame" : 154, "file" : "HPS001SH.bmp"},
+		{ "frame" : 155, "file" : "HPS131DM.bmp"},
+		{ "frame" : 156, "file" : "HPS129MK.bmp"},
+		{ "frame" : 157, "file" : "HPS002SH.bmp"},
+		{ "frame" : 158, "file" : "HPS132Wl.bmp"},
+		{ "frame" : 159, "file" : "HPS133Nc.bmp"},
+		{ "frame" : 160, "file" : "HPS134Nc.bmp"},
+		{ "frame" : 161, "file" : "HPS135Wi.bmp"},
+		{ "frame" : 162, "file" : "HPS136Wi.bmp"}
+	]
+}

+ 36 - 14
client/CAnimation.cpp

@@ -945,31 +945,53 @@ void CAnimation::init(CDefFile * file)
 	if (spriteh->haveFile(name, FILE_TEXT))
 	{
 		std::string configFile = spriteh->getTextFile(name);
-		const JsonNode &config(configFile);
 
-		JsonMap::const_iterator rootEntry = config.Struct().find("sequences");
-		if (rootEntry != config.Struct().end())
+		const JsonNode config(configFile);
+
+		std::string basepath;
+		if (!config["basepath"].isNull())
+			basepath = config["basepath"].String();
+
+		if (!config["sequences"].isNull())
 		{
-			//TODO: Process sequences group
+			const JsonVector &groups = config["sequences"].Vector();
+			for (JsonVector::const_iterator groupsIter = groups.begin(); groupsIter!=groups.end(); ++groupsIter)
+			{
+				JsonNode group = *groupsIter;
+				size_t groupID = group["group"].Float();//TODO: string-to-value conversion
+				source[groupID].clear();
+
+				const JsonVector &frames = group["frames"].Vector();
+				for (JsonVector::const_iterator framesIter = frames.begin(); framesIter!=frames.end(); ++framesIter)
+				{
+					const JsonNode &frame = *framesIter;
+					source[groupID].push_back(frame);
+					std::string filename =  frame["file"].String();
+					source[groupID].back()["file"].String() = basepath + filename;
+				}
+			}
 		}
-		
-		rootEntry = config.Struct().find("images");
-		if (rootEntry != config.Struct().end())
+
+		if (!config["images"].isNull())
 		{
-			JsonVector vector = rootEntry->second.Vector();
+			const JsonVector &vector = config["images"].Vector();
 			
 			for (JsonVector::const_iterator it = vector.begin(); it!=vector.end(); ++it)
 			{
-				JsonMap::const_iterator entry = it->Struct().find("group");
+				const JsonNode &node = *it;
 
 				size_t group=0;
-				if (entry != it->Struct().end())
-					group = entry->second.Float();
+				if (!node["group"].isNull())
+					group = node["group"].Float();
+
+				size_t frame = node["frame"].Float();
 
-				size_t frame = it->Struct().find("frame")->second.Float();
 				if (source[group].size() <= frame)
 					source[group].resize(frame+1);
-				source[group][frame] = *it;
+
+				source[group][frame] = node;
+				std::string filename =  node["file"].String();
+				source[group][frame]["file"].String() = basepath + filename;
 			}
 		}
 	}
@@ -1026,7 +1048,7 @@ void CAnimation::setCustom(std::string filename, size_t frame, size_t group)
 {
 	if (source[group].size() <= frame)
 		source[group].resize(frame+1);
-	source[group][frame] = filename;
+	source[group][frame]["file"].String() = filename;
 	//FIXME: update image if already loaded
 }
 

+ 982 - 829
client/CKingdomInterface.cpp

@@ -1,39 +1,22 @@
 #include "CKingdomInterface.h"
-#include "AdventureMapButton.h"
-#include "CAdvmapInterface.h"
-#include "CPlayerInterface.h"
-#include "CCreatureWindow.h"
-#include "../CCallback.h"
-#include "../global.h"
-#include "CConfigHandler.h"
-#include "CGameInfo.h"
-#include "CHeroWindow.h"
-#include "CSpellWindow.h"
-#include "CMessage.h"
-#include "SDL_Extensions.h"
-#include "Graphics.h"
-#include "../lib/CArtHandler.h"
-#include "../lib/CBuildingHandler.h"
-#include "CDefHandler.h"
-#include "../lib/CHeroHandler.h"
-#include "../lib/CGeneralTextHandler.h"
-#include "../lib/CObjectHandler.h"
-#include "../lib/CTownHandler.h"
-#include "../lib/CCreatureHandler.h"
-#include "../lib/CHeroHandler.h"
-#include "../lib/map.h"
-#include "../lib/NetPacks.h"
+
 #include <boost/algorithm/string/replace.hpp>
-#include <boost/assign/std/vector.hpp> 
-#include <boost/assign/list_of.hpp>
+#include <boost/bind.hpp>
 #include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
 #include <boost/format.hpp>
-#include <sstream>
-#include <SDL.h>
-#include "CBitmapHandler.h"
 
-using namespace boost::assign;
-using namespace CSDL_Ext;
+#include "../CCallback.h"
+#include "../lib/CCreatureHandler.h" //creatures name for objects list
+#include "../lib/CGeneralTextHandler.h"
+#include "../lib/CObjectHandler.h" //Hero/Town objects
+#include "AdventureMapButton.h"
+#include "CAnimation.h" //CAnimImage
+#include "CAdvmapInterface.h" //CResDataBar
+#include "CCastleInterface.h" //various town-specific classes
+#include "CConfigHandler.h"
+#include "CGameInfo.h"
+#include "CPlayerInterface.h" //LOCPLINT
 
 /*
  * CKingdomInterface.cpp, part of VCMI engine
@@ -45,1021 +28,1191 @@ using namespace CSDL_Ext;
  *
  */
 
-#define ADVOPT (conf.go()->ac)
+extern SDL_Surface *screenBuf;
 
-CKingdomInterface::CKingdomInterface()
+InfoBox::InfoBox(Point position, InfoPos Pos, InfoSize Size, IInfoBoxData *Data):
+	size(Size),
+	infoPos(Pos),
+	data(Data),
+	value(NULL),
+	name(NULL)
 {
+	assert(data);
+	used = LCLICK | RCLICK;
+	EFonts font = (size < SIZE_MEDIUM)? FONT_SMALL: FONT_MEDIUM;
+
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	defActions = SHARE_POS | DISPOSE;
-	PicCount = ADVOPT.overviewPics;
-	size =     ADVOPT.overviewSize;
-	pos.x = screen->w/2 - 400;
-	pos.y = screen->h/2 - (68+58*size);
-	showHarrisoned = false;//set to true if you want to see garrisoned heroes
-	heroPos = townPos = objPos = state = 0;
-
-	bg = BitmapHandler::loadBitmap(ADVOPT.overviewBg);
-	graphics->blueToPlayersAdv(bg, LOCPLINT->playerID);
-
-	mines   = CDefHandler::giveDefEss("OVMINES.DEF");
-	title   = CDefHandler::giveDefEss("OVTITLE.DEF");
-	hall    = CDefHandler::giveDefEss("ITMTL.DEF");
-	fort    = CDefHandler::giveDefEss("ITMCL.DEF");
-	objPics = CDefHandler::giveDefEss("FLAGPORT.DEF");
-	slots   = CDefHandler::giveDefEss("OVSLOT.DEF");
-
-	toHeroes = new AdventureMapButton (CGI->generaltexth->overview[11],"",
-		boost::bind(&CKingdomInterface::listToHeroes,this),748,28+size*116,"OVBUTN1.DEF", SDLK_h);
-	toHeroes->block(2);
-
-	toTowns = new AdventureMapButton (CGI->generaltexth->overview[12],"",
-		boost::bind(&CKingdomInterface::listToTowns,this),748,64+size*116,"OVBUTN6.DEF", SDLK_t);
-	toTowns->block(0);
-
-	exit = new AdventureMapButton (CGI->generaltexth->allTexts[600],"",
-		boost::bind(&CKingdomInterface::close,this),748,99+size*116,"OVBUTN1.DEF", SDLK_RETURN);
-	exit->setOffset(3);
-
-	statusbar = new CStatusBar(7, 91+size*116,"TSTATBAR.bmp",732);
-	resdatabar = new CResDataBar("KRESBAR.bmp",pos.x+3,pos.y+111+size*116,32,2,76,76);
-
-	for(size_t i=0;i<size;i++)//creating empty hero/town lists for input
-	{
-		heroes.push_back( new CHeroItem(i,this));
-		 towns.push_back( new CTownItem(i,this));
-	}
+	pos+=position;
 
-	slider = new CSlider(4, 4, size*116+19, boost::bind (&CKingdomInterface::sliderMoved, this, _1),
-		size, LOCPLINT->cb->howManyHeroes(showHarrisoned), 0, false, 0);
+	image = new CAnimImage(data->getImageName(size), data->getImageIndex());
+	pos = image->pos;
 
-	//creating objects list
-	ObjTop = new AdventureMapButton ("","", boost::bind(&CKingdomInterface::moveObjectList,this,0),
-		733,4,"OVBUTN4.DEF");
+	if (infoPos == POS_CORNER)
+		value = new CLabel(pos.w, pos.h, font, BOTTOMRIGHT, zwykly, data->getValueText());
 
-	ObjUp = new AdventureMapButton ("","", boost::bind(&CKingdomInterface::moveObjectList,this,1),
-		733,24,"OVBUTN4.DEF");
-	ObjUp->setOffset(4);
+	if (infoPos == POS_INSIDE)
+		value = new CLabel(pos.w/2, pos.h-6, font, CENTER, zwykly, data->getValueText());
 
-	ObjDown = new AdventureMapButton ("","", boost::bind(&CKingdomInterface::moveObjectList,this,2),
-		733,size*116-18,"OVBUTN4.DEF");
-	ObjDown->setOffset(6);
+	if (infoPos == POS_UP_DOWN || infoPos == POS_DOWN)
+		value = new CLabel(pos.w/2, pos.h+8, font, CENTER, zwykly, data->getValueText());
 
-	ObjBottom = new AdventureMapButton ("","", boost::bind(&CKingdomInterface::moveObjectList,this,3),
-		733,size*116+2,"OVBUTN4.DEF");
-	ObjBottom->setOffset(2);
+	if (infoPos == POS_UP_DOWN)
+		name = new CLabel(pos.w/2, -12, font, CENTER, zwykly, data->getNameText());
 
-	for (size_t i=0; i<8; i++)
+	if (infoPos == POS_RIGHT)
 	{
-		incomes.push_back(new HoverableArea());//bottom panel with mines
-		incomes[i]->pos = genRect(57,68,pos.x+20+i*80,pos.y+31+size*116);
-		incomes[i]->hoverText = CGI->generaltexth->mines[i].first;
-	}
-	incomes[7]->pos.w = 136;
-	incomes[7]->hoverText = CGI->generaltexth->allTexts[255];
-	incomesVal+=0,0,0,0,0,0,0,0;//for mines images
-
-	std::map<std::pair<int,int>,int> addObjects;//objects to print, except 17th dwelling
-	//format: (id,subID),image index
-	#define INSERT_MAP addObjects.insert(std::pair<std::pair<int,int>,int>(std::pair<int,int>
-	INSERT_MAP (20,1) ,81));//Golem factory
-	INSERT_MAP (42,0) ,82));//Lighthouse
-	INSERT_MAP (33,0) ,83));//Garrison
-	INSERT_MAP (219,0),83));//Garrison
-	INSERT_MAP (33,1) ,84));//Anti-magic Garrison
-	INSERT_MAP (219,1),84));//Anti-magic Garrison
-	INSERT_MAP (53,7) ,85));//Abandoned mine
-	INSERT_MAP (20,0) ,86));//Conflux
-	INSERT_MAP (87,0) ,87));//Harbor
-	#undef INSERT_MAP
-
-	std::vector<const CGObjectInstance * > myObjects = LOCPLINT->cb->getMyObjects();
-	for(size_t i = 0; i<myObjects.size(); i++)//getting mines and dwelling (in one pass to make it faster)
-	{
-		const CGObjectInstance* obj = myObjects[i];//current object
-		if (obj)
-		{
-			std::pair<int,int > curElm = std::pair<int,int >(obj->ID, obj->subID);
-			if ( obj->ID == 17 )//dwelling, text is a plural name of a creature
-			{
-				objList[obj->subID].first += 1;
-				objList[obj->subID].second = & CGI->creh->creatures[CGI->objh->cregens[obj->subID]]->namePl;
-			}
-			else if (addObjects.find(curElm) != addObjects.end())
-			{//object from addObjects map, text is name of the object
-				objList[addObjects[curElm]].first += 1;
-				objList[addObjects[curElm]].second = & obj->hoverName;
-			}
-			else if ( obj->ID == 53 )
-				incomesVal[obj->subID]+=1;
-		}
+		name = new CLabel(pos.w+6, 6, font, TOPLEFT, zwykly, data->getNameText());
+		value = new CLabel(pos.w+6, pos.h-16, font, TOPLEFT, zwykly, data->getValueText());
 	}
+	pos = image->pos;
+	if (name)
+		pos = pos | name->pos;
+	if (value)
+		pos = pos | value->pos;
+	
+	hover = new HoverableArea;
+	hover->hoverText = data->getHoverText();
+	hover->pos = pos;
+}
 
-	addObjects.clear();
-	objSize = (size*116-64)/57; //in object list will fit (height of panel)/(height of one element) items
-	ObjList.resize(objSize);
-	for(size_t i=0;i<objSize;i++)
-	{
-		ObjList[i] = new HoverableArea();
-		ObjList[i]->pos = genRect(50,50,pos.x+740,pos.y+44+i*57);
-	}
+InfoBox::~InfoBox()
+{
+	delete data;
+}
 
-	incomesVal[7] = incomesVal[6]*1000;//gold mines -> total income
-	std::vector<const CGHeroInstance*> heroes = LOCPLINT->cb->getHeroesInfo(true);
-	for(size_t i=0; i<heroes.size();i++)
-	{	//TODO: what about artifacts generating resources?
-			incomesVal[7] += heroes[i]->valOfBonuses(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, CGHeroInstance::ESTATES));
-			incomesVal[7] += heroes[i]->valOfBonuses(Selector::typeSubtype(Bonus::GENERATE_RESOURCE, Res::GOLD));
+void InfoBox::clickRight(tribool down, bool previousState)
+{
+	if (down)
+	{
+		SComponent *comp;
+		std::string text;
+		data->prepareMessage(text, &comp);
+		if (comp)
+			CRClickPopup::createAndPush(text, CInfoWindow::TCompsInfo(1, comp));
+		else
+			adventureInt->handleRightClick(text, down);
 	}
-	std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo(true);
-	for(size_t i=0; i<towns.size();i++)
-		incomesVal[7] += towns[i]->dailyIncome();
 }
 
-void CKingdomInterface::moveObjectList(int newPos)
+void InfoBox::clickLeft(tribool down, bool previousState)
 {
-	int top =    objList.size() > objSize ? 0 : objList.size() - objSize ;
-	int bottom = objList.size() > objSize ? objList.size() - objSize : 0 ;
-	switch (newPos)//checking what button was pressed
+	if((!down) && previousState)
 	{
-/*  Top */	case 0: objPos = top;
-			break;
-/*  Up  */	case 1: objPos = objPos==top?top:(objPos-1);
-			break;
-/* Down */	case 2: objPos = objPos==bottom?bottom:(objPos+1);
-			break;
-/*Bottom*/	case 3: objPos = bottom;
-			break;
+		SComponent *comp;
+		std::string text;
+		data->prepareMessage(text, &comp);
+
+		std::vector<SComponent*> compVector;
+		if (comp)
+			compVector.push_back(comp);
+		LOCPLINT->showInfoDialog(text, compVector);
 	}
-	showAll(screen2);
 }
 
-CKingdomInterface::~CKingdomInterface()
+//TODO?
+/*
+void InfoBox::update()
 {
-	SDL_FreeSurface(bg);
 
-	delete title;//deleting .def
-	delete slots;
-	delete fort;
-	delete hall;
-	delete objPics;
-	delete mines;
+}
+*/
 
-	towns.clear();//deleting lists
-	heroes.clear();
-	incomes.clear();
-	ObjList.clear();
-	objList.clear();
+IInfoBoxData::IInfoBoxData(InfoType Type):
+	type(Type)
+{
 }
 
-void CKingdomInterface::close()
+InfoBoxAbstractHeroData::InfoBoxAbstractHeroData(InfoType Type):
+	IInfoBoxData(Type)
 {
-	GH.popIntTotally(this);
 }
 
-void CKingdomInterface::updateGarrisons()
+std::string InfoBoxAbstractHeroData::getValueText()
 {
-	for (int i = 0; i<towns.size(); i++)
-	{
-		if (towns[i] && towns[i]->garr)
-			towns[i]->garr->recreateSlots();
-	}
-	for (int i = 0; i<heroes.size(); i++)
+	switch (type)
 	{
-		if (heroes[i] && heroes[i]->garr)
-			heroes[i]->garr->recreateSlots();
+	case HERO_MANA:
+	case HERO_EXPERIENCE:
+	case HERO_PRIMARY_SKILL:
+		return boost::lexical_cast<std::string>(getValue());
+	case HERO_SPECIAL:
+		{
+			std::string text = CGI->generaltexth->jktexts[5];
+			size_t begin = text.find('{');
+			size_t end   = text.find('}', begin);
+			return text.substr(begin, end-begin);
+		}
+	case HERO_SECONDARY_SKILL:
+		{
+			si64 value = getValue();
+			if (value)
+				return CGI->generaltexth->levels[value];
+		}
+	default:
+		assert(0);
 	}
+	return "";
 }
 
-void CKingdomInterface::showAll( SDL_Surface * to/*=NULL*/)
+std::string InfoBoxAbstractHeroData::getNameText()
 {
-	adventureInt->resdatabar.draw(to);
-	blitAt(bg,pos,to);
-	resdatabar->draw(to);
-	toTowns->showAll(to);
-	toHeroes->showAll(to);
-	exit->showAll(to);
-
-	ObjTop->showAll(to);
-	ObjUp->showAll(to);
-	ObjDown->showAll(to);
-	ObjBottom->showAll(to);
-
-	for (size_t i=0; i<ObjList.size(); i++)//list may be moved, recreate hover text
-		ObjList[i]->hoverText = "";
-
-	int skipCount=0, curPos=objPos<0?(-objPos):0;
-	for (std::map<int,std::pair<int, const std::string*> >::iterator it=objList.begin(); it!= objList.end(); it++)
+	switch (type)
 	{
-		if (skipCount<objPos)//we will show only objects from objPos
+	case HERO_PRIMARY_SKILL:
+		return CGI->generaltexth->primarySkillNames[getSubID()];
+	case HERO_MANA:
+		return CGI->generaltexth->allTexts[387];
+	case HERO_EXPERIENCE:
 		{
-			skipCount++;
-			continue;
+			std::string text = CGI->generaltexth->jktexts[6];
+			size_t begin = text.find('{');
+			size_t end   = text.find('}', begin);
+			return text.substr(begin, end-begin);
 		}
-		blitAt(objPics->ourImages[(*it).first].bitmap,pos.x+740,pos.y+44+curPos*57,to);
-
-		std::ostringstream ostrs;//objects count
-		ostrs << (*it).second.first;
-		CSDL_Ext::printTo(ostrs.str(),pos.x+790,pos.y+94+curPos*57,FONT_SMALL,zwykly,to);
-
-		ObjList[curPos]->hoverText = * (*it).second.second;
-		curPos++;
-		if (curPos == objSize)
-			break;
-	}
-
-	if (state == 1)
-	{//printing text "Town", "Harrisoned hero", "Visiting hero"
-		CSDL_Ext::printAtMiddle(CGI->generaltexth->overview[3],pos.x+144,pos.y+14,FONT_MEDIUM,zwykly,to);
-		CSDL_Ext::printAtMiddle(CGI->generaltexth->overview[4],pos.x+373,pos.y+14,FONT_MEDIUM,zwykly,to);
-		CSDL_Ext::printAtMiddle(CGI->generaltexth->overview[5],pos.x+606,pos.y+14,FONT_MEDIUM,zwykly,to);
-		for (size_t i=0; i<size; i++)
-			towns[i]->showAll(to);//show town list
-	}
-	else
-	{//text "Hero/stats" and "Skills"
-		CSDL_Ext::printAtMiddle(CGI->generaltexth->overview[0],pos.x+150,pos.y+14,FONT_MEDIUM,zwykly,to);
-		CSDL_Ext::printAtMiddle(CGI->generaltexth->overview[1],pos.x+500,pos.y+14,FONT_MEDIUM,zwykly,to);
-		for (size_t i=0; i<size; i++)
-			heroes[i]->showAll(to);//show hero list
+	case HERO_SPECIAL:
+		return CGI->generaltexth->hTxts[getSubID()].bonusName;
+	case HERO_SECONDARY_SKILL:
+		if (getValue())
+			return CGI->generaltexth->skillName[getSubID()];
+		else
+			return "";
+	default:
+		assert(0);
 	}
-	for (int i = 0; i<7; i++)
-		blitAt(mines->ourImages[i].bitmap,pos.x + 20 + i*80,pos.y + 31+size*116,to);
+	return "";
+}
 
-	for(size_t i=0;i<incomes.size();i++)
+std::string InfoBoxAbstractHeroData::getImageName(InfoBox::InfoSize size)
+{
+	//TODO: sizes
+	switch(size)
 	{
-		std::ostringstream oss;
-		oss << incomesVal[i];
-		CSDL_Ext::printAtMiddle(oss.str(),incomes[i]->pos.x+incomes[i]->pos.w/2,incomes[i]->pos.y+50,FONT_SMALL,zwykly,to);
+	case InfoBox::SIZE_SMALL:
+		{
+			switch(type)
+			{
+			case HERO_PRIMARY_SKILL:
+			case HERO_MANA:
+			case HERO_EXPERIENCE:
+				return "PSKIL32";
+			case HERO_SPECIAL:
+				return "UN32";
+			case HERO_SECONDARY_SKILL:
+				return "SECSK32";
+			default:
+				assert(0);
+			}
+		}
+	case InfoBox::SIZE_BIG:
+		{
+			switch(type)
+			{
+			case HERO_PRIMARY_SKILL:
+			case HERO_MANA:
+			case HERO_EXPERIENCE:
+				return "PSKIL42";
+			case HERO_SPECIAL:
+				return "UN44";
+			case HERO_SECONDARY_SKILL:
+				return "SECSKILL";
+			default:
+				assert(0);
+			}
+		}
+	default:
+		assert(0);
 	}
-
-	slider->showAll(to);
-	if(screen->w != 800 || screen->h !=600)
-		CMessage::drawBorder(LOCPLINT->playerID,to,828,136+116*size+29,pos.x-14,pos.y-15);
-	show(to);
+	return "";
 }
 
-void CKingdomInterface::show(SDL_Surface * to)
+std::string InfoBoxAbstractHeroData::getHoverText()
 {
-	statusbar->show(to);
+	//TODO: any texts here?
+	return "";
 }
 
-void CKingdomInterface::activate()
+size_t InfoBoxAbstractHeroData::getImageIndex()
 {
-	GH.statusbar = statusbar;
-	exit->activate();
-	toTowns->activate();
-	toHeroes->activate();
-
-	ObjTop->activate();
-	ObjUp->activate();
-	ObjDown->activate();
-	ObjBottom->activate();
-
-	for (size_t i=0; i<ObjList.size(); i++)
-		ObjList[i]->activate();
-
-	for (size_t i=0; i<incomes.size(); i++)
-		incomes[i]->activate();
-	if (state == 1)
-		for (size_t i=0; i<size; i++)
-			towns[i]->activate();
-	else
-		for (size_t i=0; i<size; i++)
-			heroes[i]->activate();
-
-	slider->activate();
+	switch (type)
+	{
+	case HERO_SPECIAL:
+	case HERO_PRIMARY_SKILL:
+		return getSubID();
+	case HERO_MANA:
+		return 5;
+	case HERO_EXPERIENCE:
+		return 4;
+	case HERO_SECONDARY_SKILL:
+		{
+			si64 value = getValue();
+			if (value)
+				return getSubID()*3 + value + 2;
+			else
+				return 0;//FIXME: Should be transparent instead of empty
+		}
+	default:
+		assert(0);
+		return 0;
+	}
 }
 
-void CKingdomInterface::deactivate()
+bool InfoBoxAbstractHeroData::prepareMessage(std::string &text, SComponent **comp)
 {
-	exit->deactivate();
-	toTowns->deactivate();
-	toHeroes->deactivate();
-
-	ObjTop->deactivate();
-	ObjUp->deactivate();
-	ObjDown->deactivate();
-	ObjBottom->deactivate();
-
-	for (size_t i=0; i<ObjList.size(); i++)
-		ObjList[i]->deactivate();
-
-	for (size_t i=0; i<incomes.size(); i++)
-		incomes[i]->deactivate();
+	switch (type)
+	{
+	case HERO_SPECIAL:
+		text = CGI->generaltexth->hTxts[getSubID()].longBonus;
+		*comp = NULL;
+		return true;
+	case HERO_PRIMARY_SKILL:
+		text = CGI->generaltexth->arraytxt[2+getSubID()];
+		*comp =new SComponent(SComponent::primskill, getSubID(), getValue());
+		return true;
+	case HERO_MANA:
+		text = CGI->generaltexth->allTexts[149];
+		*comp = NULL;
+		return true;
+	case HERO_EXPERIENCE:
+		text = CGI->generaltexth->allTexts[241];
+		*comp = NULL;
+		return true;
+	case HERO_SECONDARY_SKILL:
+		{
+			si64 value = getValue();
+			int  subID = getSubID();
+			if (!value)
+				return false;
+
+			text = CGI->generaltexth->skillInfoTexts[subID][value-1];
+			*comp = new SComponent(SComponent::secskill, subID, value);
+			return true;
+		}
+	default:
+		assert(0);
+		return false;
+	}
+}
 
-	if (state == 1)
-		for (size_t i=0; i<size; i++)
-			towns[i]->deactivate();
-	else
-		for (size_t i=0; i<size; i++)
-			heroes[i]->deactivate();
-	slider->deactivate();
+InfoBoxHeroData::InfoBoxHeroData(InfoType Type, const CGHeroInstance * Hero, int Index):
+	InfoBoxAbstractHeroData(Type),
+	hero(Hero),
+	index(Index)
+{
 }
 
-void CKingdomInterface::recreateHeroList(int pos)
+int InfoBoxHeroData::getSubID()
 {
-	std::vector<const CGHeroInstance*> Heroes = LOCPLINT->cb->getHeroesInfo(true);
-	int i=0, cnt=0;
-	for (size_t j = 0; ((j<Heroes.size()) && (i<size));j++)
+	switch(type)
 	{
-		if (Heroes[j]->inTownGarrison && (!showHarrisoned))//if hero in garrison and we don't show them
-			continue;
-		if (cnt<pos)//skipping heroes
-		{
-			cnt++;
-			continue;
-		}//this hero will be added
-		heroes[i]->setHero(Heroes[j]);
-		i++;
+		case HERO_PRIMARY_SKILL:
+			return index;
+		case HERO_SECONDARY_SKILL:
+			if (hero->secSkills.size() > index)
+				return hero->secSkills[index].first;
+		case HERO_MANA:
+		case HERO_EXPERIENCE:
+		case HERO_SPECIAL:
+			return 0;
+		default:
+			assert(0);
+			return 0;
 	}
-	for (;i<size;i++)//if we still have empty pieces
-		heroes[i]->setHero(NULL);//empty pic
 }
 
-void CKingdomInterface::recreateTownList(int pos)
+si64 InfoBoxHeroData::getValue()
 {
-	std::vector<const CGTownInstance*> Towns = LOCPLINT->cb->getTownsInfo(false);
-	for(size_t i=0;i<size;i++)
+	switch(type)
 	{
-		if (i+pos<LOCPLINT->cb->howManyTowns())
-			towns[i]->setTown(Towns[i+pos]);//replace town
-		else
-			towns[i]->setTown(NULL);//only empty pic
+	case HERO_PRIMARY_SKILL:
+		return hero->getPrimSkillLevel(index);
+	case HERO_MANA:
+		return hero->mana;
+	case HERO_EXPERIENCE:
+		return hero->exp;
+	case HERO_SECONDARY_SKILL:
+		if (hero->secSkills.size() > index)
+			return hero->secSkills[index].second;
+	case HERO_SPECIAL:
+			return 0;
+	default:
+		assert(0);
+		return 0;
 	}
 }
 
-void CKingdomInterface::listToTowns()
+std::string InfoBoxHeroData::getHoverText()
 {
-	state = 1;
-	toHeroes->block(0);
-	toTowns->block(2);
-	heroPos = slider->value;
-	slider->setAmount(LOCPLINT->cb->howManyTowns());
-	slider->value=townPos;//moving slider
-	recreateTownList(townPos);
-	for (size_t i=0;i<size;i++)
+	switch (type)
 	{
-		heroes[i]->deactivate();
-		towns[i]->activate();
+	case HERO_PRIMARY_SKILL:
+		return boost::str(boost::format(CGI->generaltexth->heroscrn[1]) % CGI->generaltexth->primarySkillNames[index]);
+	case HERO_MANA:
+		return CGI->generaltexth->heroscrn[22];
+	case HERO_EXPERIENCE:
+		return CGI->generaltexth->heroscrn[9];
+	case HERO_SPECIAL:
+		return CGI->generaltexth->heroscrn[27];
+	case HERO_SECONDARY_SKILL:
+		{
+		if (hero->secSkills.size() > index)
+		{
+			std::string level = CGI->generaltexth->levels[hero->secSkills[index].second-1];
+			std::string skill = CGI->generaltexth->skillName[hero->secSkills[index].first];
+			return boost::str(boost::format(CGI->generaltexth->heroscrn[21]) % level % skill);
+		}
+		else
+			return "";
+		}
+	default:
+		return InfoBoxAbstractHeroData::getHoverText();
 	}
-	showAll(screen2);
 }
 
-void CKingdomInterface::listToHeroes()
+std::string InfoBoxHeroData::getValueText()
 {
-	state = 2;
-	toHeroes->block(2);
-	toTowns->block(0);
-	townPos = slider->value;
-	slider->setAmount(LOCPLINT->cb->howManyHeroes(showHarrisoned));
-	slider->value=heroPos;//moving slider
-	recreateHeroList(heroPos);
-	for (size_t i=0;i<size;i++)
+	switch (type)
 	{
-		towns[i]->deactivate();
-		heroes[i]->activate();
+	case HERO_MANA:
+		if (hero)
+			return boost::lexical_cast<std::string>(hero->mana) + '/' +
+			       boost::lexical_cast<std::string>(hero->manaLimit());
+	case HERO_EXPERIENCE:
+		return boost::lexical_cast<std::string>(hero->exp);
+	default:
+		return InfoBoxAbstractHeroData::getValueText();
 	}
-	showAll(screen2);
 }
 
-void CKingdomInterface::sliderMoved(int newpos)
+bool InfoBoxHeroData::prepareMessage(std::string &text, SComponent**comp)
 {
-	if (state == 0)
+	switch(type)
 	{
-		townPos = newpos;
-		recreateHeroList(newpos);
-		state = 2;
-	}
-	else if ( state == 1 )//towns
-	{
-		for (size_t i=0; i<size; i++)
-			towns[i]->deactivate();
-		townPos = newpos;
-		recreateTownList(newpos);
-		for (size_t i=0; i<size; i++)
-			towns[i]->activate();
-		showAll(screen2);
-	}
-	else//heroes
-	{
-		for (size_t i=0; i<size; i++)
-			heroes[i]->deactivate();
-		heroPos = newpos;
-		recreateHeroList(newpos);
-		for (size_t i=0; i<size; i++)
-			heroes[i]->activate();
-		showAll(screen2);
+	case HERO_MANA:
+		text = CGI->generaltexth->allTexts[205];
+		boost::replace_first(text, "%s", boost::lexical_cast<std::string>(hero->name));
+		boost::replace_first(text, "%d", boost::lexical_cast<std::string>(hero->mana));
+		boost::replace_first(text, "%d", boost::lexical_cast<std::string>(hero->manaLimit()));
+		*comp = NULL;
+		return true;
+
+	case HERO_EXPERIENCE:
+		text = CGI->generaltexth->allTexts[2];
+		boost::replace_first(text, "%d", boost::lexical_cast<std::string>(hero->level));
+		boost::replace_first(text, "%d", boost::lexical_cast<std::string>(CGI->heroh->reqExp(hero->level+1)));
+		boost::replace_first(text, "%d", boost::lexical_cast<std::string>(hero->exp));
+		*comp = NULL;
+		return true;
+
+	default:
+		return InfoBoxAbstractHeroData::prepareMessage(text, comp);
 	}
 }
 
-CKingdomInterface::CTownItem::CTownItem(int num, CKingdomInterface * Owner)
+InfoBoxCustomHeroData::InfoBoxCustomHeroData(InfoType Type, int SubID, si64 Value):
+	InfoBoxAbstractHeroData(Type),
+	subID(SubID),
+	value(Value)
 {
-	recActions = DISPOSE | SHARE_POS;
-	parent = Owner;
-	numb = num;
-	pos.x += 23;
-	pos.y += 25+num*116;
-	pos.w = 702;
-	pos.h = 114;
-	town = NULL;
-	garr = NULL;
-
-	garrHero  = new CHeroArea(pos.x+244, pos.y + 6, NULL);
-	visitHero = new CHeroArea(pos.x+476, pos.y + 6, NULL);
+}
 
-	for (int i=0; i<CREATURES_PER_TOWN;i++)
-	{//creatures info
-		creaGrowth.push_back(new HoverableArea());
-		creaGrowth[i]->pos = genRect(32, 32, pos.x+56+i*37, pos.y + 78);
+int InfoBoxCustomHeroData::getSubID()
+{
+	return subID;
+}
 
-		creaCount.push_back(new CCreaPlace());
-		creaCount[i]->pos = genRect(32, 32, pos.x+409+i*37, pos.y + 78);
-		creaCount[i]->type = i;
-	}
-	hallArea = new LRClickableAreaOpenTown();
-	hallArea->pos = genRect(38, 38, pos.x+69, pos.y + 31);
-	hallArea->type = 2;
+si64 InfoBoxCustomHeroData::getValue()
+{
+	return value;
+}
 
-	fortArea = new LRClickableAreaOpenTown();
-	fortArea->pos = genRect(38, 38, pos.x+111, pos.y + 31);
-	fortArea->type = 3;
+InfoBoxCustom::InfoBoxCustom(std::string ValueText, std::string NameText, std::string ImageName, size_t ImageIndex, std::string HoverText):
+	IInfoBoxData(CUSTOM),
+	valueText(ValueText),
+	nameText(NameText),
+	imageName(ImageName),
+	hoverText(HoverText),
+	imageIndex(ImageIndex)
+{
+}
 
-	townImage = new LRClickableAreaOpenTown();
-	townImage->pos = genRect(64, 58, pos.x+5, pos.y + 6);
-	townImage->type = 1;
+std::string InfoBoxCustom::getHoverText()
+{
+	return hoverText;
+}
+
+size_t InfoBoxCustom::getImageIndex()
+{
+	return imageIndex;
+}
+
+std::string InfoBoxCustom::getImageName(InfoBox::InfoSize size)
+{
+	return imageName;
+}
+
+std::string InfoBoxCustom::getNameText()
+{
+	return nameText;
+}
+
+std::string InfoBoxCustom::getValueText()
+{
+	return valueText;
+}
 
-	incomeArea = new HoverableArea();
-	incomeArea->pos = genRect(42, 64, pos.x+154, pos.y + 31);
-	incomeArea->hoverText = CGI->generaltexth->allTexts[255];
+bool InfoBoxCustom::prepareMessage(std::string &text, SComponent **comp)
+{
+	return false;
+}
 
+CObjectList::CObjectList(IGuiObjectListManager *Manager):
+	manager(Manager)
+{
 }
 
-CKingdomInterface::CTownItem::~CTownItem()
+CObjectList::~CObjectList()
 {
-	creaGrowth.clear();
-	creaCount.clear();
-	delete garr;
+	delete manager;
 }
 
-void CKingdomInterface::CTownItem::setTown(const CGTownInstance * newTown)
+void CObjectList::deleteItem(CIntObject* item)
 {
-	BLOCK_CAPTURING;
-	delete garr;
-	town = newTown;
-	if (!town)
-	{
+	if (!item)
 		return;
-		garr = NULL;
-	}
-	garr = new CGarrisonInt(pos.x+313,pos.y+3,4,Point(232,0),parent->slots->ourImages[parent->PicCount+2].bitmap,Point(313,2),town,town->visitingHero,true,true, true);
-
-	garrHero->hero = town->garrisonHero;
-	visitHero->hero = town->visitingHero;
+	if (active)
+		item->deactivate();
+	removeChild(item);
+	manager->removeObject(item);
+}
 
-	for (int i=0; i<CREATURES_PER_TOWN;i++)
-	{
-		creaCount[i]->town = NULL;
+CIntObject* CObjectList::createItem(size_t index)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	CIntObject * item = manager->getObject(index);
+	if (item == NULL)
+		item = new CIntObject();
 
-		int crid = -1;
+	item->recActions = defActions;
 
-		if (vstd::contains(town->builtBuildings,30+i+CREATURES_PER_TOWN))
-			crid = town->town->upgradedCreatures[i];
+	//May happen if object was created before call to getObject()
+	if(item->parent != this)
+	{
+		if (item->parent)
+			moveChild(item, item->parent, this);
 		else
-			crid = town->town->basicCreatures[i];
-
-		std::string descr=CGI->generaltexth->allTexts[588];
-		boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid]->namePl);
-		creaGrowth[i]->hoverText = descr;
-
-		descr=CGI->generaltexth->heroscrn[1];
-		boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid]->namePl);
-		creaCount[i]->hoverText = descr;
-		creaCount[i]->town = town;
+			addChild(item);
 	}
 
-	townImage->hoverText = town->name;
-	townImage->town = town;
-	hallArea->town = town;
+	if (item && active)
+		item->activate();
+	return item;
+}
+
+CTabbedInt::CTabbedInt(IGuiObjectListManager *Manager, Point position, size_t ActiveID):
+	CObjectList(Manager),
+	activeTab(NULL),
+	activeID(ActiveID)
+{
+	pos += position;
+	reset();
+}
 
-	hallArea->hoverText = CGI->buildh->buildings[town->subID][10+town->hallLevel()]->Name();
-	if (town->hasFort())
+void CTabbedInt::setActive(size_t which)
+{
+	if (which != activeID)
 	{
-		fortArea->hoverText = CGI->buildh->buildings[town->subID][6+town->fortLevel()]->Name();
-		fortArea->town = town;
+		activeID = which;
+		reset();
 	}
-	else
-		fortArea->hoverText = "";
 }
 
-void CKingdomInterface::CTownItem::activate()
+void CTabbedInt::reset()
 {
-	if (!town)
-		return;
-
-	setTown(town);
-	hallArea->activate();
-	fortArea->activate();
-	incomeArea->activate();
-	townImage->activate();
-
-	garrHero->activate();
-	visitHero->activate();
+	deleteItem(activeTab);
+	activeTab = createItem(activeID);
+	activeTab->moveTo(pos.topLeft());
 
-	for (int i=0; i<CREATURES_PER_TOWN;i++)
-		if (vstd::contains(town->builtBuildings,30+i))
-		{
-			creaGrowth[i]->activate();
-			creaCount [i]->activate();
-		}
-	garr->activate();
+	if (active)
+		redraw();
 }
 
-void CKingdomInterface::CTownItem::deactivate()
+CIntObject * CTabbedInt::getItem()
 {
-	if (!town)
-		return;
-
-	hallArea->deactivate();
-	fortArea->deactivate();
-	incomeArea->deactivate();
-	townImage->deactivate();
+	return activeTab;
+}
 
-	garrHero->deactivate();
-	visitHero->deactivate();
+CListBox::CListBox(IGuiObjectListManager *Manager, Point Pos, Point ItemOffset, size_t VisibleSize,
+                   size_t TotalSize, size_t InitialPos, int Slider, Rect SliderPos):
+	CObjectList(Manager),
+	first(InitialPos),
+	totalSize(TotalSize),
+	itemOffset(ItemOffset)
+{
+	pos += Pos;
+	items.resize(VisibleSize, NULL);
 
-	for (int i=0; i<CREATURES_PER_TOWN;i++)
-		if (creaCount[i]->active)
-		{
-			creaGrowth[i]->deactivate();
-			creaCount [i]->deactivate();
-		}
-	garr->deactivate();
+	if (Slider & 1)
+	{
+		OBJ_CONSTRUCTION_CAPTURING_ALL;
+		slider = new CSlider(SliderPos.x, SliderPos.y, SliderPos.w, boost::bind(&CListBox::moveToPos, this, _1),
+		                     VisibleSize, TotalSize, InitialPos, Slider & 2, Slider & 4);
+	}
+	reset();
 }
 
-void CKingdomInterface::CTownItem::showAll(SDL_Surface * to)
+// Used to move active items after changing list position
+void CListBox::updatePositions()
 {
-	if (!town)
-	{//if NULL - print background & exit
-		blitAt(parent->slots->ourImages[numb % parent->PicCount].bitmap,pos.x,pos.y,to);
-		return;
-	}//background
-	blitAt(parent->slots->ourImages[parent->PicCount+2].bitmap,pos.x,pos.y,to);	garr->show(to);
-	//town pic/name
-	int townPic = town->subID*2;
-	if (!town->hasFort())
-		townPic += F_NUMBER*2;
-	if(town->builded >= MAX_BUILDING_PER_TURN)
-		townPic++;
-	blitAt(graphics->bigTownPic->ourImages[townPic].bitmap,pos.x+5,pos.y+6,to);
-	CSDL_Ext::printAt(town->name,pos.x+73,pos.y+8,FONT_SMALL,zwykly,to);
-	//fort pic
-	townPic = town->fortLevel()-1;
-	if (townPic==-1) townPic = 3;
-	blitAt(parent->fort->ourImages[townPic].bitmap,pos.x+111,pos.y+31,to);
-	//hall pic
-	townPic = town->hallLevel();
-	blitAt(parent->hall->ourImages[townPic].bitmap,pos.x+69,pos.y+31,to);
-	//income pic
-	std::ostringstream oss;
-	oss << town->dailyIncome();
-	CSDL_Ext::printAtMiddle(oss.str(),pos.x+189,pos.y+61,FONT_SMALL,zwykly,to);
-
-	std::vector<std::string> toPrin = CMessage::breakText(CGI->generaltexth->allTexts[265]);
-
-	CSDL_Ext::printAt(toPrin[0], pos.x+4, pos.y+76, FONT_SMALL, tytulowy, to);
-	if(toPrin.size()!=1)
-		CSDL_Ext::printAt(toPrin[1], pos.x+4, pos.y+92, FONT_SMALL, tytulowy, to);
-
-	toPrin = CMessage::breakText(CGI->generaltexth->allTexts[266]);
-
-	CSDL_Ext::printAt(toPrin[0], pos.x+351, pos.y+76, FONT_SMALL, tytulowy, to);
-	if(toPrin.size()!=1)
-		CSDL_Ext::printAt(toPrin[1], pos.x+351, pos.y+92, FONT_SMALL, tytulowy, to);
-
-	for (int i=0; i<CREATURES_PER_TOWN;i++)
-	{//creatures info
-		int crid = -1;
-		int bid = 30+i;
-		if (!vstd::contains(town->builtBuildings,bid))
-			continue;
-
-		if (vstd::contains(town->builtBuildings,bid+CREATURES_PER_TOWN))
-		{
-			crid = town->town->upgradedCreatures[i];
-			bid += CREATURES_PER_TOWN;
-		}
-		else
-			crid = town->town->basicCreatures[i];
-		//creature growth
-		blitAt(graphics->smallImgs[crid],pos.x+56+i*37,pos.y+78,to);
-		std::ostringstream oss;
-		oss << '+' << town->creatureGrowth(i);
-		CSDL_Ext::printTo(oss.str(),pos.x+87+i*37,pos.y+110,FONT_TINY,zwykly,to);
-		//creature available
-		blitAt(graphics->smallImgs[crid],pos.x+409+i*37,pos.y+78,to);
-		std::ostringstream ostrs;
-		ostrs << town->creatures[i].first;
-		CSDL_Ext::printTo(ostrs.str(),pos.x+440+i*37,pos.y+110,FONT_TINY,zwykly,to);
+	Point itemPos = pos.topLeft();
+	for (std::list<CIntObject*>::iterator it = items.begin(); it!=items.end(); it++)
+	{
+		(*it)->moveTo(itemPos);
+		itemPos += itemOffset;
+	}
+	if (active)
+	{
+		redraw();
+		if (slider)
+			slider->moveTo(first);
 	}
-	
-	garrHero->showAll(to);
-	visitHero->showAll(to);
 }
 
-CKingdomInterface::CHeroItem::CHeroItem(int num, CKingdomInterface * Owner)
+void CListBox::reset()
 {
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	recActions = DISPOSE | SHARE_POS;
-	defActions = SHARE_POS;
-	parent = Owner;
-	numb = num;
-	pos.x += 23;
-	pos.y += 25+num*116;
-	pos.w = 702;
-	pos.h = 114;
-	hero = NULL;
-	garr = NULL;
-	artGroup = 0;
-	backpackPos = 0;
-	artButtons = new CHighlightableButtonsGroup(0);
-	for (size_t it = 0; it<3; it++)
+	size_t current = first;
+	for (std::list<CIntObject*>::iterator it = items.begin(); it!=items.end(); it++)
 	{
-		artButtons->addButton(boost::assign::map_list_of(0,CGI->generaltexth->overview[13+it]),
-			CGI->generaltexth->overview[8+it], "OVBUTN3.DEF",364+it*112, 46, it);
-		std::string str = CGI->generaltexth->overview[8+it];
-		str = str.substr(str.find_first_of("{")+1, str.find_first_of("}")-str.find_first_of("{"));
-		artButtons->buttons[it]->addTextOverlay(str, FONT_SMALL, tytulowy);
+		deleteItem(*it);
+		*it = createItem(current++);
 	}
-	artButtons->onChange = boost::bind(&CKingdomInterface::CHeroItem::onArtChange, this, _1);
-	artButtons->select(0,0);
+	updatePositions();
+}
+
+void CListBox::moveToPos(size_t which)
+{
+	//Calculate new position
+	size_t maxPossible;
+	if (totalSize > items.size())
+		maxPossible = totalSize - items.size();
+	else
+		maxPossible = 0;
 
-	artLeft = new AdventureMapButton("", "", boost::bind
-		(&CKingdomInterface::CHeroItem::scrollArts,this,-1), 269, 66, "hsbtns3.def", SDLK_LEFT);
-	artRight = new AdventureMapButton("", "", boost::bind
-		(&CKingdomInterface::CHeroItem::scrollArts,this,+1), 675, 66, "hsbtns5.def", SDLK_RIGHT);
+	size_t newPos = std::min(which, maxPossible);
 
-	portrait = new CHeroArea(5,5,NULL);
-	char bufor[400];
-	for(int i=0; i<PRIMARY_SKILLS; i++)
-	{
-		primarySkills.push_back(new LRClickableAreaWTextComp(genRect(45, 32, pos.x+77 + 36*i, pos.y+26), SComponent::primskill));
-		primarySkills[i]->text = CGI->generaltexth->arraytxt[2+i];
-		primarySkills[i]->type = i;
-		sprintf(bufor, CGI->generaltexth->heroscrn[1].c_str(), CGI->generaltexth->primarySkillNames[i].c_str());
-		primarySkills[i]->hoverText = std::string(bufor);
-	};
-	experience = new LRClickableAreaWText();
-	experience->pos = genRect(33, 49, pos.x+322, pos.y+5);
-	experience->hoverText = CGI->generaltexth->heroscrn[9];
-
-	morale = new MoraleLuckBox(true, genRect(20,32,pos.x+221,pos.y+52));
-	luck = new MoraleLuckBox(false, genRect(20,32,pos.x+221,pos.y+28));
-
-	spellPoints = new LRClickableAreaWText();
-	spellPoints->pos = genRect(33, 49, pos.x+270, pos.y+5);
-	spellPoints->hoverText = CGI->generaltexth->heroscrn[22];
-
-	speciality = new LRClickableAreaWText();
-	speciality->pos = genRect(32, 32, pos.x+374, pos.y+5);
-	speciality->hoverText = CGI->generaltexth->heroscrn[27];
-
-	for(int i=0; i<SKILL_PER_HERO; ++i)
+	//If move distance is 1 (most of calls from Slider) - use faster shifts instead of resetting all items
+	if (first - newPos == 1)
+		moveToPrev();
+	else if (newPos - first == 1)
+		moveToNext();
+	else if (newPos != first)
 	{
-		secondarySkills.push_back(new LRClickableAreaWTextComp(genRect(32, 32, pos.x+410+i*37, pos.y+5), SComponent::secskill));
+		first = newPos;
+		reset();
 	}
-/*
-	for (int i=0; i<18;i++)
+}
+
+void CListBox::moveToNext()
+{
+	//Remove front item and insert new one to end
+	if (first + items.size() < totalSize)
 	{
-		artifacts.push_back(new CArtPlace(this, genRect(44, 44, pos.x+268+(i%9)*48, pos.y+66)));
+		first++;
+		deleteItem(items.front());
+		items.pop_front();
+		items.push_back(createItem(first+items.size()));
+		updatePositions();
 	}
+}
 
-	for (int i=0; i<8;i++)
+void CListBox::moveToPrev()
+{
+	//Remove last item and insert new one at start
+	if (first)
 	{
-		backpack.push_back(new CArtPlace(this, genRect(44, 44, pos.x+293+(i%9)*48, pos.y+66)));
-	}*/
+		first--;
+		deleteItem(items.back());
+		items.pop_back();
+		items.push_front(createItem(first));
+		updatePositions();
+	}
 }
 
-CKingdomInterface::CHeroItem::~CHeroItem()
+std::list<CIntObject*> CListBox::getItems()
 {
-	delete garr;
-	delete artButtons;
-	primarySkills.clear();
-	secondarySkills.clear();
-	artifacts.clear();
-	backpack.clear();
+	return items;
 }
 
-void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero)
+struct OwnedObjectInfo
 {
-	BLOCK_CAPTURING;
-	delete garr;
-	hero = newHero;
-	if (!hero)
-	{
-		return;
-		garr = NULL;
-	}
-	char bufor[4000];
-	artLeft->block(hero->artifactsInBackpack.size() <= 8);
-	artRight->block(hero->artifactsInBackpack.size() <= 8);
-	garr = new CGarrisonInt(pos.x+6, pos.y+78, 4, Point(), parent->slots->ourImages[parent->PicCount].bitmap,
-		Point(6,78), hero, NULL, true, true, true);
+	int imageID;
+	unsigned int count;
+	std::string hoverText;
+};
 
-	for (int i=0; i<artifacts.size(); i++)
+class OwnedObjectsListManager : public IGuiObjectListManager
+{
+	std::vector<OwnedObjectInfo> objects;
+public:
+	virtual CIntObject * getObject(size_t position)
 	{
-		artifacts[i]->type = hero->getArtTypeId(i);
-		if (artifacts[i]->type<0 || artifacts[i]->type == 145 )
-			artifacts[i]->hoverText = CGI->generaltexth->heroscrn[11];
-		else
+		if (position < objects.size())
 		{
-			artifacts[i]->text = CGI->generaltexth->artifDescriptions[artifacts[i]->type];
-			artifacts[i]->hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1].c_str()) % CGI->arth->artifacts[artifacts[i]->type]->Name());
+			OwnedObjectInfo &obj = objects[position];
+			std::string value = boost::lexical_cast<std::string>(obj.count);
+			return new InfoBox(Point(), InfoBox::POS_CORNER, InfoBox::SIZE_SMALL,
+			       new InfoBoxCustom(value,"", "FLAGPORT", obj.imageID, obj.hoverText));
 		}
+		return NULL;
 	}
 
-	for (int i=0; i<backpack.size(); i++)
+	OwnedObjectsListManager(std::vector<OwnedObjectInfo> Objects):
+		objects(Objects)
 	{
-		backpack[i]->type = hero->getArtTypeId(19+i);
-		if (backpack[i]->type<0)
-			backpack[i]->hoverText ="";
-		else
+	}
+};
+
+class TownHeroListManager : public IGuiObjectListManager
+{
+public:
+	CIntObject *currentItem;
+
+	CIntObject *getObject(size_t position)
+	{
+		size_t size = conf.go()->ac.overviewSize;
+		switch (position)
 		{
-			backpack[i]->text = CGI->generaltexth->artifDescriptions[backpack[i]->type];
-			backpack[i]->hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1].c_str()) % CGI->arth->artifacts[backpack[i]->type]->Name());
+		case 0:
+			return new CKingdHeroList(size);
+		case 1:
+			return new CKingdTownList(size);
+		default:
+			return NULL;
 		}
 	}
+};
+
+CKingdomInterface::CKingdomInterface()
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	background = new CPicture(conf.go()->ac.overviewBg);
+	background->colorize(LOCPLINT->playerID);
+	pos = background->center();
+	unsigned int footerPos = conf.go()->ac.overviewSize * 116;
 
-	//sprintf(bufor, CGI->generaltexth->allTexts[15].c_str(), hero->name.c_str(), hero->type->heroClass->name.c_str());
-	//portrait->hoverText = std::string(bufor);
-	portrait->hero = hero;
+	tabArea = new CTabbedInt(new TownHeroListManager, Point(4,4));
 
-	speciality->text = CGI->generaltexth->hTxts[hero->subID].longBonus;
+	std::vector<const CGObjectInstance * > ownedObjects = LOCPLINT->cb->getMyObjects();
+	generateObjectsList(ownedObjects);
+	generateMinesList(ownedObjects);
+	generateButtons();
 
-	//primary skills
-	for(size_t g=0; g<primarySkills.size(); ++g)
-		primarySkills[g]->bonusValue = hero->getPrimSkillLevel(g);
+	statusbar = new CGStatusBar(new CPicture("KSTATBAR", 10,pos.h - 45));
+	resdatabar= new CResDataBar("KRESBAR", 3, 111+footerPos, 32, 2, 76, 76);
+}
 
-	//secondary skills
-	for(size_t g=0; g<std::min(secondarySkills.size(),hero->secSkills.size()); ++g)
+void CKingdomInterface::generateObjectsList(const std::vector<const CGObjectInstance * > &ownedObjects)
+{
+	unsigned int footerPos = conf.go()->ac.overviewSize * 116;
+	size_t dwellSize = (footerPos - 64)/57;
+
+	//Map used to determine image number for several objects
+	std::map<std::pair<int,int>,int> idToImage;
+	idToImage[std::make_pair( 20, 1)] = 81;//Golem factory
+	idToImage[std::make_pair( 42, 0)] = 82;//Lighthouse
+	idToImage[std::make_pair( 33, 0)] = 83;//Garrison
+	idToImage[std::make_pair(219, 0)] = 83;//Garrison
+	idToImage[std::make_pair( 33, 1)] = 84;//Anti-magic Garrison
+	idToImage[std::make_pair(219, 1)] = 84;//Anti-magic Garrison
+	idToImage[std::make_pair( 53, 7)] = 85;//Abandoned mine
+	idToImage[std::make_pair( 20, 0)] = 86;//Conflux
+	idToImage[std::make_pair( 87, 0)] = 87;//Harbor
+
+	std::map<int, OwnedObjectInfo> visibleObjects;
+	BOOST_FOREACH(const CGObjectInstance * object, ownedObjects)
 	{
-		int skill = hero->secSkills[g].first,
-		    level = hero->secSkills[g].second;
-		secondarySkills[g]->type = skill;
-		secondarySkills[g]->bonusValue = level;
-		secondarySkills[g]->text = CGI->generaltexth->skillInfoTexts[skill][level-1];
-		sprintf(bufor, CGI->generaltexth->heroscrn[21].c_str(), CGI->generaltexth->levels[level-1].c_str(), CGI->generaltexth->skillName[skill].c_str());
-		secondarySkills[g]->hoverText = std::string(bufor);
+		//Dwellings
+		if ( object->ID == 17 )
+		{
+			OwnedObjectInfo &info = visibleObjects[object->subID];
+			if (info.count++ == 0)
+			{
+				info.hoverText = CGI->creh->creatures[CGI->objh->cregens[object->subID]]->namePl;
+				info.imageID = object->subID;
+			}
+		}
+		//Special objects from idToImage map that should be displayed in objects list
+		std::map<std::pair<int,int>,int>::iterator iter = idToImage.find(std::make_pair(object->ID, object->subID));
+		if (iter != idToImage.end())
+		{
+			OwnedObjectInfo &info = visibleObjects[iter->second];
+			if (info.count++ == 0)
+			{
+				info.hoverText = object->hoverName;
+				info.imageID = iter->second;
+			}
+		}
 	}
-	//experience
-	experience->text = CGI->generaltexth->allTexts[2].c_str();
-	boost::replace_first(experience->text, "%d", boost::lexical_cast<std::string>(hero->level));
-	boost::replace_first(experience->text, "%d", boost::lexical_cast<std::string>(CGI->heroh->reqExp(hero->level+1)));
-	boost::replace_first(experience->text, "%d", boost::lexical_cast<std::string>(hero->exp));
+	std::vector<OwnedObjectInfo> objectsVector;
+	objectsVector.reserve(visibleObjects.size());
 
-	//spell points
-	sprintf(bufor, CGI->generaltexth->allTexts[205].c_str(), hero->name.c_str(), hero->mana, hero->manaLimit());
-	spellPoints->text = std::string(bufor);
-
-	//setting morale and luck
-	morale->set(hero);
-	luck->set(hero);
+	std::pair<int, OwnedObjectInfo> element;
+	BOOST_FOREACH(element, visibleObjects)
+	{
+		objectsVector.push_back(element.second);
+	}
+	dwellingsList = new CListBox(new OwnedObjectsListManager(objectsVector), Point(740,44), Point(0,57), dwellSize, visibleObjects.size());
 }
 
-void CKingdomInterface::CHeroItem::scrollArts(int move)
+void CKingdomInterface::generateMinesList(const std::vector<const CGObjectInstance * > &ownedObjects)
 {
-	backpackPos = ( backpackPos + move + hero->artifactsInBackpack.size()) % hero->artifactsInBackpack.size();
-	for (int i=0; i<backpack.size(); i++)
+	unsigned int footerPos = conf.go()->ac.overviewSize * 116;
+	std::vector<int> minesCount(RESOURCE_QUANTITY, 0);
+	int totalIncome=0;
+
+	BOOST_FOREACH(const CGObjectInstance * object, ownedObjects)
 	{
-		backpack[i]->type = hero->getArtTypeId(19+(backpackPos + i)%hero->artifactsInBackpack.size());
-		if (backpack[i]->type<0)
-			backpack[i]->hoverText ="";
-		else
+		//Mines
+		if ( object->ID == 53 )
 		{
-			backpack[i]->text = CGI->generaltexth->artifDescriptions[backpack[i]->type];
-			backpack[i]->hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1].c_str()) % CGI->arth->artifacts[backpack[i]->type]->Name());
+			const CGMine *mine = dynamic_cast<const CGMine*>(object);
+			assert(mine);
+			minesCount[mine->producedResource]++;
+
+			if (mine->producedResource == Res::GOLD)
+				totalIncome += mine->producedQuantity;
 		}
 	}
-	showAll(screen2);
-}
 
-void CKingdomInterface::CHeroItem::showAll(SDL_Surface * to)
-{
-	if (!hero)
-	{//if we have no hero for this slot - print background & exit
-		blitAt(parent->slots->ourImages[numb % parent->PicCount].bitmap,pos.x,pos.y,to);
-		return;
-	}//print background, different for arts view/backpack mode
-	blitAt(parent->slots->ourImages[(artGroup!=2)?parent->PicCount:(parent->PicCount+1)].bitmap,pos.x,pos.y,to);
-	//text "Artifacts"
-	CSDL_Ext::printAtMiddle(CGI->generaltexth->overview[2],pos.x+320,pos.y+55,FONT_SMALL,zwykly,to);
-	portrait->showAll(to);
-
-	garr->show(to);
-	//hero name
-	CSDL_Ext::printAt(hero->name,pos.x+73,pos.y+7,FONT_SMALL,zwykly,to);
-	for (int i = 0; i<6; i++)
-	{//primary skills, mana and exp. pics
-		blitAt(graphics->pskillst->ourImages[i].bitmap,(i<4)?(pos.x+78+36*i):(pos.x+539-52*i),
-								(i<4)?(pos.y+26):(pos.y+6),to);
-		if (i>3) continue;//primary skills text
-		std::ostringstream str;
-		str << (hero->getPrimSkillLevel(i));
-		CSDL_Ext::printAtMiddle(str.str(),pos.x+94+36*i,pos.y+66,FONT_SMALL,zwykly,to);
+	//Heroes can produce gold as well - skill, speciality or arts
+	std::vector<const CGHeroInstance*> heroes = LOCPLINT->cb->getHeroesInfo(true);
+	for(size_t i=0; i<heroes.size(); i++)
+	{
+		totalIncome += heroes[i]->valOfBonuses(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, CGHeroInstance::ESTATES));
+		totalIncome += heroes[i]->valOfBonuses(Selector::typeSubtype(Bonus::GENERATE_RESOURCE, Res::GOLD));
 	}
-	{//luck and morale pics, experience and mana text
-		blitAt(graphics->luck30->ourImages[hero->LuckVal()+3].bitmap,pos.x+222,pos.y+30,to);
-		blitAt(graphics->morale30->ourImages[hero->MoraleVal()+3].bitmap,pos.x+222,pos.y+54,to);
-		std::ostringstream str;
-		str << (hero->exp);
-		CSDL_Ext::printAtMiddle(str.str(),(pos.x+348),(pos.y+31),FONT_TINY,zwykly,to);
-		std::ostringstream strnew;
-		strnew << (hero->mana)<<"/"<<(hero->manaLimit());
-		CSDL_Ext::printAtMiddle(strnew.str(),(pos.x+295),(pos.y+30),FONT_TINY,zwykly,to);
+
+	//Add town income of all towns
+	std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo(true);
+	for(size_t i=0; i<towns.size(); i++)
+	{
+		totalIncome += towns[i]->dailyIncome();
 	}
-	//hero speciality
-	blitAt(graphics->un32->ourImages[hero->subID].bitmap, pos.x+375, pos.y+6, to);
-
-	for(int i=0; i<hero->secSkills.size(); i++)
-	{//secondary skills
-		int skill = hero->secSkills[i].first,
-		    level = hero->secSkills[i].second;
-		blitAt(graphics->abils32->ourImages[skill*3+level+2].bitmap,pos.x+411+i*36,pos.y+6,to);
+	for (int i=0; i<7; i++)
+	{
+		std::string value = boost::lexical_cast<std::string>(minesCount[i]);
+		minesBox[i] = new InfoBox(Point(20+i*80, 31+footerPos), InfoBox::POS_INSIDE, InfoBox::SIZE_SMALL,
+		              new InfoBoxCustom(value, "", "OVMINES", i, CGI->generaltexth->mines[i].first));
 	}
+	incomeArea = new HoverableArea;
+	incomeArea->pos = Rect(pos.x+580, pos.y+31+footerPos, 136, 68);
+	incomeArea->hoverText = CGI->generaltexth->allTexts[255];
+	incomeAmount = new CLabel(628, footerPos + 70, FONT_SMALL, TOPLEFT, zwykly, boost::lexical_cast<std::string>(totalIncome));
+}
 
-	artButtons->show(to);
+void CKingdomInterface::generateButtons()
+{
+	unsigned int footerPos = conf.go()->ac.overviewSize * 116;
 
-	int iter=0;
-	switch (artGroup)
-	{//arts
-		case 1:iter = 9;//misc. arts, spellbook, war machines
-		case 0://equipped arts
-			/*for (int i = iter ; i<iter+9;i++)
-			{
-				int artID = hero->getArtTypeId(i);
-				if (artID>=0)
-					blitAt(graphics->artDefs->ourImages[artID].bitmap,pos.x+268+48*(i%9),pos.y+66,to);
-			}*/
-			break;
-		case 2:
-			artLeft->show(to);
-			artRight->show(to);
-			int max = hero->artifactsInBackpack.size();
-			iter = std::min(8, max);
-			/*for (size_t it = 0 ; it<iter;it++)
-				blitAt(graphics->artDefs->ourImages[hero->artifacts[(it+backpackPos)%max]->id].bitmap,pos.x+293+48*it,pos.y+66,to);
-			*/break;
-	}
-	show(to);
+	//Main control buttons
+	btnHeroes = new AdventureMapButton (CGI->generaltexth->overview[11], CGI->generaltexth->overview[6],
+	                                    boost::bind(&CKingdomInterface::activateTab, this, 0),748,28+footerPos,"OVBUTN1.DEF", SDLK_h);
+	btnHeroes->block(true);
+
+	btnTowns = new AdventureMapButton (CGI->generaltexth->overview[12], CGI->generaltexth->overview[7],
+	                                   boost::bind(&CKingdomInterface::activateTab, this, 1),748,64+footerPos,"OVBUTN6.DEF", SDLK_t);
+
+	btnExit = new AdventureMapButton (CGI->generaltexth->allTexts[600],"",
+	                                  boost::bind(&CGuiHandler::popIntTotally,&GH, this),748,99+footerPos,"OVBUTN1.DEF", SDLK_RETURN);
+	btnExit->assignedKeys.insert(SDLK_ESCAPE);
+	btnExit->setOffset(3);
+
+	//Object list control buttons
+	dwellTop = new AdventureMapButton ("", "", boost::bind(&CListBox::moveToPos, dwellingsList, 0),
+	                                   733, 4, "OVBUTN4.DEF");
+
+	dwellBottom = new AdventureMapButton ("", "", boost::bind(&CListBox::moveToPos, dwellingsList, -1),
+	                                      733, footerPos+2, "OVBUTN4.DEF");
+	dwellBottom->setOffset(2);
+
+	dwellUp = new AdventureMapButton ("", "", boost::bind(&CListBox::moveToPrev, dwellingsList),
+	                                  733, 24, "OVBUTN4.DEF");
+	dwellUp->setOffset(4);
+
+	dwellDown = new AdventureMapButton ("", "", boost::bind(&CListBox::moveToNext, dwellingsList),
+	                                    733, footerPos-18, "OVBUTN4.DEF");
+	dwellDown->setOffset(6);
 }
 
-void CKingdomInterface::CHeroItem::onArtChange(int newstate)
+void CKingdomInterface::activateTab(size_t which)
 {
-	if (!hero)
-		return;
-	deactivate();
-	artGroup = newstate;
-	activate();
-	showAll(screen2);
+	btnHeroes->block(which == 0);
+	btnTowns->block(which == 1);
+	tabArea->setActive(which);
 }
 
-void CKingdomInterface::CHeroItem::activate()
+void CKingdomInterface::townChanged(const CGTownInstance *town)
 {
-	setHero(hero);
-	if (!hero)
-		return;
-	artButtons->activate();
-	garr->activate();/*
-	if ( artGroup == 2 )
+	if (CKingdTownList * townList = dynamic_cast<CKingdTownList*>(tabArea->getItem()))
+		townList->townChanged(town);
+}
+
+void CKingdomInterface::updateGarrisons()
+{
+	if (CGarrisonHolder * garrison = dynamic_cast<CGarrisonHolder*>(tabArea->getItem()))
+		garrison->updateGarrisons();
+}
+
+void CKingdomInterface::artifactAssembled(const ArtifactLocation& artLoc)
+{
+	if (CArtifactHolder * arts = dynamic_cast<CArtifactHolder*>(tabArea->getItem()))
+		arts->artifactAssembled(artLoc);
+}
+
+void CKingdomInterface::artifactDisassembled(const ArtifactLocation& artLoc)
+{
+	if (CArtifactHolder * arts = dynamic_cast<CArtifactHolder*>(tabArea->getItem()))
+		arts->artifactDisassembled(artLoc);
+}
+
+void CKingdomInterface::artifactMoved(const ArtifactLocation& artLoc, const ArtifactLocation& destLoc)
+{
+	if (CArtifactHolder * arts = dynamic_cast<CArtifactHolder*>(tabArea->getItem()))
+		arts->artifactMoved(artLoc, destLoc);
+}
+
+void CKingdomInterface::artifactRemoved(const ArtifactLocation& artLoc)
+{
+	if (CArtifactHolder * arts = dynamic_cast<CArtifactHolder*>(tabArea->getItem()))
+		arts->artifactRemoved(artLoc);
+}
+
+class HeroListManager : public IGuiObjectListManager
+{
+	CWindowWithArtifacts * arts;
+	CArtifactsOfHero::SCommonPart * artsCommonPart;
+public:
+	HeroListManager(CWindowWithArtifacts * parent);
+	~HeroListManager();
+	CIntObject * getObject(size_t position);
+	void removeObject(CIntObject *object);
+};
+
+HeroListManager::HeroListManager(CWindowWithArtifacts * parent)
+{
+	arts = parent;
+	artsCommonPart = new CArtifactsOfHero::SCommonPart;
+}
+
+HeroListManager::~HeroListManager()
+{
+	delete artsCommonPart;
+}
+
+CIntObject * HeroListManager::getObject(size_t position)
+{
+	unsigned int picCount = conf.go()->ac.overviewPics;
+	size_t heroesCount = LOCPLINT->cb->howManyHeroes(false);
+
+	if (position < heroesCount)
 	{
-		artLeft->activate();
-		artRight->activate();
-		for (size_t i=0; i<8;i++)
-			backpack[i]->activate();
+		CHeroItem * hero = new CHeroItem(LOCPLINT->cb->getHeroBySerial(position, false), artsCommonPart);
+		artsCommonPart->participants.insert(hero->heroArts);
+		arts->artSets.push_back(hero->heroArts);
+		return hero;
 	}
 	else
 	{
-		for (size_t i=artGroup*9; i<9+artGroup*9;i++)
-			artifacts[i]->activate();
-	}*/
-	portrait->activate();
-	experience->activate();
-	morale->activate();
-	luck->activate();
-	spellPoints->activate();
-	speciality->activate();
+		return new CAnimImage("OVSLOT", (position-2) % picCount );
+	}
+};
 
-	for (size_t i=0; i<primarySkills.size();i++)
-		primarySkills[i]->activate();
+void HeroListManager::removeObject(CIntObject *object)
+{
+	if (CHeroItem * hero = dynamic_cast<CHeroItem*>(object))
+	{
+		arts->artSets.erase(std::find(arts->artSets.begin(), arts->artSets.end(), hero->heroArts));
+		artsCommonPart->participants.erase(hero->heroArts);
+	}
+	delete object;
+}
 
-	for (size_t i=0; i<std::min(secondarySkills.size(),hero->secSkills.size());i++)
-		secondarySkills[i]->activate();
+CKingdHeroList::CKingdHeroList(size_t maxSize)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	title = new CPicture("OVTITLE",16,0);
+	title->colorize(LOCPLINT->playerID);
+	heroLabel =   new CLabel(150, 10, FONT_MEDIUM, CENTER, zwykly, CGI->generaltexth->overview[0]);
+	skillsLabel = new CLabel(500, 10, FONT_MEDIUM, CENTER, zwykly, CGI->generaltexth->overview[1]);
+
+	unsigned int townCount = LOCPLINT->cb->howManyHeroes(false);
+	unsigned int size = conf.go()->ac.overviewSize*116 + 19;
+	heroes = new CListBox(new HeroListManager(this), Point(19,21), Point(0,116), maxSize, townCount, 0, 1, Rect(-19, -21, size, size) );
 }
 
-void CKingdomInterface::CHeroItem::deactivate()
+void CKingdHeroList::updateGarrisons()
 {
-	if (!hero)
-		return;
-	artButtons->deactivate();
-	garr->deactivate();/*
-	if ( artGroup == 2 )
+	std::list<CIntObject*> list = heroes->getItems();
+	BOOST_FOREACH(CIntObject* object, list)
 	{
-		artLeft->deactivate();
-		artRight->deactivate();
-		for (size_t i=0; i<8;i++)
-			backpack[i]->deactivate();
+		if (CGarrisonHolder * garrison = dynamic_cast<CGarrisonHolder*>(object) )
+			garrison->updateGarrisons();
 	}
-	else
+}
+
+class TownListManager : public IGuiObjectListManager
+{
+public:
+	CIntObject * getObject(size_t position)
 	{
-		for (size_t i=artGroup*9; i<9+artGroup*9;i++)
-			artifacts[i]->deactivate();
-	}*/
+		unsigned int picCount = conf.go()->ac.overviewPics;
+		size_t townsCount = LOCPLINT->cb->howManyTowns();
 
-	portrait->deactivate();
-	experience->deactivate();
-	morale->deactivate();
-	luck->deactivate();
-	spellPoints->deactivate();
-	speciality->deactivate();
-	for (size_t i=0; i<primarySkills.size();i++)
-		primarySkills[i]->deactivate();
+		if (position < townsCount)
+			return new CTownItem(LOCPLINT->cb->getTownBySerial(position));
+		else
+			return new CAnimImage("OVSLOT", (position-2) % picCount );
+	}
+};
 
-	for (size_t i=0; i<std::min(secondarySkills.size(),hero->secSkills.size());i++)
-		secondarySkills[i]->deactivate();
+CKingdTownList::CKingdTownList(size_t maxSize)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	title = new CPicture("OVTITLE",16,0);
+	title->colorize(LOCPLINT->playerID);
+	townLabel   = new CLabel(146,10,FONT_MEDIUM, CENTER, zwykly, CGI->generaltexth->overview[3]);
+	garrHeroLabel  = new CLabel(375,10,FONT_MEDIUM, CENTER, zwykly, CGI->generaltexth->overview[4]);
+	visitHeroLabel = new CLabel(608,10,FONT_MEDIUM, CENTER, zwykly, CGI->generaltexth->overview[5]);
+
+	unsigned int townCount = LOCPLINT->cb->howManyTowns();
+	unsigned int size = conf.go()->ac.overviewSize*116 + 19;
+	towns = new CListBox(new TownListManager, Point(19,21), Point(0,116), maxSize, townCount, 0, 1, Rect(-19, -21, size, size) );
 }
 
-CKingdomInterface::CHeroItem::CArtPlace::CArtPlace(CHeroItem * owner, const Rect &r)
-	: LRClickableAreaWTextComp(r, SComponent::artifact)
+void CKingdTownList::townChanged(const CGTownInstance *town)
 {
-	parent = owner;
-	used = LCLICK | RCLICK | HOVER;
+	std::list<CIntObject*> list = towns->getItems();
+	BOOST_FOREACH(CIntObject* object, list)
+	{
+		CTownItem * townItem = dynamic_cast<CTownItem*>(object);
+		if ( townItem && townItem->town == town)
+			townItem->update();
+	}
 }
 
-void CKingdomInterface::CHeroItem::CArtPlace::activate()
+void CKingdTownList::updateGarrisons()
 {
-	LRClickableAreaWTextComp::activate();
+	std::list<CIntObject*> list = towns->getItems();
+	BOOST_FOREACH(CIntObject* object, list)
+	{
+		if (CGarrisonHolder * garrison = dynamic_cast<CGarrisonHolder*>(object) )
+			garrison->updateGarrisons();
+	}
 }
 
-void CKingdomInterface::CHeroItem::CArtPlace::clickLeft(tribool down, bool previousState)
+CTownItem::CTownItem(const CGTownInstance* Town):
+	town(Town)
 {
-	if (!down && previousState && type>=0 && type < 145)
-	{tlog1<<type;
-		if(type == 0)
-		{
-			CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), parent->hero, LOCPLINT, false);
-			GH.pushInt(spellWindow);
-		}
-		else
-			LRClickableAreaWTextComp::clickLeft(down,previousState);
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	background =  new CAnimImage("OVSLOT", 6);
+	name = new CLabel(74, 8, FONT_SMALL, TOPLEFT, zwykly, town->name);
+
+	income = new CLabel( 190, 60, FONT_SMALL, CENTER, zwykly, boost::lexical_cast<std::string>(town->dailyIncome()));
+	hall = new CTownInfo( 69, 31, town, true);
+	fort = new CTownInfo(111, 31, town, false);
+
+	garr = new CGarrisonInt(313, 3, 4, Point(232,0),  NULL, Point(313,2), town->getUpperArmy(), town->visitingHero, true, true, true);
+	heroes = new HeroSlots(town, Point(244,6), Point(475,6), garr, false);
+
+	size_t iconIndex = town->subID*2;
+	if (!town->hasFort())
+		iconIndex += F_NUMBER*2;
+
+	if(town->builded >= MAX_BUILDING_PER_TURN)
+		iconIndex++;
+
+	picture = new CAnimImage("ITPT", iconIndex, 0, 5, 6);
+	townArea = new LRClickableAreaOpenTown;
+	townArea->pos = Rect(pos.x+5, pos.y+6, 58, 64);
+	townArea->town = town;
+
+	for (size_t i=0; i<town->creatures.size(); i++)
+	{
+		growth.push_back(new CCreaInfo(Point(401+37*i, 78), town, i, true, true));
+		available.push_back(new CCreaInfo(Point(48+37*i, 78), town, i, true, false));
 	}
 }
 
-void CKingdomInterface::CHeroItem::CArtPlace::clickRight(tribool down, bool previousState)
+void CTownItem::updateGarrisons()
 {
-	if (type>=0 && type < 145)
-		LRClickableAreaWTextComp::clickRight(down, previousState);
+	garr->highlighted = NULL;
+	garr->setArmy(town->getUpperArmy(), 0);
+	garr->setArmy(town->visitingHero, 1);
+	garr->recreateSlots();
 }
 
-void CKingdomInterface::CHeroItem::CArtPlace::deactivate()
+void CTownItem::update()
 {
-		LRClickableAreaWTextComp::deactivate();
+	std::string incomeVal = boost::lexical_cast<std::string>(town->dailyIncome());
+	if (incomeVal != income->text)
+		income->setTxt(incomeVal);
+
+	heroes->update();
+
+	for (size_t i=0; i<town->creatures.size(); i++)
+	{
+		growth[i]->update();
+		available[i]->update();
+	}
 }
 
+class ArtSlotsTab : public CIntObject
+{
+public:
+	CAnimImage * background;
+	std::vector<CArtPlace*> arts;
+
+	ArtSlotsTab()
+	{
+		OBJ_CONSTRUCTION_CAPTURING_ALL;
+		background = new CAnimImage("OVSLOT", 4);
+		pos = background->pos;
+		for (size_t i=0; i<9; i++)
+			arts.push_back(new CArtPlace(Point(270+i*48, 65)));
+	}
+};
 
-CKingdomInterface::CTownItem::CCreaPlace::CCreaPlace()
-	: LRClickableAreaWTextComp(Rect(0,0,0,0), -1)
+class BackpackTab : public CIntObject
 {
-	town = NULL;
-	used = LCLICK | RCLICK | HOVER;
-}
+public:
+	CAnimImage * background;
+	std::vector<CArtPlace*> arts;
+	AdventureMapButton *btnLeft;
+	AdventureMapButton *btnRight;
+
+	BackpackTab()
+	{
+		OBJ_CONSTRUCTION_CAPTURING_ALL;
+		background = new CAnimImage("OVSLOT", 5);
+		pos = background->pos;
+		btnLeft = new AdventureMapButton(std::string(), std::string(), CFunctionList<void()>(), 269, 66, "HSBTNS3");
+		btnRight = new AdventureMapButton(std::string(), std::string(), CFunctionList<void()>(), 675, 66, "HSBTNS5");
+		for (size_t i=0; i<8; i++)
+			arts.push_back(new CArtPlace(Point(295+i*48, 65)));
+	}
+};
+
+class HeroItemManager : public CIntObject, public IGuiObjectListManager
+{
+public:
+	ArtSlotsTab* tab1;
+	ArtSlotsTab* tab2;
+	BackpackTab* tab3;
+
+	HeroItemManager(const CGHeroInstance* Hero);
+	CIntObject * getObject(size_t position);
+	void removeObject(CIntObject * object);
+};
 
-void CKingdomInterface::CTownItem::CCreaPlace::activate()
+HeroItemManager::HeroItemManager(const CGHeroInstance* Hero)
 {
-	LRClickableAreaWTextComp::activate();
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	recActions = 0;
+	defActions = DISPOSE | SHARE_POS;
+
+	tab1 = new ArtSlotsTab;
+	tab2 = new ArtSlotsTab;
+	tab3 = new BackpackTab;
 }
 
-void CKingdomInterface::CTownItem::CCreaPlace::clickLeft(tribool down, bool previousState)
+CIntObject * HeroItemManager::getObject(size_t position)
 {
-	if (!down && previousState && town)
+	switch (position)
 	{
-		GH.pushInt (new CRecruitmentWindow(town, type, town, boost::bind
-			(&CCallback::recruitCreatures,LOCPLINT->cb,town,_1,_2, type)));
+	case 0: return tab1;
+	case 1: return tab2;
+	case 2: return tab3;
+	default: assert(0);
+	         return NULL;
 	}
 }
 
-void CKingdomInterface::CTownItem::CCreaPlace::clickRight(tribool down, bool previousState)
+void HeroItemManager::removeObject(CIntObject * object)
+{
+	addChild(object, false);
+}
+
+CHeroItem::CHeroItem(const CGHeroInstance* Hero, CArtifactsOfHero::SCommonPart * artsCommonPart):
+	hero(Hero)
 {
-	if (down && town)
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+
+	name = new CLabel(75, 7, FONT_SMALL, TOPLEFT, zwykly, hero->name);
+
+	HeroItemManager *manager = new HeroItemManager(hero);
+
+	std::vector<CArtPlace*> arts;
+	arts.insert(arts.end(), manager->tab1->arts.begin(), manager->tab1->arts.end());
+	arts.insert(arts.end(), manager->tab2->arts.begin(), manager->tab2->arts.end());
+
+	heroArts = new CArtifactsOfHero(arts, manager->tab3->arts, manager->tab3->btnLeft, manager->tab3->btnRight, false);
+	heroArts->commonInfo = artsCommonPart;
+	heroArts->setHero(hero);
+
+	artsTabs = new CTabbedInt(manager);
+
+	artButtons = new CHighlightableButtonsGroup(0);
+	for (size_t it = 0; it<3; it++)
 	{
-		int crid;
-		if (town->builtBuildings.find(30+type+CREATURES_PER_TOWN)!=town->builtBuildings.end())
-			crid = town->town->upgradedCreatures[type];
-		else
-			crid = town->town->basicCreatures[type];
-		GH.pushInt(createCreWindow(crid, 0, town->creatures[type].first));
+		std::map<int,std::string> tooltip;
+		tooltip[0] = CGI->generaltexth->overview[13+it];
+		std::string overlay = CGI->generaltexth->overview[8+it];
+
+		artButtons->addButton(tooltip, overlay, "OVBUTN3",364+it*112, 46, it);
+
+		size_t begin = overlay.find('{');
+		size_t end   = overlay.find('}', begin);
+		overlay = overlay.substr(begin+1, end - begin);
+		artButtons->buttons[it]->addTextOverlay(overlay, FONT_SMALL, tytulowy);
 	}
+	artButtons->onChange += boost::bind(&CTabbedInt::setActive, artsTabs, _1);
+	artButtons->onChange += boost::bind(&CHeroItem::onArtChange, this, _1);
+	artButtons->select(0,0);
+
+	garr = new CGarrisonInt(6, 78, 4, Point(), NULL, Point(), hero, NULL, true, true);
+
+	portrait = new CAnimImage("PortraitsLarge", hero->subID, 0, 5, 6);
+	heroArea = new CHeroArea(5, 6, hero);
+
+	name = new CLabel(73, 7, FONT_SMALL, TOPLEFT, zwykly, hero->name);
+	artsText = new CLabel(320, 55, FONT_SMALL, CENTER, zwykly, CGI->generaltexth->overview[2]);
+
+	for (size_t i=0; i<PRIMARY_SKILLS; i++)
+		heroInfo.push_back(new InfoBox(Point(78+i*36, 26), InfoBox::POS_DOWN, InfoBox::SIZE_SMALL, 
+		                   new InfoBoxHeroData(IInfoBoxData::HERO_PRIMARY_SKILL, hero, i)));
+
+	for (size_t i=0; i<SKILL_PER_HERO; i++)
+		heroInfo.push_back(new InfoBox(Point(410+i*36, 5), InfoBox::POS_NONE, InfoBox::SIZE_SMALL,
+		                   new InfoBoxHeroData(IInfoBoxData::HERO_SECONDARY_SKILL, hero, i)));
+
+	heroInfo.push_back(new InfoBox(Point(375, 5), InfoBox::POS_NONE, InfoBox::SIZE_SMALL,
+	                   new InfoBoxHeroData(IInfoBoxData::HERO_SPECIAL, hero)));
+
+	heroInfo.push_back(new InfoBox(Point(330, 5), InfoBox::POS_INSIDE, InfoBox::SIZE_SMALL,
+	                   new InfoBoxHeroData(IInfoBoxData::HERO_EXPERIENCE, hero)));
+
+	heroInfo.push_back(new InfoBox(Point(280, 5), InfoBox::POS_INSIDE, InfoBox::SIZE_SMALL,
+	                   new InfoBoxHeroData(IInfoBoxData::HERO_MANA, hero)));
+
+	morale = new MoraleLuckBox(true, Rect(225, 53, 30, 22), true);
+	luck  = new MoraleLuckBox(false, Rect(225, 28, 30, 22), true);
+
+	morale->set(hero);
+	luck->set(hero);
 }
 
-void CKingdomInterface::CTownItem::CCreaPlace::deactivate()
+void CHeroItem::onArtChange(int tabIndex)
 {
-		LRClickableAreaWTextComp::deactivate();
+	//redraw item after background change
+	if (active)
+		redraw();
 }

+ 386 - 122
client/CKingdomInterface.h

@@ -1,19 +1,20 @@
-#ifndef __CKINGDOMINTERFACE_H__
-#define __CKINGDOMINTERFACE_H__
-
+#pragma once
 
 #include "../global.h"
+
+#include <list>
+
 #include "GUIBase.h"
 #include "GUIClasses.h"
-#include "CMusicBase.h"
+
 class AdventureMapButton;
+class CAnimImage;
 class CHighlightableButtonsGroup;
 class CResDataBar;
-class CStatusBar;
 class CSlider;
-class CMinorResDataBar;
-class HoverableArea;
-class MoraleLuckBox;
+class CTownInfo;
+class CCreaInfo;
+class HeroSlots;
 
 /*
  * CKingdomInterface.h, part of VCMI engine
@@ -25,123 +26,386 @@ class MoraleLuckBox;
  *
  */
 
-/// Huge class responsible for viewing and handling kingdom view, where you can see all your towns, flagged mines and heroes
-class CKingdomInterface : public CGarrisonHolder
+class CKingdHeroList;
+class CKingdTownList;
+class IInfoBoxData;
+
+/* 
+ * Several classes to display basically any data.
+ * Main part - class InfoBox which controls how data will be formatted\positioned
+ * InfoBox have image and 0-2 labels
+ * In constructor it should receive object that implements IInfoBoxData interface
+ * 
+ * interface IInfoBoxData defines way to get data for use in InfoBox
+ * have several implementations:
+ * InfoBoxHeroData - to display one of fields from hero (e.g. absolute value of primary skills)
+ * InfoBoxCustomHeroData - to display one of hero fields without hero (e.g. bonuses from objects)
+ * InfoBoxTownData - data from town
+ * InfoBoxCustom - user-defined data
+ */
+
+/// Displays one of object propertries with image and optional labels
+class InfoBox : public CIntObject
 {
-	class CTownItem : public CWindowWithGarrison
+public:
+	enum InfoPos
 	{
-		class CCreaPlace: public LRClickableAreaWTextComp
-		{
-		public:
-			const CGTownInstance * town;
-			CCreaPlace(); //c-tor
-			void clickLeft(tribool down, bool previousState);
-			void clickRight(tribool down, bool previousState);
-			void activate();
-			void deactivate();
-		};
-	public:
-		const CGTownInstance * town;
-		CKingdomInterface * parent;
-		int numb;//position on screen (1..size)
-		HoverableArea *incomeArea;//hoverable text for town hall, fort, income
-		CHeroArea * garrHero, *visitHero;//portraits of heroes
-		LRClickableAreaOpenTown *hallArea, *fortArea,  * townImage;//town image
-		std::vector < HoverableArea * > creaGrowth;
-		std::vector < CCreaPlace * > creaCount;
-		void setTown(const CGTownInstance * newTown);//change town and update info
-		void showAll(SDL_Surface * to);
-		void activate();
-		void deactivate();
-		CTownItem (int num, CKingdomInterface * Owner);//c-tor
-		~CTownItem();//d-tor
+		POS_UP_DOWN, POS_DOWN, POS_RIGHT, POS_INSIDE, POS_CORNER, POS_NONE
 	};
-	class CHeroItem : public CWindowWithGarrison
+	enum InfoSize
 	{
-		class CArtPlace: public LRClickableAreaWTextComp
-		{
-		public:
-			CHeroItem * parent;
-			CArtPlace(CHeroItem * owner, const Rect &r = Rect(0, 0, 44, 44)); //c-tor
-			void clickLeft(tribool down, bool previousState);
-			void clickRight(tribool down, bool previousState);
-			void activate();
-			void deactivate();
-		};
-
-		public:
-		const CGHeroInstance * hero;
-		CKingdomInterface * parent;
-		int artGroup,numb;//current art group (0 = equiped, 1 = misc, 2 = backpack)
-		int backpackPos;//first visible artifact in backpack
-		AdventureMapButton * artLeft, * artRight;//buttons for backpack
-		CHeroArea * portrait;
-		LRClickableAreaWText * experience;
-		MoraleLuckBox * morale, * luck;
-		LRClickableAreaWText * spellPoints;
-		LRClickableAreaWText * speciality;
-		std::vector<LRClickableAreaWTextComp *> primarySkills;
-		std::vector<LRClickableAreaWTextComp *> secondarySkills;
-		std::vector<CArtPlace *> artifacts;
-		std::vector<CArtPlace *> backpack;
-		CHighlightableButtonsGroup * artButtons;
-		void setHero(const CGHeroInstance * newHero);//change hero and update info
-		void scrollArts(int move);//moving backpack, receiving distance
-		void onArtChange(int newstate);//changes artgroup
-		void showAll(SDL_Surface * to);
-		void activate();
-		void deactivate();
-		CHeroItem (int num, CKingdomInterface * Owner);//c-tor
-		~CHeroItem();//d-tor
+		SIZE_TINY, SIZE_SMALL, SIZE_MEDIUM, SIZE_BIG, SIZE_HUGE
 	};
+
+private:
+	InfoSize size;
+	InfoPos  infoPos;
+	IInfoBoxData *data;
+
+	CLabel * value;
+	CLabel * name;
+	CAnimImage * image;
+	HoverableArea *hover;
+
+public:
+	InfoBox(Point position, InfoPos Pos, InfoSize Size, IInfoBoxData *Data);
+	~InfoBox();
+
+	void clickRight(tribool down, bool previousState);
+	void clickLeft(tribool down, bool previousState);
+
+	//Update object if data may have changed
+	//void update();
+};
+
+class IInfoBoxData
+{
+public:
+	enum InfoType
+	{
+		HERO_PRIMARY_SKILL, HERO_MANA, HERO_EXPERIENCE, HERO_SPECIAL, HERO_SECONDARY_SKILL,
+		//TODO: Luck? Morale? Artifact?
+		ARMY_SLOT,//TODO
+		TOWN_GROWTH, TOWN_AVAILABLE, TOWN_BUILDING,//TODO
+		CUSTOM
+	};
+
+protected:
+	InfoType type;
+
+	IInfoBoxData(InfoType Type);
+
+public:
+	//methods that generate values for displaying
+	virtual std::string getValueText()=0;
+	virtual std::string getNameText()=0;
+	virtual std::string getImageName(InfoBox::InfoSize size)=0;
+	virtual std::string getHoverText()=0;
+	virtual size_t getImageIndex()=0;
+
+	//TODO: replace with something better
+	virtual bool prepareMessage(std::string &text, SComponent **comp)=0;
+};
+
+class InfoBoxAbstractHeroData : public IInfoBoxData
+{
+protected:
+	virtual int  getSubID()=0;
+	virtual si64 getValue()=0;
+
+public:
+	InfoBoxAbstractHeroData(InfoType Type);
+
+	std::string getValueText();
+	std::string getNameText();
+	std::string getImageName(InfoBox::InfoSize size);
+	std::string getHoverText();
+	size_t getImageIndex();
+
+	bool prepareMessage(std::string &text, SComponent **comp);
+};
+
+class InfoBoxHeroData : public InfoBoxAbstractHeroData
+{
+	const CGHeroInstance * hero;
+	int index;//index of data in hero (0-7 for sec. skill, 0-3 for pr. skill)
+
+	int  getSubID();
+	si64 getValue();
+
 public:
-	//common data
-	int state;//1 = towns showed, 2 = heroes;
-	SDL_Surface * bg;//background
-	CStatusBar * statusbar;//statusbar
-	CResDataBar *resdatabar;//resources
-	int size,PicCount;
-
-	//buttons
-	AdventureMapButton *exit;//exit button
-	AdventureMapButton *toTowns;//town button
-	AdventureMapButton *toHeroes;//hero button
-	CDefEssential * title; //title bar
-
-	//hero/town lists
-	CSlider * slider;//slider
-	bool showHarrisoned;//show harrisoned hero in heroes list or not, disabled by default
-	int heroPos,townPos;//position of lists
-	std::vector<CHeroItem *> heroes;//heroes list
-	std::vector<CTownItem *> towns;//towns list
-	CDefEssential * slots, *fort, *hall;
-
-	//objects list
-	int objSize, objPos;
-	CDefEssential *objPics;
-	std::map<int,std::pair<int, const std::string*> > objList; //dwelling ID, count, hover text
-	std::vector <HoverableArea* > ObjList;//list of dwellings
-	AdventureMapButton* ObjUp, *ObjDown, *ObjTop, *ObjBottom;//buttons for dwellings list
-
-	//income pics
-	std::vector<HoverableArea*> incomes;//mines + incomes
-	std::vector<int> incomesVal;//values to print
-	CDefEssential * mines;
-
-	CKingdomInterface(); //c-tor
-	~CKingdomInterface(); //d-tor
-	void updateGarrisons();//garrison updater
-	void moveObjectList(int newPos);
-	void recreateHeroList(int pos);//recreating heroes list (on slider move)
-	void recreateTownList(int pos);//same for town list
-	void listToTowns();//changing list to town view
-	void listToHeroes();//changing list to heroes view
-	void sliderMoved(int newpos);//when we move a slider...
-	void show(SDL_Surface * to);
-	void showAll(SDL_Surface * to);
-	void close();
-	void activate();
-	void deactivate();
-};
-
-#endif // __CCASTLEINTERFACE_H__
+	InfoBoxHeroData(InfoType Type, const CGHeroInstance *Hero, int Index=0);
+
+	//To get a bit different texts for hero window
+	std::string getHoverText();
+	std::string getValueText();
+
+	bool prepareMessage(std::string &text, SComponent **comp);
+};
+
+class InfoBoxCustomHeroData : public InfoBoxAbstractHeroData
+{
+	int subID;//subID of data (0=attack...)
+	si64 value;//actual value of data, 64-bit to fit experience and negative values
+
+	int  getSubID();
+	si64 getValue();
+
+public:
+	InfoBoxCustomHeroData(InfoType Type, int subID, si64 value);
+};
+
+class InfoBoxCustom : public IInfoBoxData
+{
+public:
+	std::string valueText;
+	std::string nameText;
+	std::string imageName;
+	std::string hoverText;
+	size_t imageIndex;
+
+	InfoBoxCustom(std::string ValueText, std::string NameText, std::string ImageName, size_t ImageIndex, std::string HoverText="");
+
+	std::string getValueText();
+	std::string getNameText();
+	std::string getImageName(InfoBox::InfoSize size);
+	std::string getHoverText();
+	size_t getImageIndex();
+
+	bool prepareMessage(std::string &text, SComponent **comp);
+};
+
+//TODO!!!
+class InfoBoxTownData : public IInfoBoxData
+{
+	const CGTownInstance * town;
+	int index;//index of data in town
+	int value;//actual value of data
+
+public:
+	InfoBoxTownData(InfoType Type, const CGTownInstance * Town, int Index);
+	InfoBoxTownData(InfoType Type, int SubID, int Value);
+
+	std::string getValueText();
+	std::string getNameText();
+	std::string getImageName(InfoBox::InfoSize size);
+	std::string getHoverText();
+	size_t getImageIndex();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+/// Interface used in CTabbedInt and CListBox
+class IGuiObjectListManager
+{
+public:
+	//Create object for specified position, may return NULL if no object is needed at this position
+	//NOTE: position may be greater then size (empty rows in ListBox)
+	virtual CIntObject * getObject(size_t position)=0;
+
+	//Called when object needs to be removed
+	virtual void removeObject(CIntObject * object)
+	{
+		delete object;
+	};
+	virtual ~IGuiObjectListManager(){};
+};
+
+/// Used as base for Tabs and List classes
+class CObjectList : public CIntObject
+{
+	IGuiObjectListManager *manager;
+
+protected:
+	//Internal methods for safe creation of items (Children capturing and activation/deactivation if needed)
+	void deleteItem(CIntObject* item);
+	CIntObject* createItem(size_t index);
+
+public:
+	CObjectList(IGuiObjectListManager *Manager);
+	~CObjectList();
+};
+
+/// Window element with multiple tabs
+class CTabbedInt : public CObjectList
+{
+private:
+	CIntObject * activeTab;
+	size_t activeID;
+
+public:
+	//Manager - object which implements this interface, will be destroyed by TabbedInt
+	//Pos - position of object, all tabs will be moved here
+	//ActiveID - ID of initially active tab
+	CTabbedInt(IGuiObjectListManager *Manager, Point position=Point(), size_t ActiveID=0);
+
+	void setActive(size_t which);
+	//recreate active tab
+	void reset();
+
+	//return currently active item
+	CIntObject * getItem();
+};
+
+/// List of IntObjects with optional slider
+class CListBox : public CObjectList
+{
+private:
+	std::list< CIntObject* > items;
+	size_t first;
+	size_t totalSize;
+
+	Point itemOffset;
+	CSlider * slider;
+
+	void updatePositions();
+public:
+	//Manager - object which implements this interface, will be destroyed by ListBox
+	//Pos - position of first item
+	//ItemOffset - distance between items in the list
+	//VisibleSize - maximal number of displayable at once items
+	//TotalSize 
+	//Slider - slider style, bit field: 1 = present(disabled), 2=horisontal(vertical), 4=blue(brown)
+	//SliderPos - position of slider, if present
+	CListBox(IGuiObjectListManager *Manager, Point Pos, Point ItemOffset, size_t VisibleSize,
+	         size_t TotalSize, size_t InitialPos=0, int Slider=0, Rect SliderPos=Rect() );
+
+	//recreate all visible items
+	void reset();
+
+	//return currently active items
+	std::list< CIntObject * > getItems();
+
+	//scroll list
+	void moveToPos(size_t which);
+	void moveToNext();
+	void moveToPrev();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+/// Class which holds all parts of kingdom overview window
+class CKingdomInterface : public CGarrisonHolder, public CArtifactHolder
+{
+private:
+	CListBox * dwellingsList;
+	CTabbedInt * tabArea;
+	CPicture * background;
+
+	//Main buttons
+	AdventureMapButton *btnTowns;
+	AdventureMapButton *btnHeroes;
+	AdventureMapButton *btnExit;
+
+	//Buttons for scrolling dwellings list
+	AdventureMapButton *dwellUp, *dwellDown;
+	AdventureMapButton *dwellTop, *dwellBottom;
+
+	InfoBox * minesBox[7];
+
+	HoverableArea * incomeArea;
+	CLabel * incomeAmount;
+
+	CGStatusBar * statusbar;
+	CResDataBar *resdatabar;
+
+	void activateTab(size_t which);
+
+	//Internal functions used during construction
+	void generateButtons();
+	void generateObjectsList(const std::vector<const CGObjectInstance * > &ownedObjects);
+	void generateMinesList(const std::vector<const CGObjectInstance * > &ownedObjects);
+
+public:
+	CKingdomInterface();
+
+	void townChanged(const CGTownInstance *town);
+	void updateGarrisons();
+	void artifactRemoved(const ArtifactLocation &artLoc);
+	void artifactMoved(const ArtifactLocation &artLoc, const ArtifactLocation &destLoc);
+	void artifactDisassembled(const ArtifactLocation &artLoc);
+	void artifactAssembled(const ArtifactLocation &artLoc);
+};
+
+/// List item with town
+class CTownItem : public CGarrisonHolder
+{
+	CAnimImage *background;
+	CAnimImage *picture;
+	CLabel *name;
+	CLabel *income;
+	CGarrisonInt *garr;
+	LRClickableAreaOpenTown *townArea;
+
+	HeroSlots *heroes;
+	CTownInfo *hall, *fort;
+	std::vector<CCreaInfo*> available;
+	std::vector<CCreaInfo*> growth;
+
+public:
+	const CGTownInstance * town;
+
+	CTownItem(const CGTownInstance* town);
+
+	void updateGarrisons();
+	void update();
+};
+
+/// List item with hero
+class CHeroItem : public CWindowWithGarrison
+{
+	const CGHeroInstance * hero;
+
+	CAnimImage *background;
+	CAnimImage *portrait;
+	CLabel *name;
+	CHeroArea *heroArea;
+
+	CLabel *artsText;
+	CTabbedInt *artsTabs;
+
+	CHighlightableButtonsGroup *artButtons;
+	std::vector<InfoBox*> heroInfo;
+	MoraleLuckBox * morale, * luck;
+
+	void onArtChange(int tabIndex);
+
+public:
+	CArtifactsOfHero *heroArts;
+
+	CHeroItem(const CGHeroInstance* hero, CArtifactsOfHero::SCommonPart * artsCommonPart);
+};
+
+/// Tab with all hero-specific data
+class CKingdHeroList : public CGarrisonHolder, public CWindowWithArtifacts
+{
+private:
+	std::vector<CHeroItem*> heroItems;
+	CListBox * heroes;
+	CPicture * title;
+	CLabel * heroLabel;
+	CLabel * skillsLabel;
+
+public:
+	CKingdHeroList(size_t maxSize);
+
+	void updateGarrisons();
+};
+
+/// Tab with all town-specific data
+class CKingdTownList : public CGarrisonHolder
+{
+private:
+	std::vector<CTownItem*> townItems;
+	CListBox * towns;
+	CPicture * title;
+	CLabel * townLabel;
+	CLabel * garrHeroLabel;
+	CLabel * visitHeroLabel;
+	
+public:
+	CKingdTownList(size_t maxSize);
+	
+	void townChanged(const CGTownInstance *town);
+	void updateGarrisons();
+};

+ 18 - 1
client/CPlayerInterface.cpp

@@ -4,6 +4,7 @@
 #include "../CCallback.h"
 #include "CCastleInterface.h"
 #include "CCursorHandler.h"
+#include "CKingdomInterface.h"
 #include "CGameInfo.h"
 #include "CHeroWindow.h"
 #include "CMessage.h"
@@ -488,6 +489,15 @@ void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
 		c->garr->recreateSlots();
 		c->heroes->update();
 	}
+	BOOST_FOREACH(IShowActivable *isa, GH.listInt)
+	{
+		CKingdomInterface *ki = dynamic_cast<CKingdomInterface*>(isa);
+		if (ki)
+		{
+			ki->townChanged(town);
+			ki->updateGarrisons();
+		}
+	}
 	GH.totalRedraw();
 }
 void CPlayerInterface::heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town)
@@ -1032,11 +1042,18 @@ void CPlayerInterface::heroArtifactSetChanged(const CGHeroInstance*hero)
 void CPlayerInterface::availableCreaturesChanged( const CGDwelling *town )
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
-	if(castleInt && town->ID == TOWNI_TYPE)
+	if(const CGTownInstance * townObj = dynamic_cast<const CGTownInstance*>(town))
 	{
 		CFortScreen *fs = dynamic_cast<CFortScreen*>(GH.topInt());
 		if(fs)
 			fs->creaturesChanged();
+
+		BOOST_FOREACH(IShowActivable *isa, GH.listInt)
+		{
+			CKingdomInterface *ki = dynamic_cast<CKingdomInterface*>(isa);
+			if (ki && townObj)
+				ki->townChanged(townObj);
+		}
 	}
 	else if(GH.listInt.size() && (town->ID == 17  ||  town->ID == 20  ||  town->ID == 106)) //external dwelling
 	{

+ 7 - 4
client/GUIClasses.cpp

@@ -5409,10 +5409,13 @@ void CArtifactsOfHero::updateParentWindow()
 
 void CArtifactsOfHero::safeRedraw()
 {
-	if(parent)
-		parent->redraw();
-	else 
-		redraw();
+	if (active)
+	{
+		if(parent)
+			parent->redraw();
+		else 
+			redraw();
+	}
 }
 
 void CArtifactsOfHero::realizeCurrentTransaction()

+ 20 - 0
lib/JsonNode.cpp

@@ -5,6 +5,8 @@
 #include <fstream>
 #include <sstream>
 
+const JsonNode JsonNode::nullNode;
+
 JsonNode::JsonNode(JsonType Type):
 	type(DATA_NULL)
 {
@@ -76,6 +78,11 @@ void JsonNode::setType(JsonType Type)
 	}
 }
 
+bool JsonNode::isNull() const
+{
+	return type == DATA_NULL;
+}
+
 bool & JsonNode::Bool()
 {
 	setType(DATA_BOOL);
@@ -137,6 +144,19 @@ const JsonMap & JsonNode::Struct() const
 	return *data.Struct;
 }
 
+JsonNode & JsonNode::operator[](std::string child)
+{
+	return Struct()[child];
+}
+
+const JsonNode & JsonNode::operator[](std::string child) const
+{
+	JsonMap::const_iterator it = Struct().find(child);
+	if (it != Struct().end())
+		return it->second;
+	return nullNode;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 //Helper to write content of map/vector

+ 10 - 1
lib/JsonNode.h

@@ -41,7 +41,7 @@ public:
 	//Create empty node
 	JsonNode(JsonType Type = DATA_NULL);
 	//Create tree from Json-formatted input
-	JsonNode(std::string input);
+	explicit JsonNode(std::string input);
 	//Copy c-tor
 	JsonNode(const JsonNode &copy);
 
@@ -54,6 +54,8 @@ public:
 	void setType(JsonType Type);
 	JsonType getType() const;
 
+	bool isNull() const;
+
 	//non-const acessors, node will change type on type mismatch
 	bool & Bool();
 	int & Int();
@@ -72,6 +74,13 @@ public:
 
 	//formatted output of this node in JSON format
 	void write(std::ostream &out, std::string prefix="") const;
+
+	//operator [], for structs only - get child node by name
+	JsonNode & operator[](std::string child);
+	const JsonNode & operator[](std::string child) const;
+
+	//error value for const operator[]
+	static const JsonNode nullNode;
 };
 
 std::ostream & operator<<(std::ostream &out, const JsonNode &node);