diff --git a/Sprites/PortraitsLarge.json b/Sprites/PortraitsLarge.json new file mode 100644 index 000000000..9a74e7dc2 --- /dev/null +++ b/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"} + ] +} diff --git a/Sprites/PortraitsSmall.json b/Sprites/PortraitsSmall.json new file mode 100644 index 000000000..773fba725 --- /dev/null +++ b/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"} + ] +} diff --git a/client/CAnimation.cpp b/client/CAnimation.cpp index 91d328d68..a9a2b20c6 100644 --- a/client/CAnimation.cpp +++ b/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 } diff --git a/client/CKingdomInterface.cpp b/client/CKingdomInterface.cpp index 2f567f4ec..b8e9a10f1 100644 --- a/client/CKingdomInterface.cpp +++ b/client/CKingdomInterface.cpp @@ -1,39 +1,22 @@ #include "CKingdomInterface.h" -#include "AdventureMapButton.h" -#include "CAdvmapInterface.h" -#include "CPlayerInterface.h" -#include "CCreatureWindow.h" + +#include +#include +#include +#include +#include + #include "../CCallback.h" -#include "../global.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 "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 -#include -#include -#include -#include -#include -#include -#include "CBitmapHandler.h" - -using namespace boost::assign; -using namespace CSDL_Ext; +#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; + +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; + pos+=position; + + image = new CAnimImage(data->getImageName(size), data->getImageIndex()); + pos = image->pos; + + if (infoPos == POS_CORNER) + value = new CLabel(pos.w, pos.h, font, BOTTOMRIGHT, zwykly, data->getValueText()); + + if (infoPos == POS_INSIDE) + value = new CLabel(pos.w/2, pos.h-6, font, CENTER, zwykly, data->getValueText()); + + if (infoPos == POS_UP_DOWN || infoPos == POS_DOWN) + value = new CLabel(pos.w/2, pos.h+8, font, CENTER, zwykly, data->getValueText()); + + if (infoPos == POS_UP_DOWN) + name = new CLabel(pos.w/2, -12, font, CENTER, zwykly, data->getNameText()); + + if (infoPos == POS_RIGHT) + { + 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; +} + +InfoBox::~InfoBox() +{ + delete data; +} + +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); + } +} + +void InfoBox::clickLeft(tribool down, bool previousState) +{ + if((!down) && previousState) + { + SComponent *comp; + std::string text; + data->prepareMessage(text, &comp); + + std::vector compVector; + if (comp) + compVector.push_back(comp); + LOCPLINT->showInfoDialog(text, compVector); + } +} + +//TODO? +/* +void InfoBox::update() +{ + +} +*/ + +IInfoBoxData::IInfoBoxData(InfoType Type): + type(Type) +{ +} + +InfoBoxAbstractHeroData::InfoBoxAbstractHeroData(InfoType Type): + IInfoBoxData(Type) +{ +} + +std::string InfoBoxAbstractHeroData::getValueText() +{ + switch (type) + { + case HERO_MANA: + case HERO_EXPERIENCE: + case HERO_PRIMARY_SKILL: + return boost::lexical_cast(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 ""; +} + +std::string InfoBoxAbstractHeroData::getNameText() +{ + switch (type) + { + case HERO_PRIMARY_SKILL: + return CGI->generaltexth->primarySkillNames[getSubID()]; + case HERO_MANA: + return CGI->generaltexth->allTexts[387]; + case HERO_EXPERIENCE: + { + std::string text = CGI->generaltexth->jktexts[6]; + size_t begin = text.find('{'); + size_t end = text.find('}', begin); + return text.substr(begin, end-begin); + } + 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); + } + return ""; +} + +std::string InfoBoxAbstractHeroData::getImageName(InfoBox::InfoSize size) +{ + //TODO: sizes + switch(size) + { + 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); + } + return ""; +} + +std::string InfoBoxAbstractHeroData::getHoverText() +{ + //TODO: any texts here? + return ""; +} + +size_t InfoBoxAbstractHeroData::getImageIndex() +{ + 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; + } +} + +bool InfoBoxAbstractHeroData::prepareMessage(std::string &text, SComponent **comp) +{ + 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; + } +} + +InfoBoxHeroData::InfoBoxHeroData(InfoType Type, const CGHeroInstance * Hero, int Index): + InfoBoxAbstractHeroData(Type), + hero(Hero), + index(Index) +{ +} + +int InfoBoxHeroData::getSubID() +{ + switch(type) + { + 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; + } +} + +si64 InfoBoxHeroData::getValue() +{ + switch(type) + { + 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; + } +} + +std::string InfoBoxHeroData::getHoverText() +{ + switch (type) + { + 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(); + } +} + +std::string InfoBoxHeroData::getValueText() +{ + switch (type) + { + case HERO_MANA: + if (hero) + return boost::lexical_cast(hero->mana) + '/' + + boost::lexical_cast(hero->manaLimit()); + case HERO_EXPERIENCE: + return boost::lexical_cast(hero->exp); + default: + return InfoBoxAbstractHeroData::getValueText(); + } +} + +bool InfoBoxHeroData::prepareMessage(std::string &text, SComponent**comp) +{ + switch(type) + { + case HERO_MANA: + text = CGI->generaltexth->allTexts[205]; + boost::replace_first(text, "%s", boost::lexical_cast(hero->name)); + boost::replace_first(text, "%d", boost::lexical_cast(hero->mana)); + boost::replace_first(text, "%d", boost::lexical_cast(hero->manaLimit())); + *comp = NULL; + return true; + + case HERO_EXPERIENCE: + text = CGI->generaltexth->allTexts[2]; + boost::replace_first(text, "%d", boost::lexical_cast(hero->level)); + boost::replace_first(text, "%d", boost::lexical_cast(CGI->heroh->reqExp(hero->level+1))); + boost::replace_first(text, "%d", boost::lexical_cast(hero->exp)); + *comp = NULL; + return true; + + default: + return InfoBoxAbstractHeroData::prepareMessage(text, comp); + } +} + +InfoBoxCustomHeroData::InfoBoxCustomHeroData(InfoType Type, int SubID, si64 Value): + InfoBoxAbstractHeroData(Type), + subID(SubID), + value(Value) +{ +} + +int InfoBoxCustomHeroData::getSubID() +{ + return subID; +} + +si64 InfoBoxCustomHeroData::getValue() +{ + return value; +} + +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) +{ +} + +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; +} + +bool InfoBoxCustom::prepareMessage(std::string &text, SComponent **comp) +{ + return false; +} + +CObjectList::CObjectList(IGuiObjectListManager *Manager): + manager(Manager) +{ +} + +CObjectList::~CObjectList() +{ + delete manager; +} + +void CObjectList::deleteItem(CIntObject* item) +{ + if (!item) + return; + if (active) + item->deactivate(); + removeChild(item); + manager->removeObject(item); +} + +CIntObject* CObjectList::createItem(size_t index) +{ + OBJ_CONSTRUCTION_CAPTURING_ALL; + CIntObject * item = manager->getObject(index); + if (item == NULL) + item = new CIntObject(); + + item->recActions = defActions; + + //May happen if object was created before call to getObject() + if(item->parent != this) + { + if (item->parent) + moveChild(item, item->parent, this); + else + addChild(item); + } + + 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(); +} + +void CTabbedInt::setActive(size_t which) +{ + if (which != activeID) + { + activeID = which; + reset(); + } +} + +void CTabbedInt::reset() +{ + deleteItem(activeTab); + activeTab = createItem(activeID); + activeTab->moveTo(pos.topLeft()); + + if (active) + redraw(); +} + +CIntObject * CTabbedInt::getItem() +{ + return activeTab; +} + +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); + + 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(); +} + +// Used to move active items after changing list position +void CListBox::updatePositions() +{ + Point itemPos = pos.topLeft(); + for (std::list::iterator it = items.begin(); it!=items.end(); it++) + { + (*it)->moveTo(itemPos); + itemPos += itemOffset; + } + if (active) + { + redraw(); + if (slider) + slider->moveTo(first); + } +} + +void CListBox::reset() +{ + size_t current = first; + for (std::list::iterator it = items.begin(); it!=items.end(); it++) + { + deleteItem(*it); + *it = createItem(current++); + } + updatePositions(); +} + +void CListBox::moveToPos(size_t which) +{ + //Calculate new position + size_t maxPossible; + if (totalSize > items.size()) + maxPossible = totalSize - items.size(); + else + maxPossible = 0; + + size_t newPos = std::min(which, maxPossible); + + //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) + { + first = newPos; + reset(); + } +} + +void CListBox::moveToNext() +{ + //Remove front item and insert new one to end + if (first + items.size() < totalSize) + { + first++; + deleteItem(items.front()); + items.pop_front(); + items.push_back(createItem(first+items.size())); + updatePositions(); + } +} + +void CListBox::moveToPrev() +{ + //Remove last item and insert new one at start + if (first) + { + first--; + deleteItem(items.back()); + items.pop_back(); + items.push_front(createItem(first)); + updatePositions(); + } +} + +std::list CListBox::getItems() +{ + return items; +} + +struct OwnedObjectInfo +{ + int imageID; + unsigned int count; + std::string hoverText; +}; + +class OwnedObjectsListManager : public IGuiObjectListManager +{ + std::vector objects; +public: + virtual CIntObject * getObject(size_t position) + { + if (position < objects.size()) + { + OwnedObjectInfo &obj = objects[position]; + std::string value = boost::lexical_cast(obj.count); + return new InfoBox(Point(), InfoBox::POS_CORNER, InfoBox::SIZE_SMALL, + new InfoBoxCustom(value,"", "FLAGPORT", obj.imageID, obj.hoverText)); + } + return NULL; + } + + OwnedObjectsListManager(std::vector Objects): + objects(Objects) + { + } +}; + +class TownHeroListManager : public IGuiObjectListManager +{ +public: + CIntObject *currentItem; + + CIntObject *getObject(size_t position) + { + size_t size = conf.go()->ac.overviewSize; + switch (position) + { + case 0: + return new CKingdHeroList(size); + case 1: + return new CKingdTownList(size); + default: + return NULL; + } + } +}; CKingdomInterface::CKingdomInterface() { 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; + background = new CPicture(conf.go()->ac.overviewBg); + background->colorize(LOCPLINT->playerID); + pos = background->center(); + unsigned int footerPos = conf.go()->ac.overviewSize * 116; - bg = BitmapHandler::loadBitmap(ADVOPT.overviewBg); - graphics->blueToPlayersAdv(bg, LOCPLINT->playerID); + tabArea = new CTabbedInt(new TownHeroListManager, Point(4,4)); - 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"); + std::vector ownedObjects = LOCPLINT->cb->getMyObjects(); + generateObjectsList(ownedObjects); + generateMinesList(ownedObjects); + generateButtons(); - toHeroes = new AdventureMapButton (CGI->generaltexth->overview[11],"", - boost::bind(&CKingdomInterface::listToHeroes,this),748,28+size*116,"OVBUTN1.DEF", SDLK_h); - toHeroes->block(2); + statusbar = new CGStatusBar(new CPicture("KSTATBAR", 10,pos.h - 45)); + resdatabar= new CResDataBar("KRESBAR", 3, 111+footerPos, 32, 2, 76, 76); +} - toTowns = new AdventureMapButton (CGI->generaltexth->overview[12],"", - boost::bind(&CKingdomInterface::listToTowns,this),748,64+size*116,"OVBUTN6.DEF", SDLK_t); - toTowns->block(0); +void CKingdomInterface::generateObjectsList(const std::vector &ownedObjects) +{ + unsigned int footerPos = conf.go()->ac.overviewSize * 116; + size_t dwellSize = (footerPos - 64)/57; - exit = new AdventureMapButton (CGI->generaltexth->allTexts[600],"", - boost::bind(&CKingdomInterface::close,this),748,99+size*116,"OVBUTN1.DEF", SDLK_RETURN); - exit->setOffset(3); + //Map used to determine image number for several objects + std::map,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 - 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 visibleObjects; + BOOST_FOREACH(const CGObjectInstance * object, ownedObjects) { - heroes.push_back( new CHeroItem(i,this)); - towns.push_back( new CTownItem(i,this)); - } - - slider = new CSlider(4, 4, size*116+19, boost::bind (&CKingdomInterface::sliderMoved, this, _1), - size, LOCPLINT->cb->howManyHeroes(showHarrisoned), 0, false, 0); - - //creating objects list - ObjTop = new AdventureMapButton ("","", boost::bind(&CKingdomInterface::moveObjectList,this,0), - 733,4,"OVBUTN4.DEF"); - - ObjUp = new AdventureMapButton ("","", boost::bind(&CKingdomInterface::moveObjectList,this,1), - 733,24,"OVBUTN4.DEF"); - ObjUp->setOffset(4); - - ObjDown = new AdventureMapButton ("","", boost::bind(&CKingdomInterface::moveObjectList,this,2), - 733,size*116-18,"OVBUTN4.DEF"); - ObjDown->setOffset(6); - - ObjBottom = new AdventureMapButton ("","", boost::bind(&CKingdomInterface::moveObjectList,this,3), - 733,size*116+2,"OVBUTN4.DEF"); - ObjBottom->setOffset(2); - - for (size_t i=0; i<8; i++) - { - 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,int> addObjects;//objects to print, except 17th dwelling - //format: (id,subID),image index - #define INSERT_MAP addObjects.insert(std::pair,int>(std::pair - 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 myObjects = LOCPLINT->cb->getMyObjects(); - for(size_t i = 0; iID == 17 ) { - std::pair curElm = std::pair(obj->ID, obj->subID); - if ( obj->ID == 17 )//dwelling, text is a plural name of a creature + OwnedObjectInfo &info = visibleObjects[object->subID]; + if (info.count++ == 0) { - objList[obj->subID].first += 1; - objList[obj->subID].second = & CGI->creh->creatures[CGI->objh->cregens[obj->subID]]->namePl; + info.hoverText = CGI->creh->creatures[CGI->objh->cregens[object->subID]]->namePl; + info.imageID = object->subID; } - 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; + } + //Special objects from idToImage map that should be displayed in objects list + std::map,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; } - else if ( obj->ID == 53 ) - incomesVal[obj->subID]+=1; + } + } + std::vector objectsVector; + objectsVector.reserve(visibleObjects.size()); + + std::pair 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::generateMinesList(const std::vector &ownedObjects) +{ + unsigned int footerPos = conf.go()->ac.overviewSize * 116; + std::vector minesCount(RESOURCE_QUANTITY, 0); + int totalIncome=0; + + BOOST_FOREACH(const CGObjectInstance * object, ownedObjects) + { + //Mines + if ( object->ID == 53 ) + { + const CGMine *mine = dynamic_cast(object); + assert(mine); + minesCount[mine->producedResource]++; + + if (mine->producedResource == Res::GOLD) + totalIncome += mine->producedQuantity; } } - 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;ipos = genRect(50,50,pos.x+740,pos.y+44+i*57); - } - - incomesVal[7] = incomesVal[6]*1000;//gold mines -> total income + //Heroes can produce gold as well - skill, speciality or arts std::vector heroes = LOCPLINT->cb->getHeroesInfo(true); - for(size_t i=0; ivalOfBonuses(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, CGHeroInstance::ESTATES)); - incomesVal[7] += heroes[i]->valOfBonuses(Selector::typeSubtype(Bonus::GENERATE_RESOURCE, Res::GOLD)); - } - std::vector towns = LOCPLINT->cb->getTownsInfo(true); - for(size_t i=0; idailyIncome(); -} - -void CKingdomInterface::moveObjectList(int newPos) -{ - 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 + for(size_t i=0; ivalOfBonuses(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, CGHeroInstance::ESTATES)); + totalIncome += heroes[i]->valOfBonuses(Selector::typeSubtype(Bonus::GENERATE_RESOURCE, Res::GOLD)); } - showAll(screen2); + + //Add town income of all towns + std::vector towns = LOCPLINT->cb->getTownsInfo(true); + for(size_t i=0; idailyIncome(); + } + for (int i=0; i<7; i++) + { + std::string value = boost::lexical_cast(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(totalIncome)); } -CKingdomInterface::~CKingdomInterface() +void CKingdomInterface::generateButtons() { - SDL_FreeSurface(bg); + unsigned int footerPos = conf.go()->ac.overviewSize * 116; - delete title;//deleting .def - delete slots; - delete fort; - delete hall; - delete objPics; - delete mines; + //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); - towns.clear();//deleting lists - heroes.clear(); - incomes.clear(); - ObjList.clear(); - objList.clear(); + 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::close() +void CKingdomInterface::activateTab(size_t which) { - GH.popIntTotally(this); + btnHeroes->block(which == 0); + btnTowns->block(which == 1); + tabArea->setActive(which); +} + +void CKingdomInterface::townChanged(const CGTownInstance *town) +{ + if (CKingdTownList * townList = dynamic_cast(tabArea->getItem())) + townList->townChanged(town); } void CKingdomInterface::updateGarrisons() { - for (int i = 0; igarr) - towns[i]->garr->recreateSlots(); - } - for (int i = 0; igarr) - heroes[i]->garr->recreateSlots(); - } + if (CGarrisonHolder * garrison = dynamic_cast(tabArea->getItem())) + garrison->updateGarrisons(); } -void CKingdomInterface::showAll( SDL_Surface * to/*=NULL*/) +void CKingdomInterface::artifactAssembled(const ArtifactLocation& artLoc) { - adventureInt->resdatabar.draw(to); - blitAt(bg,pos,to); - resdatabar->draw(to); - toTowns->showAll(to); - toHeroes->showAll(to); - exit->showAll(to); + if (CArtifactHolder * arts = dynamic_cast(tabArea->getItem())) + arts->artifactAssembled(artLoc); +} - ObjTop->showAll(to); - ObjUp->showAll(to); - ObjDown->showAll(to); - ObjBottom->showAll(to); +void CKingdomInterface::artifactDisassembled(const ArtifactLocation& artLoc) +{ + if (CArtifactHolder * arts = dynamic_cast(tabArea->getItem())) + arts->artifactDisassembled(artLoc); +} - for (size_t i=0; ihoverText = ""; +void CKingdomInterface::artifactMoved(const ArtifactLocation& artLoc, const ArtifactLocation& destLoc) +{ + if (CArtifactHolder * arts = dynamic_cast(tabArea->getItem())) + arts->artifactMoved(artLoc, destLoc); +} - int skipCount=0, curPos=objPos<0?(-objPos):0; - for (std::map >::iterator it=objList.begin(); it!= objList.end(); it++) +void CKingdomInterface::artifactRemoved(const ArtifactLocation& artLoc) +{ + if (CArtifactHolder * arts = dynamic_cast(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) { - if (skipCountourImages[(*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; ishowAll(to);//show town list + CHeroItem * hero = new CHeroItem(LOCPLINT->cb->getHeroBySerial(position, false), artsCommonPart); + artsCommonPart->participants.insert(hero->heroArts); + arts->artSets.push_back(hero->heroArts); + return hero; } 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; ishowAll(to);//show hero list - } - for (int i = 0; i<7; i++) - blitAt(mines->ourImages[i].bitmap,pos.x + 20 + i*80,pos.y + 31+size*116,to); - - for(size_t i=0;ipos.x+incomes[i]->pos.w/2,incomes[i]->pos.y+50,FONT_SMALL,zwykly,to); + return new CAnimImage("OVSLOT", (position-2) % picCount ); } +}; - 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); -} - -void CKingdomInterface::show(SDL_Surface * to) +void HeroListManager::removeObject(CIntObject *object) { - statusbar->show(to); -} - -void CKingdomInterface::activate() -{ - GH.statusbar = statusbar; - exit->activate(); - toTowns->activate(); - toHeroes->activate(); - - ObjTop->activate(); - ObjUp->activate(); - ObjDown->activate(); - ObjBottom->activate(); - - for (size_t i=0; iactivate(); - - for (size_t i=0; iactivate(); - if (state == 1) - for (size_t i=0; iactivate(); - else - for (size_t i=0; iactivate(); - - slider->activate(); -} - -void CKingdomInterface::deactivate() -{ - exit->deactivate(); - toTowns->deactivate(); - toHeroes->deactivate(); - - ObjTop->deactivate(); - ObjUp->deactivate(); - ObjDown->deactivate(); - ObjBottom->deactivate(); - - for (size_t i=0; ideactivate(); - - for (size_t i=0; ideactivate(); - - if (state == 1) - for (size_t i=0; ideactivate(); - else - for (size_t i=0; ideactivate(); - slider->deactivate(); -} - -void CKingdomInterface::recreateHeroList(int pos) -{ - std::vector Heroes = LOCPLINT->cb->getHeroesInfo(true); - int i=0, cnt=0; - for (size_t j = 0; ((j(object)) { - if (Heroes[j]->inTownGarrison && (!showHarrisoned))//if hero in garrison and we don't show them - continue; - if (cntsetHero(Heroes[j]); - i++; + arts->artSets.erase(std::find(arts->artSets.begin(), arts->artSets.end(), hero->heroArts)); + artsCommonPart->participants.erase(hero->heroArts); } - for (;isetHero(NULL);//empty pic + delete object; } -void CKingdomInterface::recreateTownList(int pos) -{ - std::vector Towns = LOCPLINT->cb->getTownsInfo(false); - for(size_t i=0;icb->howManyTowns()) - towns[i]->setTown(Towns[i+pos]);//replace town - else - towns[i]->setTown(NULL);//only empty pic - } -} - -void CKingdomInterface::listToTowns() -{ - 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;ideactivate(); - towns[i]->activate(); - } - showAll(screen2); -} - -void CKingdomInterface::listToHeroes() -{ - 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;ideactivate(); - heroes[i]->activate(); - } - showAll(screen2); -} - -void CKingdomInterface::sliderMoved(int newpos) -{ - if (state == 0) - { - townPos = newpos; - recreateHeroList(newpos); - state = 2; - } - else if ( state == 1 )//towns - { - for (size_t i=0; ideactivate(); - townPos = newpos; - recreateTownList(newpos); - for (size_t i=0; iactivate(); - showAll(screen2); - } - else//heroes - { - for (size_t i=0; ideactivate(); - heroPos = newpos; - recreateHeroList(newpos); - for (size_t i=0; iactivate(); - showAll(screen2); - } -} - -CKingdomInterface::CTownItem::CTownItem(int num, CKingdomInterface * Owner) -{ - 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; ipos = genRect(32, 32, pos.x+56+i*37, pos.y + 78); - - 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; - - fortArea = new LRClickableAreaOpenTown(); - fortArea->pos = genRect(38, 38, pos.x+111, pos.y + 31); - fortArea->type = 3; - - townImage = new LRClickableAreaOpenTown(); - townImage->pos = genRect(64, 58, pos.x+5, pos.y + 6); - townImage->type = 1; - - incomeArea = new HoverableArea(); - incomeArea->pos = genRect(42, 64, pos.x+154, pos.y + 31); - incomeArea->hoverText = CGI->generaltexth->allTexts[255]; - -} - -CKingdomInterface::CTownItem::~CTownItem() -{ - creaGrowth.clear(); - creaCount.clear(); - delete garr; -} - -void CKingdomInterface::CTownItem::setTown(const CGTownInstance * newTown) -{ - BLOCK_CAPTURING; - delete garr; - town = newTown; - if (!town) - { - 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; - - for (int i=0; itown = NULL; - - int crid = -1; - - if (vstd::contains(town->builtBuildings,30+i+CREATURES_PER_TOWN)) - crid = town->town->upgradedCreatures[i]; - 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; - } - - townImage->hoverText = town->name; - townImage->town = town; - hallArea->town = town; - - hallArea->hoverText = CGI->buildh->buildings[town->subID][10+town->hallLevel()]->Name(); - if (town->hasFort()) - { - fortArea->hoverText = CGI->buildh->buildings[town->subID][6+town->fortLevel()]->Name(); - fortArea->town = town; - } - else - fortArea->hoverText = ""; -} - -void CKingdomInterface::CTownItem::activate() -{ - if (!town) - return; - - setTown(town); - hallArea->activate(); - fortArea->activate(); - incomeArea->activate(); - townImage->activate(); - - garrHero->activate(); - visitHero->activate(); - - for (int i=0; ibuiltBuildings,30+i)) - { - creaGrowth[i]->activate(); - creaCount [i]->activate(); - } - garr->activate(); -} - -void CKingdomInterface::CTownItem::deactivate() -{ - if (!town) - return; - - hallArea->deactivate(); - fortArea->deactivate(); - incomeArea->deactivate(); - townImage->deactivate(); - - garrHero->deactivate(); - visitHero->deactivate(); - - for (int i=0; iactive) - { - creaGrowth[i]->deactivate(); - creaCount [i]->deactivate(); - } - garr->deactivate(); -} - -void CKingdomInterface::CTownItem::showAll(SDL_Surface * to) -{ - 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 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; ibuiltBuildings,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); - } - - garrHero->showAll(to); - visitHero->showAll(to); -} - -CKingdomInterface::CHeroItem::CHeroItem(int num, CKingdomInterface * Owner) +CKingdHeroList::CKingdHeroList(size_t maxSize) { 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; + 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 CKingdHeroList::updateGarrisons() +{ + std::list list = heroes->getItems(); + BOOST_FOREACH(CIntObject* object, list) + { + if (CGarrisonHolder * garrison = dynamic_cast(object) ) + garrison->updateGarrisons(); + } +} + +class TownListManager : public IGuiObjectListManager +{ +public: + CIntObject * getObject(size_t position) + { + unsigned int picCount = conf.go()->ac.overviewPics; + size_t townsCount = LOCPLINT->cb->howManyTowns(); + + if (position < townsCount) + return new CTownItem(LOCPLINT->cb->getTownBySerial(position)); + else + return new CAnimImage("OVSLOT", (position-2) % picCount ); + } +}; + +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) ); +} + +void CKingdTownList::townChanged(const CGTownInstance *town) +{ + std::list list = towns->getItems(); + BOOST_FOREACH(CIntObject* object, list) + { + CTownItem * townItem = dynamic_cast(object); + if ( townItem && townItem->town == town) + townItem->update(); + } +} + +void CKingdTownList::updateGarrisons() +{ + std::list list = towns->getItems(); + BOOST_FOREACH(CIntObject* object, list) + { + if (CGarrisonHolder * garrison = dynamic_cast(object) ) + garrison->updateGarrisons(); + } +} + +CTownItem::CTownItem(const CGTownInstance* Town): + town(Town) +{ + 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(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; icreatures.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 CTownItem::updateGarrisons() +{ + garr->highlighted = NULL; + garr->setArmy(town->getUpperArmy(), 0); + garr->setArmy(town->visitingHero, 1); + garr->recreateSlots(); +} + +void CTownItem::update() +{ + std::string incomeVal = boost::lexical_cast(town->dailyIncome()); + if (incomeVal != income->text) + income->setTxt(incomeVal); + + heroes->update(); + + for (size_t i=0; icreatures.size(); i++) + { + growth[i]->update(); + available[i]->update(); + } +} + +class ArtSlotsTab : public CIntObject +{ +public: + CAnimImage * background; + std::vector 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))); + } +}; + +class BackpackTab : public CIntObject +{ +public: + CAnimImage * background; + std::vector 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(), 269, 66, "HSBTNS3"); + btnRight = new AdventureMapButton(std::string(), std::string(), CFunctionList(), 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); +}; + +HeroItemManager::HeroItemManager(const CGHeroInstance* Hero) +{ + OBJ_CONSTRUCTION_CAPTURING_ALL; + recActions = 0; + defActions = DISPOSE | SHARE_POS; + + tab1 = new ArtSlotsTab; + tab2 = new ArtSlotsTab; + tab3 = new BackpackTab; +} + +CIntObject * HeroItemManager::getObject(size_t position) +{ + switch (position) + { + case 0: return tab1; + case 1: return tab2; + case 2: return tab3; + default: assert(0); + return NULL; + } +} + +void HeroItemManager::removeObject(CIntObject * object) +{ + addChild(object, false); +} + +CHeroItem::CHeroItem(const CGHeroInstance* Hero, CArtifactsOfHero::SCommonPart * artsCommonPart): + hero(Hero) +{ + OBJ_CONSTRUCTION_CAPTURING_ALL; + + name = new CLabel(75, 7, FONT_SMALL, TOPLEFT, zwykly, hero->name); + + HeroItemManager *manager = new HeroItemManager(hero); + + std::vector 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++) { - 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); + std::map 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(&CKingdomInterface::CHeroItem::onArtChange, this, _1); + artButtons->onChange += boost::bind(&CTabbedInt::setActive, artsTabs, _1); + artButtons->onChange += boost::bind(&CHeroItem::onArtChange, this, _1); artButtons->select(0,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); + garr = new CGarrisonInt(6, 78, 4, Point(), NULL, Point(), hero, NULL, true, true); - portrait = new CHeroArea(5,5,NULL); - char bufor[400]; - for(int i=0; itext = 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]; + portrait = new CAnimImage("PortraitsLarge", hero->subID, 0, 5, 6); + heroArea = new CHeroArea(5, 6, hero); - 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)); + name = new CLabel(73, 7, FONT_SMALL, TOPLEFT, zwykly, hero->name); + artsText = new CLabel(320, 55, FONT_SMALL, CENTER, zwykly, CGI->generaltexth->overview[2]); - spellPoints = new LRClickableAreaWText(); - spellPoints->pos = genRect(33, 49, pos.x+270, pos.y+5); - spellPoints->hoverText = CGI->generaltexth->heroscrn[22]; + for (size_t i=0; ipos = genRect(32, 32, pos.x+374, pos.y+5); - speciality->hoverText = CGI->generaltexth->heroscrn[27]; + for (size_t i=0; iblock(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); + morale = new MoraleLuckBox(true, Rect(225, 53, 30, 22), true); + luck = new MoraleLuckBox(false, Rect(225, 28, 30, 22), true); - for (int i=0; itype = hero->getArtTypeId(i); - if (artifacts[i]->type<0 || artifacts[i]->type == 145 ) - artifacts[i]->hoverText = CGI->generaltexth->heroscrn[11]; - else - { - 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()); - } - } - - for (int i=0; itype = hero->getArtTypeId(19+i); - if (backpack[i]->type<0) - backpack[i]->hoverText =""; - else - { - 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()); - } - } - - //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; - - speciality->text = CGI->generaltexth->hTxts[hero->subID].longBonus; - - //primary skills - for(size_t g=0; gbonusValue = hero->getPrimSkillLevel(g); - - //secondary skills - for(size_t g=0; gsecSkills.size()); ++g) - { - 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); - } - //experience - experience->text = CGI->generaltexth->allTexts[2].c_str(); - boost::replace_first(experience->text, "%d", boost::lexical_cast(hero->level)); - boost::replace_first(experience->text, "%d", boost::lexical_cast(CGI->heroh->reqExp(hero->level+1))); - boost::replace_first(experience->text, "%d", boost::lexical_cast(hero->exp)); - - //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); } -void CKingdomInterface::CHeroItem::scrollArts(int move) +void CHeroItem::onArtChange(int tabIndex) { - backpackPos = ( backpackPos + move + hero->artifactsInBackpack.size()) % hero->artifactsInBackpack.size(); - for (int i=0; itype = hero->getArtTypeId(19+(backpackPos + i)%hero->artifactsInBackpack.size()); - if (backpack[i]->type<0) - backpack[i]->hoverText =""; - else - { - 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()); - } - } - 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); - } - {//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); - } - //hero speciality - blitAt(graphics->un32->ourImages[hero->subID].bitmap, pos.x+375, pos.y+6, to); - - for(int i=0; isecSkills.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); - } - - artButtons->show(to); - - int iter=0; - switch (artGroup) - {//arts - case 1:iter = 9;//misc. arts, spellbook, war machines - case 0://equipped arts - /*for (int i = iter ; igetArtTypeId(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 ; itartDefs->ourImages[hero->artifacts[(it+backpackPos)%max]->id].bitmap,pos.x+293+48*it,pos.y+66,to); - */break; - } - show(to); -} - -void CKingdomInterface::CHeroItem::onArtChange(int newstate) -{ - if (!hero) - return; - deactivate(); - artGroup = newstate; - activate(); - showAll(screen2); -} - -void CKingdomInterface::CHeroItem::activate() -{ - setHero(hero); - if (!hero) - return; - artButtons->activate(); - garr->activate();/* - if ( artGroup == 2 ) - { - artLeft->activate(); - artRight->activate(); - for (size_t i=0; i<8;i++) - backpack[i]->activate(); - } - 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(); - - for (size_t i=0; iactivate(); - - for (size_t i=0; isecSkills.size());i++) - secondarySkills[i]->activate(); -} - -void CKingdomInterface::CHeroItem::deactivate() -{ - if (!hero) - return; - artButtons->deactivate(); - garr->deactivate();/* - if ( artGroup == 2 ) - { - artLeft->deactivate(); - artRight->deactivate(); - for (size_t i=0; i<8;i++) - backpack[i]->deactivate(); - } - else - { - for (size_t i=artGroup*9; i<9+artGroup*9;i++) - artifacts[i]->deactivate(); - }*/ - - portrait->deactivate(); - experience->deactivate(); - morale->deactivate(); - luck->deactivate(); - spellPoints->deactivate(); - speciality->deactivate(); - for (size_t i=0; ideactivate(); - - for (size_t i=0; isecSkills.size());i++) - secondarySkills[i]->deactivate(); -} - -CKingdomInterface::CHeroItem::CArtPlace::CArtPlace(CHeroItem * owner, const Rect &r) - : LRClickableAreaWTextComp(r, SComponent::artifact) -{ - parent = owner; - used = LCLICK | RCLICK | HOVER; -} - -void CKingdomInterface::CHeroItem::CArtPlace::activate() -{ - LRClickableAreaWTextComp::activate(); -} - -void CKingdomInterface::CHeroItem::CArtPlace::clickLeft(tribool down, bool previousState) -{ - if (!down && previousState && type>=0 && type < 145) - {tlog1<w - 620)/2, (screen->h - 595)/2), parent->hero, LOCPLINT, false); - GH.pushInt(spellWindow); - } - else - LRClickableAreaWTextComp::clickLeft(down,previousState); - } -} - -void CKingdomInterface::CHeroItem::CArtPlace::clickRight(tribool down, bool previousState) -{ - if (type>=0 && type < 145) - LRClickableAreaWTextComp::clickRight(down, previousState); -} - -void CKingdomInterface::CHeroItem::CArtPlace::deactivate() -{ - LRClickableAreaWTextComp::deactivate(); -} - - -CKingdomInterface::CTownItem::CCreaPlace::CCreaPlace() - : LRClickableAreaWTextComp(Rect(0,0,0,0), -1) -{ - town = NULL; - used = LCLICK | RCLICK | HOVER; -} - -void CKingdomInterface::CTownItem::CCreaPlace::activate() -{ - LRClickableAreaWTextComp::activate(); -} - -void CKingdomInterface::CTownItem::CCreaPlace::clickLeft(tribool down, bool previousState) -{ - if (!down && previousState && town) - { - GH.pushInt (new CRecruitmentWindow(town, type, town, boost::bind - (&CCallback::recruitCreatures,LOCPLINT->cb,town,_1,_2, type))); - } -} - -void CKingdomInterface::CTownItem::CCreaPlace::clickRight(tribool down, bool previousState) -{ - if (down && town) - { - 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)); - } -} - -void CKingdomInterface::CTownItem::CCreaPlace::deactivate() -{ - LRClickableAreaWTextComp::deactivate(); + //redraw item after background change + if (active) + redraw(); } diff --git a/client/CKingdomInterface.h b/client/CKingdomInterface.h index 5f2a6a977..d7d17a27e 100644 --- a/client/CKingdomInterface.h +++ b/client/CKingdomInterface.h @@ -1,19 +1,20 @@ -#ifndef __CKINGDOMINTERFACE_H__ -#define __CKINGDOMINTERFACE_H__ - +#pragma once #include "../global.h" + +#include + #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 - { - 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 - }; - class CHeroItem : public CWindowWithGarrison - { - 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 primarySkills; - std::vector secondarySkills; - std::vector artifacts; - std::vector 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 - }; public: - //common data - int state;//1 = towns showed, 2 = heroes; - SDL_Surface * bg;//background - CStatusBar * statusbar;//statusbar - CResDataBar *resdatabar;//resources - int size,PicCount; + enum InfoPos + { + POS_UP_DOWN, POS_DOWN, POS_RIGHT, POS_INSIDE, POS_CORNER, POS_NONE + }; + enum InfoSize + { + SIZE_TINY, SIZE_SMALL, SIZE_MEDIUM, SIZE_BIG, SIZE_HUGE + }; - //buttons - AdventureMapButton *exit;//exit button - AdventureMapButton *toTowns;//town button - AdventureMapButton *toHeroes;//hero button - CDefEssential * title; //title bar +private: + InfoSize size; + InfoPos infoPos; + IInfoBoxData *data; - //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 heroes;//heroes list - std::vector towns;//towns list - CDefEssential * slots, *fort, *hall; + CLabel * value; + CLabel * name; + CAnimImage * image; + HoverableArea *hover; - //objects list - int objSize, objPos; - CDefEssential *objPics; - std::map > objList; //dwelling ID, count, hover text - std::vector ObjList;//list of dwellings - AdventureMapButton* ObjUp, *ObjDown, *ObjTop, *ObjBottom;//buttons for dwellings list +public: + InfoBox(Point position, InfoPos Pos, InfoSize Size, IInfoBoxData *Data); + ~InfoBox(); - //income pics - std::vector incomes;//mines + incomes - std::vector incomesVal;//values to print - CDefEssential * mines; + void clickRight(tribool down, bool previousState); + void clickLeft(tribool down, bool previousState); - 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(); + //Update object if data may have changed + //void update(); }; -#endif // __CCASTLEINTERFACE_H__ +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: + 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 &ownedObjects); + void generateMinesList(const std::vector &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 available; + std::vector 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 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 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 townItems; + CListBox * towns; + CPicture * title; + CLabel * townLabel; + CLabel * garrHeroLabel; + CLabel * visitHeroLabel; + +public: + CKingdTownList(size_t maxSize); + + void townChanged(const CGTownInstance *town); + void updateGarrisons(); +}; diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index c166e2681..e8b48a7a4 100644 --- a/client/CPlayerInterface.cpp +++ b/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(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 un(*pim); - if(castleInt && town->ID == TOWNI_TYPE) + if(const CGTownInstance * townObj = dynamic_cast(town)) { CFortScreen *fs = dynamic_cast(GH.topInt()); if(fs) fs->creaturesChanged(); + + BOOST_FOREACH(IShowActivable *isa, GH.listInt) + { + CKingdomInterface *ki = dynamic_cast(isa); + if (ki && townObj) + ki->townChanged(townObj); + } } else if(GH.listInt.size() && (town->ID == 17 || town->ID == 20 || town->ID == 106)) //external dwelling { diff --git a/client/GUIClasses.cpp b/client/GUIClasses.cpp index cf251363d..49595dff6 100644 --- a/client/GUIClasses.cpp +++ b/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() diff --git a/lib/JsonNode.cpp b/lib/JsonNode.cpp index 44c53fe46..5072b2e5c 100644 --- a/lib/JsonNode.cpp +++ b/lib/JsonNode.cpp @@ -5,6 +5,8 @@ #include #include +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 diff --git a/lib/JsonNode.h b/lib/JsonNode.h index 56587566e..08901718a 100644 --- a/lib/JsonNode.h +++ b/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 ©); @@ -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);