diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 1ae748208..c18507881 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -1267,7 +1267,7 @@ bool VCAI::tryBuildStructure(const CGTownInstance * t, int building, unsigned in BOOST_FOREACH(int buildID, toBuild) { - const CBuilding *b = VLC->buildh->buildings[t->subID][buildID]; + const CBuilding *b = t->town->buildings[buildID]; int canBuild = cb->canBuildStructure(t, buildID); if(canBuild == EBuildingState::ALLOWED) @@ -1282,7 +1282,7 @@ bool VCAI::tryBuildStructure(const CGTownInstance * t, int building, unsigned in } else if(canBuild == EBuildingState::NO_RESOURCES) { - TResources cost = VLC->buildh->buildings[t->subID][buildID]->resources; + TResources cost = t->town->buildings[buildID]->resources; for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; i++) { int diff = currentRes[i] - cost[i] + income[i]; diff --git a/client/CCastleInterface.cpp b/client/CCastleInterface.cpp index 0de5be75b..3193b4495 100644 --- a/client/CCastleInterface.cpp +++ b/client/CCastleInterface.cpp @@ -49,7 +49,7 @@ int hordeToDwellingID(int bid)//helper, converts horde buiding ID into correspon } } -CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance *Town, const Structure *Str) +CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance *Town, const CStructure *Str) :CShowableAnim(0, 0, Str->defName, CShowableAnim::BASE | CShowableAnim::USE_RLE), parent(Par), town(Town), @@ -120,7 +120,7 @@ void CBuildingRect::clickRight(tribool down, bool previousState) if( !CSDL_Ext::isTransparent(area, GH.current->motion.x-pos.x, GH.current->motion.y-pos.y) ) //inside building image { int bid = hordeToDwellingID(str->ID); - const CBuilding *bld = CGI->buildh->buildings[str->townID].find(bid)->second; + const CBuilding *bld = town->town->buildings[bid]; if (bid < EBuilding::DWELL_FIRST) { std::vector comps(1, new CComponent(CComponent::building, bld->tid, bld->bid)); @@ -214,7 +214,7 @@ std::string getBuildingSubtitle(int tid, int bid)//hover text for building bid = hordeToDwellingID(bid); if (bid<30)//non-dwellings - only buiding name - return CGI->buildh->buildings[tid].find(bid)->second->Name(); + return CGI->townh->towns[tid].buildings[bid]->Name(); else//dwellings - recruit %creature% { int creaID = t->creatures[(bid-30)%GameConstants::CREATURES_PER_TOWN].second.back();//taking last of available creatures @@ -445,7 +445,7 @@ public: }; SORTHELP buildSorter; -SORTHELP structSorter; +SORTHELP structSorter; CCastleBuildings::CCastleBuildings(const CGTownInstance* Town): town(Town), @@ -459,10 +459,9 @@ CCastleBuildings::CCastleBuildings(const CGTownInstance* Town): //Generate buildings list for (std::set::const_iterator building=town->builtBuildings.begin(); building!=town->builtBuildings.end(); building++) { - std::map::iterator structure; - structure = CGI->townh->structures[town->subID].find(*building); + auto structure = town->town->clientInfo.structures.find(*building); - if(structure != CGI->townh->structures[town->subID].end() && structure->second) + if(structure != town->town->clientInfo.structures.end() && structure->second) { if(structure->second->group<0) // no group - just add it buildings.push_back(new CBuildingRect(this, town, structure->second)); @@ -471,18 +470,18 @@ CCastleBuildings::CCastleBuildings(const CGTownInstance* Town): } } - Structure * shipyard = CGI->townh->structures[town->subID][6]; + CStructure * shipyard = town->town->clientInfo.structures[6]; //ship in shipyard if(shipyard && vstd::contains(groups, shipyard->group)) { std::vector vobjs = LOCPLINT->cb->getVisitableObjs(town->bestLocation()); if(!vobjs.empty() && (vobjs.front()->ID == 8 || vobjs.front()->ID == GameConstants::HEROI_TYPE)) //there is visitable obj at shipyard output tile and it's a boat or hero (on boat) { - groups[shipyard->group].push_back(CGI->townh->structures[town->subID][20]); + groups[shipyard->group].push_back(town->town->clientInfo.structures[20]); } } //Create building for each group - for (std::map< int, std::vector >::iterator group = groups.begin(); group != groups.end(); group++) + for (std::map< int, std::vector >::iterator group = groups.begin(); group != groups.end(); group++) { std::sort(group->second.begin(), group->second.end(), structSorter); buildings.push_back(new CBuildingRect(this, town, group->second.back())); @@ -521,10 +520,10 @@ void CCastleBuildings::checkRules() int buildingID = animRule[i].buildID; //check if this building have been upgraded (Ship is upgrade of Shipyard) - int groupID = CGI->townh->structures[town->subID][animRule[i].buildID]->group; + int groupID = town->town->clientInfo.structures[animRule[i].buildID]->group; if (groupID != -1) { - std::map< int, std::vector >::const_iterator git= groups.find(groupID); + std::map< int, std::vector >::const_iterator git= groups.find(groupID); if ( git == groups.end() || git->second.empty() ) continue; buildingID = git->second.back()->ID; @@ -548,10 +547,9 @@ void CCastleBuildings::checkRules() void CCastleBuildings::addBuilding(int building) { OBJ_CONSTRUCTION_CAPTURING_ALL; - std::map::const_iterator structure; - structure = CGI->townh->structures[town->subID].find(building); + auto structure = town->town->clientInfo.structures.find(building); - if(structure != CGI->townh->structures[town->subID].end()) //we have info about that structure + if(structure != town->town->clientInfo.structures.end()) //we have info about that structure { if(structure->second->group<0) //no group - just add it { @@ -586,10 +584,9 @@ void CCastleBuildings::addBuilding(int building) void CCastleBuildings::removeBuilding(int building) { OBJ_CONSTRUCTION_CAPTURING_ALL; - std::map::const_iterator structure; - structure = CGI->townh->structures[town->subID].find(building); + auto structure = town->town->clientInfo.structures.find(building); - if(structure != CGI->townh->structures[town->subID].end()) //we have info about that structure + if(structure != town->town->clientInfo.structures.end()) //we have info about that structure { if(structure->second->group<0) //no group - just add it { @@ -642,7 +639,7 @@ void CCastleBuildings::buildingClicked(int building) { tlog5<<"You've clicked on "<buildh->buildings[town->subID].find(building)->second; + const CBuilding *b = town->town->buildings.find(building)->second; if(building >= EBuilding::DWELL_FIRST) { @@ -784,7 +781,7 @@ void CCastleBuildings::enterBlacksmith(int ArtifactID) const CGHeroInstance *hero = town->visitingHero; if(!hero) { - LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % CGI->buildh->buildings[town->subID].find(16)->second->Name())); + LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % town->town->buildings.find(16)->second->Name())); return; } int price = CGI->arth->artifacts[ArtifactID]->price; @@ -797,7 +794,7 @@ void CCastleBuildings::enterBuilding(int building) std::vector comps(1, new CComponent(CComponent::building, town->subID, building)); LOCPLINT->showInfoDialog( - CGI->buildh->buildings[town->subID].find(building)->second->Description(),comps); + town->town->buildings.find(building)->second->Description(),comps); } void CCastleBuildings::enterCastleGate() @@ -833,9 +830,9 @@ void CCastleBuildings::enterFountain(int building) { std::vector comps(1, new CComponent(CComponent::building,town->subID,building)); - std::string descr = CGI->buildh->buildings[town->subID].find(building)->second->Description(); + std::string descr = town->town->buildings.find(building)->second->Description(); if ( building == 21)//we need description for mystic pond as well - descr += "\n\n"+CGI->buildh->buildings[town->subID].find(17)->second->Description(); + descr += "\n\n"+town->town->buildings.find(17)->second->Description(); if (town->bonusValue.first == 0)//fountain was builded this week descr += "\n\n"+ CGI->generaltexth->allTexts[677]; else//fountain produced something; @@ -1182,7 +1179,7 @@ CTownInfo::CTownInfo(int posX, int posY, const CGTownInstance* Town, bool townHa return; picture = new CAnimImage("ITMCL.DEF", town->fortLevel()-1); } - building = CGI->buildh->buildings[town->subID][buildID]; + building = town->town->buildings[buildID]; pos = picture->pos; } @@ -1330,7 +1327,7 @@ CHallInterface::CBuildingBox::CBuildingBox(int x, int y, const CGTownInstance * } CHallInterface::CHallInterface(const CGTownInstance *Town): - CWindowObject(PLAYER_COLORED | BORDERED, CGI->buildh->hall[Town->subID].first), + CWindowObject(PLAYER_COLORED | BORDERED, Town->town->clientInfo.hallBackground), town(Town) { OBJ_CONSTRUCTION_CAPTURING_ALL; @@ -1341,12 +1338,12 @@ CHallInterface::CHallInterface(const CGTownInstance *Town): Rect barRect(5, 556, 740, 18); statusBar = new CGStatusBar(new CPicture(*background, barRect, 5, 556, false)); - title = new CLabel(399, 12, FONT_MEDIUM, CENTER, Colors::Cornsilk, CGI->buildh->buildings[town->subID][town->hallLevel()+EBuilding::VILLAGE_HALL]->Name()); + title = new CLabel(399, 12, FONT_MEDIUM, CENTER, Colors::Cornsilk, town->town->buildings[town->hallLevel()+EBuilding::VILLAGE_HALL]->Name()); exit = new CAdventureMapButton(CGI->generaltexth->hcommands[8], "", boost::bind(&CHallInterface::close,this), 748, 556, "TPMAGE1.DEF", SDLK_RETURN); exit->assignedKeys.insert(SDLK_ESCAPE); - const std::vector< std::vector< std::vector > > &boxList = CGI->buildh->hall[town->subID].second; + auto & boxList = town->town->clientInfo.hallSlots; boxes.resize(boxList.size()); for(size_t row=0; rowbuildh->buildings[town->subID][buildingID]; + building = town->town->buildings[buildingID]; if (buildingID == 18 || buildingID == 24) { @@ -1407,7 +1404,7 @@ std::string CBuildWindow::getTextForState(int state) { if (vstd::contains(town->builtBuildings, *i)) continue;//skipping constructed buildings - ret+= CGI->buildh->buildings[town->subID][*i]->Name() + ", "; + ret+= town->town->buildings[*i]->Name() + ", "; } ret.erase(ret.size()-2); } @@ -1479,7 +1476,7 @@ CFortScreen::CFortScreen(const CGTownInstance * town): if (fortSize > GameConstants::CREATURES_PER_TOWN && town->creatures.back().second.empty()) fortSize--; - const CBuilding *fortBuilding = CGI->buildh->buildings[town->subID][town->fortLevel()+6]; + const CBuilding *fortBuilding = town->town->buildings[town->fortLevel()+6]; title = new CLabel(400, 12, FONT_BIG, CENTER, Colors::Cornsilk, fortBuilding->Name()); std::string text = boost::str(boost::format(CGI->generaltexth->fcommands[6]) % fortBuilding->Name()); @@ -1610,7 +1607,7 @@ CFortScreen::RecruitArea::RecruitArea(int posX, int posY, const CGTownInstance * values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[194], CGI->generaltexth->fcommands[5], town->creatureGrowth(level))); creatureName = new CLabel(78, 11, FONT_SMALL, CENTER, Colors::Cornsilk, creature->namePl); - dwellingName = new CLabel(78, 101, FONT_SMALL, CENTER, Colors::Cornsilk, CGI->buildh->buildings[town->subID][buildingID]->Name()); + dwellingName = new CLabel(78, 101, FONT_SMALL, CENTER, Colors::Cornsilk, town->town->buildings[buildingID]->Name()); if (vstd::contains(town->builtBuildings, buildingID)) { diff --git a/client/CCastleInterface.h b/client/CCastleInterface.h index c397aec4c..8eb2eb1e3 100644 --- a/client/CCastleInterface.h +++ b/client/CCastleInterface.h @@ -17,7 +17,7 @@ class CResDataBar; class CSpell; class CTextBox; class CTownList; -struct Structure; +struct CStructure; class CGHeroInstance; class CGarrisonInt; class CCreature; @@ -39,13 +39,13 @@ class CBuildingRect : public CShowableAnim public: CCastleBuildings * parent; const CGTownInstance * town; - const Structure* str; + const CStructure* str; SDL_Surface* border; SDL_Surface* area; ui32 stateCounter;//For building construction - current stage in animation - CBuildingRect(CCastleBuildings * Par, const CGTownInstance *Town, const Structure *Str); //c-tor + CBuildingRect(CCastleBuildings * Par, const CGTownInstance *Town, const CStructure *Str); //c-tor ~CBuildingRect(); //d-tor bool operator<(const CBuildingRect & p2) const; void hover(bool on); @@ -115,7 +115,7 @@ class CCastleBuildings : public CIntObject { CPicture *background; //List of buildings for each group - std::map< int, std::vector > groups; + std::map< int, std::vector > groups; //Vector with all blittable buildings std::vector buildings; diff --git a/client/CGameInfo.cpp b/client/CGameInfo.cpp index 606e38d51..0855d51ac 100644 --- a/client/CGameInfo.cpp +++ b/client/CGameInfo.cpp @@ -32,5 +32,4 @@ void CGameInfo::setFromLib() objh = VLC->objh; spellh = VLC->spellh; dobjinfo = VLC->dobjinfo; - buildh = VLC->buildh; } \ No newline at end of file diff --git a/client/CGameInfo.h b/client/CGameInfo.h index 3dcf60e45..681bef28a 100644 --- a/client/CGameInfo.h +++ b/client/CGameInfo.h @@ -61,7 +61,6 @@ public: ConstTransitivePtr dobjinfo; CGeneralTextHandler * generaltexth; CMapHandler * mh; - ConstTransitivePtr buildh; CTownHandler * townh; //CTownHandler * townh; diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index 5149aa4ab..2e10df955 100644 --- a/client/CPreGame.cpp +++ b/client/CPreGame.cpp @@ -3067,9 +3067,8 @@ void CBonusSelection::updateBonusSelection() picName = graphics->ERMUtoPicture[faction][buildID]; picNumber = -1; - tlog1<buildh->buildings.size()<<"\t"<buildh->buildings[faction].size()<<"\t"<buildh->buildings[faction], buildID)) - desc = CGI->buildh->buildings[faction].find(buildID)->second->Description(); + if (vstd::contains(CGI->townh->towns[faction].buildings, buildID)) + desc = CGI->townh->towns[faction].buildings.find(buildID)->second->Description(); } break; case 3: //artifact diff --git a/client/GUIClasses.cpp b/client/GUIClasses.cpp index 14245697c..80bca94f7 100644 --- a/client/GUIClasses.cpp +++ b/client/GUIClasses.cpp @@ -904,7 +904,7 @@ std::string CComponent::getDescription() case spell: return CGI->spellh->spells[subtype]->descriptions[val]; case morale: return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)]; case luck: return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)]; - case building: return CGI->buildh->buildings[subtype][val]->Description(); + case building: return CGI->townh->towns[subtype].buildings[val]->Description(); case hero: return CGI->heroh->heroes[subtype]->name; case flag: return ""; } @@ -936,7 +936,7 @@ std::string CComponent::getSubtitleInternal() case spell: return CGI->spellh->spells[subtype]->name; case morale: return ""; case luck: return ""; - case building: return CGI->buildh->buildings[subtype][val]->Name(); + case building: return CGI->townh->towns[subtype].buildings[val]->Name(); case hero: return CGI->heroh->heroes[subtype]->name; case flag: return CGI->generaltexth->capColors[subtype]; } @@ -2437,9 +2437,9 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstan { switch (mode) { - break; case EMarketMode::CREATURE_RESOURCE: title = CGI->buildh->buildings[6][21]->Name(); - break; case EMarketMode::RESOURCE_ARTIFACT: title = CGI->buildh->buildings[market->o->subID][17]->Name(); - break; case EMarketMode::ARTIFACT_RESOURCE: title = CGI->buildh->buildings[market->o->subID][17]->Name(); + break; case EMarketMode::CREATURE_RESOURCE: title = CGI->townh->towns[6].buildings[21]->Name(); + break; case EMarketMode::RESOURCE_ARTIFACT: title = CGI->townh->towns[market->o->subID].buildings[17]->Name(); + break; case EMarketMode::ARTIFACT_RESOURCE: title = CGI->townh->towns[market->o->subID].buildings[17]->Name(); break; default: title = CGI->generaltexth->allTexts[158]; } } diff --git a/config/buildings.json b/config/buildings.json index f46827ff0..c8b5473c5 100644 --- a/config/buildings.json +++ b/config/buildings.json @@ -1,95 +1,9 @@ -// Town properties, ordered by city type (0 to 8) - -// defnames: Buildings coordinates inside a city -// blit_order: Buildings not mentioned in the file will be blitted first. -// Then buildings in the list will be drawn in that order. -// creatures_basic: ids of the basic creatures in each dwelling, ordered by level. 8th is WoG and is ignored. -// creatures_upgraded: ids of the upgraded creatures in each dwelling, ordered by level -// horde: horde building creature levels (-1 if not present) -// mage_guild: maximum level of the mage guild -// primary_resource: (1,3,4,5 for rares and 127 for wood+ore) -// war_machine: type of war machine that this city can build - { - "schema" : - { - "town_type" : - { - "type" : "array", - "items" : - { - "type" : "object", - "properties" : - { - "blit_order" : { "type" : "array", "items" : {"type":"number"}, "default" :[] }, - "creatures" : { "type" : "array", "items" : { "type" : "array", "items" : {"type":"number"} } }, - "horde" : { "type" : "array", "items" : {"type":"number", "default" : -1} }, - "primary_resource" : { "type" : "number", "default" : 127}, - "mage_guild" : { "type" : "number", "default" : 5}, - "war_machine" : { "type" : "number"}, - "defnames" : - { - "type" : "array", - "items" : - { - "type" : "object", - "properties" : - { - "id" : { "type" : "number" }, - "x" : { "type" : "number" }, - "y" : { "type" : "number" }, - "defname" : { "type" : "string" }, - "border" : { "type" : "string", "default" : ""}, - "area" : { "type" : "string", "default" : ""} - } - } - }, - "building_requirements" : - { - "type" : "array", - "items" : - { - "type" : "object", - "properties" : - { - "id" : - { - "type" : "number" - }, - "requires" : - { - "type" : "array", - "items" : {"type":"number"} - } - } - } - } - } - } - }, - "town_groups" : - { - "type" : "array", - "items" : - { - "type" : "object", - "properties" : - { - "id" : { "type" : "number" }, - "groups" : - { - "type" : "array", - "items" : { "type" : "array", "items" : {"type":"number"}, } - } - } - } - } - }, - "town_type" : + "towns" : [ { // 0 - Castle - "defnames" : + "structures" : [ { "id" : 16, "defname" : "TBCSBLAK.def", "x" : 213, "y" : 251, "border" : "TOCSBLAK.bmp", "area" : "TZCSBLAK.bmp" }, { "id" : 8, "defname" : "TBCSCAS2.def", "x" : 478, "y" : 66, "border" : "TOCSCAS2.bmp", "area" : "TZCSCAS2.bmp" }, @@ -130,30 +44,63 @@ { "id" : 43, "defname" : "TBCSUP_6.def", "x" : 303, "y" : 0, "border" : "TOCSANG2.bmp", "area" : "TZCSANG2.bmp" }, { "id" : 20, "defname" : "TBCSBOAT.def", "x" : 478, "y" : 134, "border" : "TOCSDKMN.bmp", "area" : "TZCSDKMN.bmp" } ], + "groups" : + [ + [ 0, 1, 2, 3, 4 ], + [ 6, 20 ], + [ 7, 8, 9 ], + [ 10, 11, 12, 13 ], + [ 30, 37 ], + [ 31, 38 ], + [ 32, 39, 18, 19 ], + [ 33, 40 ], + [ 34, 41 ], + [ 35, 42 ], + [ 36, 43 ] + ], + "hallBackground": "TPTHBKCS.BMP", + "hallSlots": + [ + [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5, 22 ], [ 16 ] ], + [ [ 14, 15 ], [ 0, 1, 2, 3 ], [ 6, 17 ] ], + [ [ 21 ], [ 18, 19 ] ], + [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], + [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] + ], + "blit_order" : [ 0, 1, 2, 3, 10, 11, 12, 13, 5, 22, 30, 37, 16, 6, 20, 18, 19, 34, 41 ], "creatures" : [ [0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13] ], - "horde" : [ 2, null ], + "horde" : [ 2, -1 ], + "primary_resource" : 127, "mage_guild" : 4, "war_machine" : 4, - "building_requirements" : + "buildings" : [ + { "id" : 0 }, { "id" : 1, "requires" : [ 0 ] }, { "id" : 2, "requires" : [ 1 ] }, { "id" : 3, "requires" : [ 2 ] }, { "id" : 4, "requires" : [ 3 ] }, + { "id" : 5 }, + { "id" : 6 }, + { "id" : 7 }, { "id" : 8, "requires" : [ 7 ] }, { "id" : 9, "requires" : [ 8 ] }, + { "id" : 10 }, { "id" : 11, "requires" : [ 10, 5 ] }, { "id" : 12, "requires" : [ 11, 0, 14, 16 ] }, { "id" : 13, "requires" : [ 12, 9 ] }, + { "id" : 14 }, { "id" : 15, "requires" : [ 14 ] }, + { "id" : 16 }, { "id" : 17, "requires" : [ 6 ] }, { "id" : 18, "requires" : [ 32 ] }, { "id" : 19, "requires" : [ 39 ] }, - { "id" : 20, "requires" : [ 6 ] }, + { "id" : 20 }, { "id" : 21, "requires" : [ 33 ] }, { "id" : 22, "requires" : [ 5 ] }, + { "id" : 26 }, { "id" : 30, "requires" : [ 7 ] }, { "id" : 31, "requires" : [ 30 ] }, { "id" : 32, "requires" : [ 33 ] }, @@ -173,7 +120,7 @@ { // 1 - Rampart - "defnames" : + "structures" : [ { "id" : 16, "defname" : "TBRMBLAK.def", "x" : 558, "y" : 105, "border" : "TORAID.bmp", "area" : "TZRAID.bmp" }, { "id" : 9, "defname" : "TBRMCAS3.def", "x" : 79, "y" : 18, "border" : "TORCAS2.bmp", "area" : "TZRCAS2.bmp" }, @@ -218,6 +165,30 @@ { "id" : 12, "defname" : "TBRMHAL3.def", "x" : 538, "y" : 187, "border" : "TORHAL3.bmp", "area" : "TZRHAL3.bmp" }, { "id" : 11, "defname" : "TBRMHAL2.def", "x" : 538, "y" : 187, "border" : "TORHAL2.bmp", "area" : "TZRHAL2.bmp" } ], + "groups" : + [ + [ 0, 1, 2, 3, 4 ], + [ 6, 20 ], + [ 7, 8, 9 ], + [ 10, 11, 12, 13 ], + [ 30, 37 ], + [ 32, 39 ], + [ 33, 40 ], + [ 35, 42 ], + [ 36, 43 ], + [ 24, 25, 34, 41 ], + [ 17, 21 ], + [ 31, 18, 38, 19 ] + ], + "hallBackground": "TPTHBKRM.BMP", + "hallSlots": + [ + [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], + [ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 17, 21 ] ], + [ [ 22 ], [ 24, 25 ], [ 18, 19 ] ], + [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], + [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] + ], "blit_order" : [ 33, 40, 35, 42, 16, 32, 39, 0, 1, 2, 3, 4, 31, 18, 38, 19, 34, 24, 41, 25, 5, 30, 37, 14, 10, 11, 12, 13, 17, 21, 22, -1, 27, 28, 29, 15 ], "creatures" : [ [14, 15], [16, 17], [18, 19], [20, 21], [22, 23], [24, 25], [26, 27] ], "horde" : [ 1, 4 ], @@ -225,24 +196,32 @@ "primary_resource" : 4, "war_machine" : 6, - "building_requirements" : + "buildings" : [ + { "id" : 0 }, { "id" : 1, "requires" : [ 0 ] }, { "id" : 2, "requires" : [ 1 ] }, { "id" : 3, "requires" : [ 2 ] }, { "id" : 4, "requires" : [ 3 ] }, + { "id" : 5 }, + { "id" : 7 }, { "id" : 8, "requires" : [ 7 ] }, { "id" : 9, "requires" : [ 8 ] }, + { "id" : 10 }, { "id" : 11, "requires" : [ 10, 5 ] }, { "id" : 12, "requires" : [ 11, 0, 14, 16 ] }, { "id" : 13, "requires" : [ 12, 9 ] }, + { "id" : 14 }, { "id" : 15, "requires" : [ 14 ] }, + { "id" : 16 }, + { "id" : 17 }, { "id" : 18, "requires" : [ 31 ] }, { "id" : 19, "requires" : [ 38 ] }, { "id" : 21, "requires" : [ 17 ] }, { "id" : 22, "requires" : [ 18 ] }, { "id" : 24, "requires" : [ 34 ] }, { "id" : 25, "requires" : [ 41 ] }, + { "id" : 26 }, { "id" : 30, "requires" : [ 7 ] }, { "id" : 31, "requires" : [ 30 ] }, { "id" : 32, "requires" : [ 30 ] }, @@ -262,7 +241,7 @@ { // 2 - Tower - "defnames" : + "structures" : [ { "id" : 16, "defname" : "TBTWBLAK.def", "x" : 478, "y" : 211, "border" : "TOTBLKA.bmp", "area" : "TZTBLKA.bmp" }, { "id" : 9, "defname" : "TBTWCAS3.def", "x" : 301, "y" : 0, "border" : "TOTCAS3.bmp", "area" : "TZTCAS3.bmp" }, @@ -302,30 +281,61 @@ { "id" : 43, "defname" : "TBTWUP_6.def", "x" : 75, "y" : 91, "border" : "TOTTIT2.bmp", "area" : "TZTTIT2.bmp" }, { "id" : 8, "defname" : "TBTWCAS2.def", "x" : 301, "y" : 0, "border" : "TOTCAS2.bmp", "area" : "TZTCAS2.bmp" } ], + "groups" : + [ + [ 0, 1, 2, 3, 4 ], + [ 6, 20 ], + [ 7, 8, 9 ], + [ 10, 11, 12, 13 ], + [ 30, 37 ], + [ 32, 39 ], + [ 33, 40 ], + [ 34, 41 ], + [ 35, 42 ], + [ 36, 43 ], + [ 18, 19, 31, 38 ] + ], + "hallBackground": "TPTHBKTW.BMP", + "hallSlots": + [ + [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], + [ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 22 ], [ 23 ] ], + [ [ 17 ], [ 21 ], [ 18, 19 ] ], + [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], + [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] + ], "blit_order" : [ 36, 43, 32, 39, 10, 11, 12, 13, 32, 35, 42, 15, 5, 18, 19 ], "creatures" : [ [28, 29], [30, 31], [32, 33], [34, 35], [36, 37], [38, 39], [40, 41] ], - "horde" : [ 1, null ], + "horde" : [ 1, -1 ], "primary_resource" : 5, + "mage_guild" : 5, "war_machine" : 5, - "building_requirements" : + "buildings" : [ + { "id" : 0 }, { "id" : 1, "requires" : [ 0 ] }, { "id" : 2, "requires" : [ 1 ] }, { "id" : 3, "requires" : [ 2 ] }, { "id" : 4, "requires" : [ 3 ] }, + { "id" : 5 }, + { "id" : 7 }, { "id" : 8, "requires" : [ 7 ] }, { "id" : 9, "requires" : [ 8 ] }, + { "id" : 10 }, { "id" : 11, "requires" : [ 10, 5 ] }, { "id" : 12, "requires" : [ 11, 0, 14, 16 ] }, { "id" : 13, "requires" : [ 12, 9 ] }, + { "id" : 14 }, { "id" : 15, "requires" : [ 14 ] }, + { "id" : 16 }, { "id" : 17, "requires" : [ 14 ] }, { "id" : 18, "requires" : [ 31 ] }, { "id" : 19, "requires" : [ 38 ] }, { "id" : 21, "requires" : [ 7 ] }, { "id" : 22, "requires" : [ 0 ] }, { "id" : 23, "requires" : [ 0 ] }, + { "id" : 26 }, { "id" : 30, "requires" : [ 7 ] }, { "id" : 31, "requires" : [ 30 ] }, { "id" : 32, "requires" : [ 30 ] }, @@ -345,7 +355,7 @@ { // 3 - Inferno - "defnames" : + "structures" : [ { "id" : 16, "defname" : "TBINBLAK.def", "x" : 684, "y" : 253, "border" : "TOIBLKA.bmp", "area" : "TZIBLKA.bmp" }, { "id" : 9, "defname" : "TBINCAS3.def", "x" : 222, "y" : 18, "border" : "TOICAS3A.bmp", "area" : "TZICAS3A.bmp" }, @@ -386,24 +396,55 @@ { "id" : 43, "defname" : "TBINUP_6.def", "x" : 420, "y" : 105, "border" : "TOIDVL2.bmp", "area" : "TZIDVL2.bmp" }, { "id" : 8, "defname" : "TBINCAS2.def", "x" : 222, "y" : 44, "border" : "TOICAS1A.bmp", "area" : "TZICAS1A.bmp" } ], + "groups" : + [ + [ 0, 1, 2, 3, 4 ], + [ 6, 20 ], + [ 7, 8, 9 ], + [ 10, 11, 12, 13 ], + [ 30, 37 ], + [ 31, 38 ], + [ 33, 40 ], + [ 34, 41 ], + [ 35, 42 ], + [ 36, 43 ], + [ 18, 19, 30, 37 ], + [ 32, 39, 24, 25 ] + ], + "hallBackground": "TPTHBKIN.BMP", + "hallSlots": + [ + [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], + [ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 23 ], [ 21 ] ], + [ [ 22 ], [ 18, 19 ], [ 24, 25 ] ], + [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], + [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] + ], "blit_order" : [ 26, 21, 7, 8, 9, 22, 31, 38, 36, 43, 10, 11, 12, 13, 5, 32, 39, 24, 25, 33, 40, 34, 41, 30, 37, 18, 19, 14, 15, 16, 35, 42 ], "creatures" : [ [42, 43], [44, 45], [46, 47], [48, 49], [50, 51], [52, 53], [54, 55] ], "horde" : [ 0, 2 ], + "mage_guild" : 5, "primary_resource" : 1, "war_machine" : 5, - "building_requirements" : + "buildings" : [ + { "id" : 0 }, { "id" : 1, "requires" : [ 0 ] }, { "id" : 2, "requires" : [ 1 ] }, { "id" : 3, "requires" : [ 2 ] }, { "id" : 4, "requires" : [ 3 ] }, + { "id" : 5 }, + { "id" : 7 }, { "id" : 8, "requires" : [ 7 ] }, { "id" : 9, "requires" : [ 8 ] }, + { "id" : 10 }, { "id" : 11, "requires" : [ 10, 5 ] }, { "id" : 12, "requires" : [ 11, 0, 14, 16 ] }, { "id" : 13, "requires" : [ 12, 9 ] }, + { "id" : 14 }, { "id" : 15, "requires" : [ 14 ] }, + { "id" : 16 }, { "id" : 18, "requires" : [ 30 ] }, { "id" : 19, "requires" : [ 37 ] }, { "id" : 21, "requires" : [ 7 ] }, @@ -411,6 +452,7 @@ { "id" : 23, "requires" : [ 0 ] }, { "id" : 24, "requires" : [ 32 ] }, { "id" : 25, "requires" : [ 39 ] }, + { "id" : 26 }, { "id" : 30, "requires" : [ 7 ] }, { "id" : 31, "requires" : [ 30 ] }, { "id" : 32, "requires" : [ 30 ] }, @@ -430,7 +472,7 @@ { // 4 - Necropolis - "defnames" : + "structures" : [ { "id" : 16, "defname" : "TBNCBLAK.def", "x" : 382, "y" : 252, "border" : "TONSMITA.bmp", "area" : "TZNSMITA.bmp" }, { "id" : 8, "defname" : "TBNCCAS2.def", "x" : 139, "y" : 66, "border" : "TONCAS2.bmp", "area" : "TZNCAS2.bmp" }, @@ -475,29 +517,63 @@ { "id" : 43, "defname" : "TBNCUP_6.def", "x" : 662, "y" : 23, "border" : "TONBON2.bmp", "area" : "TZNBON2.bmp" }, { "id" : 20, "defname" : "TBNCBOAT.def", "x" : 617, "y" : 265, "border" : "TONSHPNA.bmp", "area" : "TZNSHPNA.bmp" } ], + "groups" : + [ + [ 0, 1, 2, 3, 4 ], + [ 6, 20 ], + [ 7, 8, 9 ], + [ 10, 11, 12, 13 ], + [ 31, 38 ], + [ 32, 39 ], + [ 33, 40 ], + [ 34, 41 ], + [ 35, 42 ], + [ 36, 43 ], + [ 30, 37, 18, 19 ] + ], + "hallBackground": "TPTHBKNC.BMP", + "hallSlots": + [ + [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], + [ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 21 ], [ 6 ] ], + [ [ 17 ], [ 22 ], [ 18, 19 ] ], + [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], + [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] + ], "blit_order" : [ 17, 0, 1, 2, 3, 4, 7, 8, 9, 32, 39, 26, 15, 14, 34, 41, 16, 5, 33, 40, 31, 38, 6, 30, 18, 37, 19, 22, 20 ], "creatures" : [ [56, 57], [58, 59], [60, 61], [62, 63], [64, 65], [66, 67], [68, 69] ], - "horde" : [ 0, null ], + "horde" : [ 0, -1 ], + "mage_guild" : 5, + "primary_resource" : 127, "war_machine" : 6, + - "building_requirements" : + "buildings" : [ + { "id" : 0 }, { "id" : 1, "requires" : [ 0 ] }, { "id" : 2, "requires" : [ 1 ] }, { "id" : 3, "requires" : [ 2 ] }, { "id" : 4, "requires" : [ 3 ] }, + { "id" : 5 }, + { "id" : 6 }, + { "id" : 7 }, { "id" : 8, "requires" : [ 7 ] }, { "id" : 9, "requires" : [ 8 ] }, + { "id" : 10 }, { "id" : 11, "requires" : [ 10, 5 ] }, { "id" : 12, "requires" : [ 11, 0, 14, 16 ] }, { "id" : 13, "requires" : [ 12, 9 ] }, + { "id" : 14 }, { "id" : 15, "requires" : [ 14 ] }, + { "id" : 16 }, { "id" : 17, "requires" : [ 7 ] }, { "id" : 18, "requires" : [ 22, 30 ] }, { "id" : 19, "requires" : [ 22, 37 ] }, - { "id" : 20, "requires" : [ 6 ] }, + { "id" : 20 }, { "id" : 21, "requires" : [ 0 ] }, { "id" : 22, "requires" : [ 30 ] }, + { "id" : 26 }, { "id" : 30, "requires" : [ 7 ] }, { "id" : 31, "requires" : [ 30 ] }, { "id" : 32, "requires" : [ 30 ] }, @@ -517,7 +593,7 @@ { // 5 - Dungeon - "defnames" : + "structures" : [ { "id" : 16, "defname" : "TBDNBLAK.def", "x" : 544, "y" : 248, "border" : "TODSMITH.bmp", "area" : "TZDSMITH.bmp" }, { "id" : 9, "defname" : "TBDNCAS3.def", "x" : 363, "y" : 87, "border" : "TODCAS3.bmp", "area" : "TZDCAS3.bmp" }, @@ -557,28 +633,61 @@ { "id" : 43, "defname" : "TBDNUP_6.def", "x" : 550, "y" : 0, "border" : "TODDRA2A.bmp", "area" : "TZDDRA2A.bmp" }, { "id" : 8, "defname" : "TBDNCAS2.def", "x" : 363, "y" : 87, "border" : "TODCAS2.bmp", "area" : "TZDCAS2.bmp" } ], + "groups" : + [ + [ 0, 1, 2, 3, 4 ], + [ 6, 20 ], + [ 7, 8, 9 ], + [ 10, 11, 12, 13 ], + [ 31, 38 ], + [ 32, 39 ], + [ 33, 40 ], + [ 34, 41 ], + [ 35, 42 ], + [ 36, 43 ], + [ 30, 37, 18, 19 ] + ], + "hallBackground": "TPTHBKDG.BMP", + "hallSlots": + [ + [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], + [ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 21 ], [ 22 ] ], + [ [ 17 ], [ 23 ], [ 18, 19 ] ], + [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], + [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] + ], "blit_order" : [ 0, 1, 2, 3, 4, 21, 35, 42, 5, 30, 18, 37, 19, 32, 39, 26, 7, 8, 9, 23 ], "creatures" : [ [70, 71], [72, 73], [74, 75], [76, 77], [78, 79], [80, 81], [82, 83] ], - "horde" : [ 0, null ], + "horde" : [ 0, -1 ], + "mage_guild" : 5, "primary_resource" : 3, "war_machine" : 4, - "building_requirements" : + "buildings" : [ + { "id" : 0 }, { "id" : 1, "requires" : [ 0 ] }, { "id" : 2, "requires" : [ 1 ] }, { "id" : 3, "requires" : [ 2 ] }, { "id" : 4, "requires" : [ 3 ] }, + { "id" : 5 }, + { "id" : 7 }, { "id" : 8, "requires" : [ 7 ] }, { "id" : 9, "requires" : [ 8 ] }, + { "id" : 10 }, { "id" : 11, "requires" : [ 10, 5 ] }, { "id" : 12, "requires" : [ 11, 0, 14, 16 ] }, { "id" : 13, "requires" : [ 12, 9 ] }, + { "id" : 14 }, { "id" : 15, "requires" : [ 14 ] }, + { "id" : 16 }, { "id" : 17, "requires" : [ 14 ] }, { "id" : 18, "requires" : [ 30 ] }, { "id" : 19, "requires" : [ 37 ] }, { "id" : 21, "requires" : [ 0 ] }, + { "id" : 22 }, + { "id" : 23 }, + { "id" : 26 }, { "id" : 30, "requires" : [ 7 ] }, { "id" : 31, "requires" : [ 30 ] }, { "id" : 32, "requires" : [ 30 ] }, @@ -598,7 +707,7 @@ { // 6 - Stronghold - "defnames" : + "structures" : [ { "id" : 31, "defname" : "TBSTDW_1.def", "x" : 266, "y" : 246, "border" : "TOSWOL1.bmp", "area" : "TZSWOL1.bmp" }, { "id" : 43, "defname" : "TBSTUP_6.def", "x" : 604, "y" : 0, "border" : "TOSBEH2A.bmp", "area" : "TZSBEH2A.bmp" }, @@ -637,30 +746,61 @@ { "id" : 42, "defname" : "TBSTUP_5.def", "x" : 616, "y" : 93, "border" : "TOSCYC2A.bmp", "area" : "TZSCYC2A.bmp" }, { "id" : 16, "defname" : "TBSTBLAK.def", "x" : 660, "y" : 286, "border" : "TOSBLK1.bmp", "area" : "TZSBLK1.bmp" } ], + "groups" : + [ + [ 0, 1, 2, 3, 4 ], + [ 6, 20 ], + [ 7, 8, 9 ], + [ 10, 11, 12, 13 ], + [ 31, 38 ], + [ 32, 39 ], + [ 33, 40 ], + [ 34, 41 ], + [ 35, 42 ], + [ 36, 43 ], + [ 30, 37, 18, 19 ] + ], + "hallBackground": "TPTHBKTW.BMP", + "hallSlots": + [ + [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], + [ [ 14, 15 ], [ 0, 1, 2 ], [ 23 ], [ 17 ] ], + [ [ 21 ], [ 22 ], [ 18, 19 ] ], + [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], + [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] + ], "blit_order" : [ 33, 40, 30, 18, 37, 19, 31, 38, 23, 26, 5, 32, 39, 15, 14, 21, 16, 22 ], "creatures" : [ [84, 85], [86, 87], [88, 89], [90, 91], [92, 93], [94, 95], [96, 97] ], - "horde" : [ 0, null ], + "horde" : [ 0, -1 ], "mage_guild" : 3, + "primary_resource" : 127, "war_machine" : 5, - "building_requirements" : + "buildings" : [ + { "id" : 0 }, { "id" : 1, "requires" : [ 0 ] }, { "id" : 2, "requires" : [ 1 ] }, { "id" : 3, "requires" : [ 2 ] }, { "id" : 4, "requires" : [ 3 ] }, + { "id" : 5 }, + { "id" : 7 }, { "id" : 8, "requires" : [ 7 ] }, { "id" : 9, "requires" : [ 8 ] }, + { "id" : 10 }, { "id" : 11, "requires" : [ 10, 5 ] }, { "id" : 12, "requires" : [ 11, 0, 14, 16 ] }, { "id" : 13, "requires" : [ 12, 9 ] }, + { "id" : 14 }, { "id" : 15, "requires" : [ 14 ] }, + { "id" : 16 }, { "id" : 17, "requires" : [ 7 ] }, { "id" : 18, "requires" : [ 30 ] }, { "id" : 19, "requires" : [ 37 ] }, { "id" : 21, "requires" : [ 14 ] }, { "id" : 22, "requires" : [ 16 ] }, { "id" : 23, "requires" : [ 7 ] }, + { "id" : 26 }, { "id" : 30, "requires" : [ 7 ] }, { "id" : 31, "requires" : [ 30 ] }, { "id" : 32, "requires" : [ 30 ] }, @@ -680,7 +820,7 @@ { // 7 - Fortress - "defnames" : + "structures" : [ { "id" : 16, "defname" : "TBFRBLAK.def", "x" : 360, "y" : 160, "border" : "TOFAIDA.bmp", "area" : "TZFAIDA.bmp" }, { "id" : 8, "defname" : "TBFRCAS2.def", "x" : 368, "y" : 98, "border" : "TOFCAS2.bmp", "area" : "TZFCAS2.bmp" }, @@ -721,29 +861,62 @@ { "id" : 29, "defname" : "TBFRWTRW.def", "x" : 320, "y" : 141 }, { "id" : 20, "defname" : "TBFRBOAT.def", "x" : 197, "y" : 294, "border" : "TOFDCK1.bmp", "area" : "TZFDCK1.bmp" } ], + "groups" : + [ + [ 0, 1, 2, 3, 4 ], + [ 6, 20 ], + [ 7, 8, 9 ], + [ 10, 11, 12, 13 ], + [ 31, 38 ], + [ 32, 39 ], + [ 33, 40 ], + [ 34, 41 ], + [ 35, 42 ], + [ 36, 43 ], + [ 30, 37, 18, 19 ] + ], + "hallBackground": "TPTHBKFR.BMP", + "hallSlots": + [ + [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], + [ [ 14, 15 ], [ 0, 1, 2 ], [ 6 ] ], + [ [ 17 ], [ 21, 22 ], [ 18, 19 ] ], + [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], + [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] + ], "blit_order" : [ 16, 15, 14, 34, 41, 31, 38, 10, 11, 12, 13, 29, 0, 1, 2, 33, 40, 30, 18, 37, 19, 5, 36, 43, 26 ], "creatures" : [ [98, 99], [100, 101], [104, 105], [106, 107], [102, 103], [108, 109], [110, 111] ], - "horde" : [ 0, null ], + "horde" : [ 0, -1 ], "mage_guild" : 3, + "primary_resource" : 127, "war_machine" : 6, - "building_requirements" : + "buildings" : [ + { "id" : 0 }, { "id" : 1, "requires" : [ 0 ] }, { "id" : 2, "requires" : [ 1 ] }, { "id" : 3, "requires" : [ 2 ] }, { "id" : 4, "requires" : [ 3 ] }, + { "id" : 5 }, + { "id" : 6 }, + { "id" : 7 }, { "id" : 8, "requires" : [ 7 ] }, { "id" : 9, "requires" : [ 8 ] }, + { "id" : 10 }, { "id" : 11, "requires" : [ 10, 5 ] }, { "id" : 12, "requires" : [ 11, 0, 14, 16 ] }, { "id" : 13, "requires" : [ 12, 9 ] }, + { "id" : 14 }, { "id" : 15, "requires" : [ 14 ] }, + { "id" : 16 }, { "id" : 17, "requires" : [ 11, 21 ] }, { "id" : 18, "requires" : [ 30 ] }, { "id" : 19, "requires" : [ 37 ] }, + { "id" : 20 }, { "id" : 21, "requires" : [ 7 ] }, { "id" : 22, "requires" : [ 21 ] }, + { "id" : 26 }, { "id" : 30, "requires" : [ 7 ] }, { "id" : 31, "requires" : [ 30 ] }, { "id" : 32, "requires" : [ 30 ] }, @@ -763,7 +936,7 @@ { // 8 - Conflux - "defnames" : + "structures" : [ { "id" : 16, "defname" : "TBELBLAK.def", "x" : 449, "y" : 151, "border" : "TOELBLAK.bmp", "area" : "TZELBLAK.bmp" }, { "id" : 8, "defname" : "TBELCAS2.def", "x" : 349, "y" : 101, "border" : "TOELCAS2.bmp", "area" : "TZELCAS2.bmp" }, @@ -808,28 +981,61 @@ { "id" : 43, "defname" : "TBELUP_6.def", "x" : 43, "y" : 0, "border" : "TOELUP_6.bmp", "area" : "TZELUP_6.bmp" }, { "id" : 20, "defname" : "TBELBOAT.def", "x" : 239, "y" : 215, "border" : "TOELBOAT.bmp", "area" : "TZELBOAT.bmp" } ], + "groups" : + [ + [ 0, 1, 2, 3, 4 ], + [ 6, 20 ], + [ 7, 8, 9 ], + [ 10, 11, 12, 13 ], + [ 31, 38 ], + [ 32, 39 ], + [ 33, 40 ], + [ 34, 41 ], + [ 35, 42 ], + [ 36, 43 ], + [ 30, 37, 18, 19 ] + ], + "hallBackground": "TPTHBKFR.BMP", + "hallSlots": + [ + [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], + [ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 6 ] ], + [ [ 21 ], [ 17 ], [ 18, 19 ] ], + [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], + [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] + ], "blit_order" : [ -1, 27, 28, 16, 34, 41, 6, 20, 33, 40, 36, 43, 21, 0, 1, 2, 3, 4, 5, 15, 14, 17, 35, 42, 30, 18, 37, 19, 10, 11, 12, 13, 29 ], "creatures" : [ [118, 119], [112, 127], [115, 123], [114, 129], [113, 125], [120, 121], [130, 131] ], - "horde" : [ 0, null ], + "horde" : [ 0, -1 ], + "mage_guild" : 5, "primary_resource" : 1, "war_machine" : 4, - "building_requirements" : + "buildings" : [ + { "id" : 0 }, { "id" : 1, "requires" : [ 0 ] }, { "id" : 2, "requires" : [ 1 ] }, { "id" : 3, "requires" : [ 2 ] }, { "id" : 4, "requires" : [ 3 ] }, + { "id" : 5 }, + { "id" : 6 }, + { "id" : 7 }, { "id" : 8, "requires" : [ 7 ] }, { "id" : 9, "requires" : [ 8 ] }, + { "id" : 10 }, { "id" : 11, "requires" : [ 10, 5 ] }, { "id" : 12, "requires" : [ 11, 0, 14, 16 ] }, { "id" : 13, "requires" : [ 12, 9 ] }, + { "id" : 14 }, { "id" : 15, "requires" : [ 14 ] }, + { "id" : 16 }, { "id" : 17, "requires" : [ 14 ] }, { "id" : 18, "requires" : [ 30 ] }, { "id" : 19, "requires" : [ 37 ] }, + { "id" : 20 }, { "id" : 21, "requires" : [ 0 ] }, + { "id" : 26 }, { "id" : 30, "requires" : [ 7 ] }, { "id" : 31, "requires" : [ 30, 0 ] }, { "id" : 32, "requires" : [ 30, 0 ] }, @@ -846,100 +1052,5 @@ { "id" : 43, "requires" : [ 36 ] } ] } - ], - - //A group contains a vector of building IDs - //In the town screen only the last built structure from the group is displayed - //Eg. when there is Mage Guild Level 3, then we don't display Mage Guild Level 1 and 2 - "town_groups" : - [ - { - // Applies to all castles - "id" : -1, - "groups" : - [ - [ 0, 1, 2, 3, 4 ], - [ 6, 20 ], - [ 7, 8, 9 ], - [ 10, 11, 12, 13 ], - [ 30, 37 ], - [ 31, 38 ], - [ 32, 39 ], - [ 33, 40 ], - [ 34, 41 ], - [ 35, 42 ], - [ 36, 43 ], - [ 24, 25 ], - [ 18, 19 ] - ] - }, - - { - "id" : 1, - "groups" : - [ - [ 24, 25, 34, 41 ], - [ 17, 21 ], - [ 31, 18, 38, 19 ] - ] - }, - - { - "id" : 2, - "groups" : - [ - [ 18, 19, 31, 38 ] - ] - }, - - { - "id" : 3, - "groups" : - [ - [ 18, 19, 30, 37 ], - [ 32, 39, 24, 25 ] - ] - }, - - { - "id" : 4, - "groups" : - [ - [ 30, 37, 18, 19 ] - ] - }, - - { - "id" : 5, - "groups" : - [ - [ 30, 37, 18, 19 ] - ] - }, - - { - "id" : 6, - "groups" : - [ - [ 21 ], - [ 30, 37, 18, 19 ] - ] - }, - - { - "id" : 7, - "groups" : - [ - [ 30, 37, 18, 19 ] - ] - }, - - { - "id" : 8, - "groups" : - [ - [ 30, 37, 18, 19 ] - ] - } ] } diff --git a/config/hall.json b/config/hall.json deleted file mode 100644 index db15de54e..000000000 --- a/config/hall.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - // for each castle: - // id: town ID - // boxes: row buildings containing sets of ids for each box - "town": [ - { - "id": 0, - "image": "TPTHBKCS.BMP", - "boxes": [ - [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5, 22 ], [ 16 ] ], - [ [ 14, 15 ], [ 0, 1, 2, 3 ], [ 6, 17 ] ], - [ [ 21 ], [ 18, 19 ] ], - [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], - [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] - ] - }, - - { - "id": 1, - "image": "TPTHBKRM.BMP", - "boxes": [ - [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], - [ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 17, 21 ] ], - [ [ 22 ], [ 24, 25 ], [ 18, 19 ] ], - [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], - [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] - ] - }, - - { - "id": 2, - "image": "TPTHBKTW.BMP", - "boxes": [ - [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], - [ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 22 ], [ 23 ] ], - [ [ 17 ], [ 21 ], [ 18, 19 ] ], - [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], - [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] - ] - }, - - { - "id": 3, - "image": "TPTHBKIN.BMP", - "boxes": [ - [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], - [ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 23 ], [ 21 ] ], - [ [ 22 ], [ 18, 19 ], [ 24, 25 ] ], - [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], - [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] - ] - }, - - { - "id": 4, - "image": "TPTHBKNC.BMP", - "boxes": [ - [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], - [ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 21 ], [ 6 ] ], - [ [ 17 ], [ 22 ], [ 18, 19 ] ], - [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], - [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] - ] - }, - - { - "id": 5, - "image": "TPTHBKDG.BMP", - "boxes": [ - [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], - [ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 21 ], [ 22 ] ], - [ [ 17 ], [ 23 ], [ 18, 19 ] ], - [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], - [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] - ] - }, - - { - "id": 6, - "image": "TPTHBKTW.BMP", - "boxes": [ - [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], - [ [ 14, 15 ], [ 0, 1, 2 ], [ 23 ], [ 17 ] ], - [ [ 21 ], [ 22 ], [ 18, 19 ] ], - [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], - [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] - ] - }, - - { - "id": 7, - "image": "TPTHBKFR.BMP", - "boxes": [ - [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], - [ [ 14, 15 ], [ 0, 1, 2 ], [ 6 ] ], - [ [ 17 ], [ 21, 22 ], [ 18, 19 ] ], - [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], - [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] - ] - }, - - { - "id": 8, - "image": "TPTHBKFR.BMP", - "boxes": [ - [ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ], - [ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 6 ] ], - [ [ 21 ], [ 17 ], [ 18, 19 ] ], - [ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ], - [ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ] - ] - } - ] -} diff --git a/lib/CBuildingHandler.cpp b/lib/CBuildingHandler.cpp index 42b5c8688..5142a2393 100644 --- a/lib/CBuildingHandler.cpp +++ b/lib/CBuildingHandler.cpp @@ -1,10 +1,6 @@ #include "StdInc.h" #include "CBuildingHandler.h" -#include "CGeneralTextHandler.h" -#include "VCMI_Lib.h" -#include "Filesystem/CResourceLoader.h" -#include "JsonNode.h" #include "GameConstants.h" /* @@ -17,175 +13,6 @@ * */ -CBuilding * readBuilding(CLegacyConfigParser & parser, int townID, int buildID) -{ - CBuilding * ret = new CBuilding; - ret->tid = townID; - ret->bid = buildID; - for (size_t i=0; i< ret->resources.size(); i++) - ret->resources[i] = parser.readNumber(); - - parser.endLine(); - return ret; -} - -void CBuildingHandler::loadBuildings() -{ - CLegacyConfigParser parser("DATA/BUILDING.TXT"); - buildings.resize(GameConstants::F_NUMBER); - - parser.endLine(); // header - parser.endLine(); - - //Unique buildings - for (size_t town=0; towntid = town; - } - buildID++; - } - while (!parser.isNextEntryEmpty()); - - parser.endLine(); //header - parser.endLine(); - - //Dwellings - for (size_t town=0; towntid = town; - buildings[town][26]->bid = 26; - } - } - - /////done reading BUILDING.TXT***************************** - const JsonNode config(ResourceID("config/hall.json")); - - BOOST_FOREACH(const JsonNode &town, config["town"].Vector()) - { - int tid = town["id"].Float(); - - hall[tid].first = town["image"].String(); - (hall[tid].second).resize(5); //rows - - int row_num = 0; - BOOST_FOREACH(const JsonNode &row, town["boxes"].Vector()) - { - BOOST_FOREACH(const JsonNode &box, row.Vector()) - { - (hall[tid].second)[row_num].push_back(std::vector()); //push new box - std::vector &box_vec = (hall[tid].second)[row_num].back(); - - BOOST_FOREACH(const JsonNode &value, box.Vector()) - { - box_vec.push_back(value.Float()); - } - } - row_num ++; - } - assert (row_num == 5); - } - - // Buildings dependencies. Which building depend on which other building. - const JsonNode buildingsConf(ResourceID("config/buildings.json")); - - // Iterate for each city type - int townID = 0; - BOOST_FOREACH(const JsonNode &town_node, buildingsConf["town_type"].Vector()) - { - BOOST_FOREACH(const JsonNode &node, town_node["building_requirements"].Vector()) - { - int id = node["id"].Float(); - CBuilding * build = buildings[townID][id]; - if (build) - { - BOOST_FOREACH(const JsonNode &building, node["requires"].Vector()) - { - build->requirements.insert(building.Float()); - } - } - } - townID++; - } -} - -CBuildingHandler::~CBuildingHandler() -{ - for(std::vector< bmap > >::iterator i=buildings.begin(); i!=buildings.end(); i++) - for(std::map >::iterator j=i->begin(); j!=i->end(); j++) - j->second.dellNull(); -} - -static std::string emptyStr = ""; - -const std::string & CBuilding::Name() const -{ - if(name.length()) - return name; - else if(vstd::contains(VLC->generaltexth->buildings,tid) && vstd::contains(VLC->generaltexth->buildings[tid],bid)) - return VLC->generaltexth->buildings[tid][bid].first; - tlog2 << "Warning: Cannot find name text for building " << bid << "for " << tid << "town.\n"; - return emptyStr; -} - -const std::string & CBuilding::Description() const -{ - if(description.length()) - return description; - else if(vstd::contains(VLC->generaltexth->buildings,tid) && vstd::contains(VLC->generaltexth->buildings[tid],bid)) - return VLC->generaltexth->buildings[tid][bid].second; - tlog2 << "Warning: Cannot find description text for building " << bid << "for " << tid << "town.\n"; - return emptyStr; -} - -CBuilding::CBuilding( int TID, int BID ) -{ - tid = TID; - bid = BID; -} - int CBuildingHandler::campToERMU( int camp, int townType, std::set builtBuildings ) { using namespace boost::assign; diff --git a/lib/CBuildingHandler.h b/lib/CBuildingHandler.h index 0047ae07f..5228940fa 100644 --- a/lib/CBuildingHandler.h +++ b/lib/CBuildingHandler.h @@ -1,9 +1,5 @@ #pragma once - -#include "../lib/ConstTransitivePtr.h" -#include "ResourceSet.h" - /* * CBuildingHandler.h, part of VCMI engine * @@ -14,39 +10,8 @@ * */ -//enum EbuildingType {NEUTRAL=-1, CASTLE, RAMPART, TOWER, INFERNO, NECROPOLIS, DUNGEON, STRONGHOLD, FORTRESS, CONFLUX}; -class DLL_LINKAGE CBuilding //a typical building encountered in every castle ;] -{ -public: - si32 tid, bid; //town ID and structure ID - TResources resources; - std::string name; - std::string description; - std::set requirements; //set of required buildings - - const std::string &Name() const; - const std::string &Description() const; - - template void serialize(Handler &h, const int version) - { - h & tid & bid & resources & name & description & requirements; - } - CBuilding(int TID = -1, int BID = -1); -}; - class DLL_LINKAGE CBuildingHandler { public: - typedef bmap > TBuildingsMap; - std::vector< TBuildingsMap > buildings; ///< vector by castle ID, second the building ID (in ERM-U format) - bmap > > > > hall; //map >[5]> - external vector is the vector of buildings in the row, internal is the list of buildings for the specific slot - - void loadBuildings(); //main loader - ~CBuildingHandler(); //d-tor static int campToERMU(int camp, int townType, std::set builtBuildings); - - template void serialize(Handler &h, const int version) - { - h & buildings & hall; - } }; diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 7997cb8f9..240db5409 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -1053,30 +1053,12 @@ void CGameState::init(StartInfo * si) } /******************RESOURCES****************************************************/ - TResources startresAI, startresHuman; const JsonNode config(ResourceID("config/startres.json")); const JsonVector &vector = config["difficulty"].Vector(); const JsonNode &level = vector[scenarioOps->difficulty]; - const JsonNode &human = level["human"]; - const JsonNode &ai = level["ai"]; - startresHuman[0] = human["wood"].Float(); - startresHuman[1] = human["mercury"].Float(); - startresHuman[2] = human["ore"].Float(); - startresHuman[3] = human["sulfur"].Float(); - startresHuman[4] = human["crystal"].Float(); - startresHuman[5] = human["gems"].Float(); - startresHuman[6] = human["gold"].Float(); - startresHuman[7] = human["mithril"].Float(); - - startresAI[0] = ai["wood"].Float(); - startresAI[1] = ai["mercury"].Float(); - startresAI[2] = ai["ore"].Float(); - startresAI[3] = ai["sulfur"].Float(); - startresAI[4] = ai["crystal"].Float(); - startresAI[5] = ai["gems"].Float(); - startresAI[6] = ai["gold"].Float(); - startresAI[7] = ai["mithril"].Float(); + TResources startresAI(level["ai"]); + TResources startresHuman(level["human"]); for (std::map::iterator i = players.begin(); i!=players.end(); i++) { diff --git a/lib/CObjectHandler.cpp b/lib/CObjectHandler.cpp index 8d3f5827e..71d414b5e 100644 --- a/lib/CObjectHandler.cpp +++ b/lib/CObjectHandler.cpp @@ -7267,7 +7267,7 @@ GrowthInfo::Entry::Entry(const std::string &format, int _count) GrowthInfo::Entry::Entry(int subID, EBuilding::EBuilding building, int _count) : count(_count) { - description = boost::str(boost::format("%s %+d") % VLC->buildh->buildings[subID][building]->Name() % count); + description = boost::str(boost::format("%s %+d") % VLC->townh->towns[subID].buildings[building]->Name() % count); } CTownAndVisitingHero::CTownAndVisitingHero() diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp index 24822ea2f..378c25120 100644 --- a/lib/CTownHandler.cpp +++ b/lib/CTownHandler.cpp @@ -17,148 +17,26 @@ * */ -CTownHandler::CTownHandler() +static std::string emptyStr = ""; + +const std::string & CBuilding::Name() const { - VLC->townh = this; + if(name.length()) + return name; + else if(vstd::contains(VLC->generaltexth->buildings,tid) && vstd::contains(VLC->generaltexth->buildings[tid],bid)) + return VLC->generaltexth->buildings[tid][bid].first; + tlog2 << "Warning: Cannot find name text for building " << bid << "for " << tid << "town.\n"; + return emptyStr; } -CTownHandler::~CTownHandler() + +const std::string & CBuilding::Description() const { - for( std::vector >::iterator i= structures.begin(); i!=structures.end(); i++) - for( std::map::iterator j = i->begin(); j!=i->end(); j++) - delete j->second; -} -void CTownHandler::loadStructures() -{ - int townID; - - for (townID=0; townID &town = structures[townID]; - - // Read buildings coordinates for that city - BOOST_FOREACH(const JsonNode &node, town_node["defnames"].Vector()) { - Structure *vinya = new Structure; - const JsonNode *value; - - vinya->group = -1; - vinya->townID = townID; - vinya->ID = node["id"].Float(); - vinya->defName = node["defname"].String(); - vinya->name = vinya->defName; //TODO - use normal names - vinya->pos.x = node["x"].Float(); - vinya->pos.y = node["y"].Float(); - vinya->pos.z = 0; - - value = &node["border"]; - if (!value->isNull()) - vinya->borderName = value->String(); - - value = &node["area"]; - if (!value->isNull()) - vinya->areaName = value->String(); - - town[vinya->ID] = vinya; - } - - // Read buildings blit order for that city - int itr = 1; - BOOST_FOREACH(const JsonNode &node, town_node["blit_order"].Vector()) { - int buildingID = node.Float(); - - /* Find the building and set its order. */ - std::map::iterator i2 = town.find(buildingID); - if (i2 != (town.end())) - i2->second->pos.z = itr++; - else - tlog3 << "Warning1: No building " << buildingID << " in the castle " << townID << std::endl; - } - - // Read creatures belonging to that city - level = 0; - BOOST_FOREACH(const JsonNode &list, town_node["creatures"].Vector()) - { - BOOST_FOREACH(const JsonNode &node, list.Vector()) - { - towns[townID].creatures[level].push_back(node.Float()); - } - level ++; - } - - // Horde building creature level - level = 0; - BOOST_FOREACH(const JsonNode &node, town_node["horde"].Vector()) { - towns[townID].hordeLvl[level] = node.Float(); - level ++; - } - - // Misc. - towns[townID].mageLevel = town_node["mage_guild"].Float(); - towns[townID].primaryRes = town_node["primary_resource"].Float(); - towns[townID].warMachine = town_node["war_machine"].Float(); - - townID ++; - } - - int group_num=0; - - // Iterate for each city - BOOST_FOREACH(const JsonNode &town_node, config["town_groups"].Vector()) { - townID = town_node["id"].Float(); - - // Iterate for each group for that city - BOOST_FOREACH(const JsonNode &group, town_node["groups"].Vector()) { - - group_num ++; - - // Iterate for each bulding value in the group - BOOST_FOREACH(const JsonNode &value, group.Vector()) { - int buildingID = value.Float(); - - std::vector >::iterator i; - std::map::iterator i2; - - if (townID >= 0) { - if ((i = structures.begin() + townID) != structures.end()) { - if ((i2=(i->find(buildingID)))!=(i->end())) - i2->second->group = group_num; - else - tlog3 << "Warning3: No building "<begin(); i2!=i->end(); i2++) { - if(i2->first == buildingID) { - i2->second->group = group_num; - break; - } - } - } - } - } - } - } + if(description.length()) + return description; + else if(vstd::contains(VLC->generaltexth->buildings,tid) && vstd::contains(VLC->generaltexth->buildings[tid],bid)) + return VLC->generaltexth->buildings[tid][bid].second; + tlog2 << "Warning: Cannot find description text for building " << bid << "for " << tid << "town.\n"; + return emptyStr; } const std::string & CTown::Name() const @@ -173,6 +51,267 @@ const std::vector & CTown::Names() const { if(names.size()) return names; - else + else return VLC->generaltexth->townNames[typeID]; } + +CTownHandler::CTownHandler() +{ + VLC->townh = this; +} + +JsonNode readBuilding(CLegacyConfigParser & parser) +{ + JsonNode ret; + JsonNode & cost = ret["cost"]; + + const std::string resources [] = {"wood", "mercury", "ore", "sulfur", "crystal", "gems", "gold"}; + + BOOST_FOREACH(const std::string & resID, resources) + cost[resID].Float() = parser.readNumber(); + + parser.endLine(); + return ret; +} + +void CTownHandler::loadLegacyData(JsonNode & dest) +{ + CLegacyConfigParser parser("DATA/BUILDING.TXT"); + dest.Vector().resize(GameConstants::F_NUMBER); + + parser.endLine(); // header + parser.endLine(); + + //Unique buildings + for (size_t town=0; townname = source["name"].String(); + ret->description = source["description"].String(); + + ret->tid = town.typeID; + ret->bid = source["id"].Float(); + + ret->resources = TResources(source["cost"]); + + BOOST_FOREACH(const JsonNode &building, source["requires"].Vector()) + ret->requirements.insert(building.Float()); + + town.buildings[ret->bid] = ret; +} + +void CTownHandler::loadBuildings(CTown &town, const JsonNode & source) +{ + BOOST_FOREACH(const JsonNode &node, source.Vector()) + { + loadBuilding(town, node); + } +} + +void CTownHandler::loadStructure(CTown &town, const JsonNode & source) +{ + CStructure * ret = new CStructure; + + ret->ID = source["id"].Float(); + ret->pos.x = source["x"].Float(); + ret->pos.y = source["y"].Float(); + ret->pos.z = 0; + + ret->defName = source["defname"].String(); + ret->borderName = source["border"].String(); + ret->areaName = source["area"].String(); + + ret->group = -1; + ret->townID = town.typeID; + + town.clientInfo.structures[ret->ID] = ret; +} + +void CTownHandler::loadStructures(CTown &town, const JsonNode & source) +{ + BOOST_FOREACH(const JsonNode &node, source["structures"].Vector()) + { + loadStructure(town, node); + } + + // Read buildings blit order for that city + int itr = 1; + BOOST_FOREACH(const JsonNode &node, source["blit_order"].Vector()) + { + int buildingID = node.Float(); + + /* Find the building and set its order. */ + auto i2 = town.clientInfo.structures.find(buildingID); + if (i2 != (town.clientInfo.structures.end())) + i2->second->pos.z = itr++; + } + + // Iterate for each group for that city + int groupID = 0; + BOOST_FOREACH(const JsonNode &group, source["groups"].Vector()) + { + groupID++; + + // Iterate for each bulding value in the group + BOOST_FOREACH(const JsonNode &value, group.Vector()) + { + auto buildingIter = town.clientInfo.structures.find(value.Float()); + + if (buildingIter != town.clientInfo.structures.end()) + { + buildingIter->second->group = groupID; + } + } + } +} + +void CTownHandler::loadTownHall(CTown &town, const JsonNode & source) +{ + BOOST_FOREACH(const JsonNode &row, source.Vector()) + { + std::vector< std::vector > hallRow; + + BOOST_FOREACH(const JsonNode &box, row.Vector()) + { + std::vector hallBox; + + BOOST_FOREACH(const JsonNode &value, box.Vector()) + { + hallBox.push_back(value.Float()); + } + hallRow.push_back(hallBox); + } + town.clientInfo.hallSlots.push_back(hallRow); + } +} + +void CTownHandler::loadTown(std::vector &towns, const JsonNode & source) +{ + towns.push_back(CTown()); + CTown & town = towns.back(); + + //TODO: allow loading name and names vector from json and from h3 txt's + + town.typeID = towns.size() - 1; + + town.bonus = town.typeID; + if (town.bonus==8) + town.bonus=3; + + town.clientInfo.hallBackground = source["hallBackground"].String(); + town.mageLevel = source["mage_guild"].Float(); + town.primaryRes = source["primary_resource"].Float(); + town.warMachine = source["war_machine"].Float(); + + // Horde building creature level + BOOST_FOREACH(const JsonNode &node, source["horde"].Vector()) + { + town.hordeLvl[town.hordeLvl.size()] = node.Float(); + } + + BOOST_FOREACH(const JsonNode &list, source["creatures"].Vector()) + { + std::vector level; + BOOST_FOREACH(const JsonNode &node, list.Vector()) + { + level.push_back(node.Float()); + } + town.creatures.push_back(level); + } + + loadTownHall(town, source["hallSlots"]); + loadBuildings(town, source["buildings"]); + loadStructures(town, source); +} + +void CTownHandler::loadTowns(std::vector &towns, const JsonNode & source) +{ + BOOST_FOREACH(const JsonNode & node, source.Vector()) + { + loadTown(towns, node); + } + + // ensure that correct number of town have been loaded. Safe to remove + assert(towns.size() == GameConstants::F_NUMBER); +} + +void CTownHandler::load() +{ + JsonNode buildingsConf(ResourceID("config/buildings.json")); + + JsonNode legacyConfig; + loadLegacyData(legacyConfig); + + // semi-manually merge legacy config with towns json + // legacy config have only one item: town buildings stored in 2d vector + size_t townsToMerge = std::min(buildingsConf["towns"].Vector().size(), legacyConfig.Vector().size()); + for (size_t i=0; i< townsToMerge; i++) + { + JsonNode & buildings = buildingsConf["towns"].Vector()[i]["buildings"]; + BOOST_FOREACH(JsonNode & building, buildings.Vector()) + { + if (vstd::contains(building.Struct(), "id")) + { + JsonNode & legacyBuilding = legacyConfig.Vector()[i].Vector()[building["id"].Float()]; + + if (!legacyBuilding.isNull()) + JsonNode::merge(building, legacyBuilding); + } + } + } + + loadTowns(towns, buildingsConf["towns"]); +} diff --git a/lib/CTownHandler.h b/lib/CTownHandler.h index a06cc88ff..2f51cb4da 100644 --- a/lib/CTownHandler.h +++ b/lib/CTownHandler.h @@ -1,6 +1,7 @@ #pragma once - +#include "ConstTransitivePtr.h" +#include "ResourceSet.h" #include "int3.h" /* @@ -13,66 +14,137 @@ * */ -class CBuilding; -class CSpell; -class CHero; -class CGTownInstance; -class DLL_LINKAGE CTown +class CLegacyConfigParser; +class JsonNode; + +/// a typical building encountered in every castle ;] +/// this is structure available to both client and server +/// contains all mechanics-related data about town structures +class DLL_LINKAGE CBuilding { - std::string name; //name of type + std::string name; + std::string description; + public: + si32 tid, bid; //town ID and structure ID + TResources resources; + std::set requirements; //set of required buildings - std::vector names; //names of the town instances - std::vector > creatures; //level (from 0) -> list of creatures on this tier - std::map hordeLvl; //[0] - first horde building creature level; [1] - second horde building (-1 if not present) - ui32 mageLevel; //max available mage guild level - int bonus; //pic number - ui16 primaryRes, warMachine; - ui8 typeID; - - - const std::vector & Names() const; - const std::string & Name() const; - void Name(const std::string & val) { name = val; } - + const std::string &Name() const; + const std::string &Description() const; template void serialize(Handler &h, const int version) { - h & names & creatures & hordeLvl & mageLevel & bonus - & primaryRes & warMachine & typeID; + h & tid & bid & resources & name & description & requirements; } + + friend class CTownHandler; }; -struct DLL_LINKAGE Structure +/// This is structure used only by client +/// Consists of all gui-related data about town structures +/// Should be mode from lib to client +struct DLL_LINKAGE CStructure { int ID; int3 pos; - std::string defName, borderName, areaName, name; + std::string defName, borderName, areaName; int townID, group; - bool operator<(const Structure & p2) const + bool operator<(const CStructure & p2) const { if(pos.z != p2.pos.z) return (pos.z) < (p2.pos.z); else return (ID) < (p2.ID); } + + template void serialize(Handler &h, const int version) + { + h & ID & pos & defName & borderName & areaName & townID & group; + } +}; + +class DLL_LINKAGE CTown +{ + std::string name; //name of type + std::vector names; //names of the town instances + +public: + ui32 typeID; + + /// level -> list of creatures on this tier + /// TODO: replace with pointers to CCreature? + std::vector > creatures; + + bmap > buildings; + + // should be removed at least from configs in favour of auto-detection + std::map hordeLvl; //[0] - first horde building creature level; [1] - second horde building (-1 if not present) + ui32 mageLevel; //max available mage guild level + int bonus; //pic number + ui16 primaryRes, warMachine; + + // Client-only data. Should be moved away from lib + struct ClientInfo + { + std::string hallBackground; + std::vector< std::vector< std::vector > > hallSlots; /// vector[row][column] = list of buildings in this slot + bmap > structures; + + template void serialize(Handler &h, const int version) + { + h & hallBackground & hallSlots & structures; + } + } clientInfo; + + const std::vector & Names() const; + const std::string & Name() const; + + template void serialize(Handler &h, const int version) + { + h & name & names & typeID & creatures & buildings & hordeLvl & mageLevel & bonus + & primaryRes & warMachine & clientInfo; + } + + friend class CTownHandler; }; class DLL_LINKAGE CTownHandler { + /// loads CBuilding's into town + void loadBuilding(CTown &town, const JsonNode & source); + void loadBuildings(CTown &town, const JsonNode & source); + + /// loads CStructure's into town + void loadStructure(CTown &town, const JsonNode & source); + void loadStructures(CTown &town, const JsonNode & source); + + /// loads town hall vector (hallSlots) + void loadTownHall(CTown &town, const JsonNode & source); + + /// load town and insert it into towns vector + void loadTown(std::vector &towns, const JsonNode & source); + + /// main loading function, accepts merged JSON source and add all entries from it into game + /// all entries in JSON should be checked for validness before using this function + void loadTowns(std::vector &towns, const JsonNode & source); + + /// load all available data from h3 txt(s) into json structure using format similar to vcmi configs + /// returns 2d array [townID] [buildID] of buildings + void loadLegacyData(JsonNode & dest); public: std::vector towns; - std::vector > structures; // > - CTownHandler(); //c-tor - ~CTownHandler(); //d-tor - void loadStructures(); + CTownHandler(); //c-tor, set pointer in VLC to this + + /// "entry point" for towns loading. + /// reads legacy txt's from H3 + vcmi json, merges them + /// and loads resulting structure to game using loadTowns method + void load(); template void serialize(Handler &h, const int version) { h & towns; - if(!h.saving) - loadStructures(); } }; diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index 5a3174899..c319ad610 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -547,7 +547,7 @@ int CGameInfoCallback::canBuildStructure( const CGTownInstance *t, int ID ) if(t->builded >= GameConstants::MAX_BUILDING_PER_TURN) ret = EBuildingState::CANT_BUILD_TODAY; //building limit - CBuilding * pom = VLC->buildh->buildings[t->subID][ID]; + CBuilding * pom = t->town->buildings[ID]; if(!pom) return EBuildingState::BUILDING_ERROR; @@ -603,7 +603,7 @@ std::set CGameInfoCallback::getBuildingRequiments( const CGTownInstance *t, std::set used; used.insert(ID); - std::set reqs = VLC->buildh->buildings[t->subID][ID]->requirements; + std::set reqs = t->town->buildings[ID]->requirements; while(true) { @@ -614,8 +614,8 @@ std::set CGameInfoCallback::getBuildingRequiments( const CGTownInstance *t, { used.insert(*i); for( - std::set::iterator j=VLC->buildh->buildings[t->subID][*i]->requirements.begin(); - j!= VLC->buildh->buildings[t->subID][*i]->requirements.end(); + std::set::iterator j= t->town->buildings[*i]->requirements.begin(); + j!= t->town->buildings[*i]->requirements.end(); j++) { reqs.insert(*j);//creating full list of requirements diff --git a/lib/JsonNode.cpp b/lib/JsonNode.cpp index 490f7ff97..51ba93ce2 100644 --- a/lib/JsonNode.cpp +++ b/lib/JsonNode.cpp @@ -236,6 +236,38 @@ const JsonNode & JsonNode::operator[](std::string child) const return it->second; return nullNode; } +//////////////////////////////////////////////////////////////////////////////// + +void JsonNode::merge(JsonNode & dest, JsonNode & source) +{ + switch (source.getType()) + { + break; case DATA_NULL: dest.setType(DATA_NULL); + break; case DATA_BOOL: std::swap(dest.Bool(), source.Bool()); + break; case DATA_FLOAT: std::swap(dest.Float(), source.Float()); + break; case DATA_STRING: std::swap(dest.String(), source.String()); + break; case DATA_VECTOR: + { + //reserve place and *move* data from source to dest + source.Vector().reserve(source.Vector().size() + dest.Vector().size()); + + std::move(source.Vector().begin(), source.Vector().end(), + std::back_inserter(dest.Vector())); + } + break; case DATA_STRUCT: + { + //recursively merge all entries from struct + BOOST_FOREACH(auto & node, source.Struct()) + merge(dest[node.first], node.second); + } + } +} + +void JsonNode::mergeCopy(JsonNode & dest, JsonNode source) +{ + // uses copy created in stack to safely merge two nodes + merge(dest, source); +} //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/JsonNode.h b/lib/JsonNode.h index bdafb4cc5..f46f3cdaf 100644 --- a/lib/JsonNode.h +++ b/lib/JsonNode.h @@ -94,6 +94,17 @@ public: //error value for const operator[] static const JsonNode nullNode; + + /// recursivly merges source into dest, replacing identical fields + /// struct : recursively calls this function + /// arrays : append array in dest with data from source + /// values : value in source will replace value in dest + /// null : if value in source is present but set to null it will delete entry in dest + + /// this function will destroy data in source + static void merge(JsonNode & dest, JsonNode & source); + /// this function will preserve data stored in source by creating copy + static void mergeCopy(JsonNode & dest, JsonNode source); }; class JsonWriter diff --git a/lib/ResourceSet.cpp b/lib/ResourceSet.cpp index 2b42073b7..eb558816a 100644 --- a/lib/ResourceSet.cpp +++ b/lib/ResourceSet.cpp @@ -1,10 +1,24 @@ #include "StdInc.h" #include "ResourceSet.h" #include "GameConstants.h" - +#include "JsonNode.h" + Res::ResourceSet::ResourceSet() { resize(GameConstants::RESOURCE_QUANTITY, 0); +} + +Res::ResourceSet::ResourceSet(const JsonNode & node) +{ + resize(GameConstants::RESOURCE_QUANTITY, 0); + at(0) = node["wood"].Float(); + at(1) = node["mercury"].Float(); + at(2) = node["ore"].Float(); + at(3) = node["sulfur"].Float(); + at(4) = node["crystal"].Float(); + at(5) = node["gems"].Float(); + at(6) = node["gold"].Float(); + at(7) = node["mithril"].Float(); } bool Res::ResourceSet::nonZero() const diff --git a/lib/ResourceSet.h b/lib/ResourceSet.h index 707c4885d..17a819886 100644 --- a/lib/ResourceSet.h +++ b/lib/ResourceSet.h @@ -3,6 +3,8 @@ typedef si32 TResource; typedef si64 TResourceCap; //to avoid overflow when adding integers. Signed values are easier to control. +class JsonNode; + namespace Res { class ResourceSet; @@ -18,6 +20,8 @@ namespace Res { public: DLL_LINKAGE ResourceSet(); + // read resources set from json. Format example: { "gold": 500, "wood":5 } + DLL_LINKAGE ResourceSet(const JsonNode & node); #define scalarOperator(OPSIGN) \ diff --git a/lib/VCMI_Lib.cpp b/lib/VCMI_Lib.cpp index ddb005000..92e272021 100644 --- a/lib/VCMI_Lib.cpp +++ b/lib/VCMI_Lib.cpp @@ -87,7 +87,7 @@ void LibClasses::init() tlog0<<"\tCreature handler: "<loadStructures(); + townh->load(); tlog0<<"\tTown handler: "<load(); tlog0<<"\tDef information handler: "<loadBuildings(); - tlog0<<"\tBuilding handler: "<loadSpells(); tlog0<<"\tSpell handler: "< void serialize(Handler &h, const int version) { - h & heroh & arth & creh & townh & objh & dobjinfo & buildh & spellh & modh & IS_AI_ENABLED;; + h & heroh & arth & creh & townh & objh & dobjinfo & spellh & modh & IS_AI_ENABLED;; if(!h.saving) { callWhenDeserializing(); diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index be4db55d8..8c0c459a3 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2417,7 +2417,7 @@ bool CGameHandler::disbandCreature( si32 id, ui8 pos ) bool CGameHandler::buildStructure( si32 tid, si32 bid, bool force /*=false*/ ) { CGTownInstance * t = static_cast(gs->map->objects[tid].get()); - CBuilding * b = VLC->buildh->buildings[t->subID][bid]; + CBuilding * b = t->town->buildings[bid]; if(!force) { @@ -3729,7 +3729,7 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message ) CGTownInstance *town = gs->getTown(gs->getPlayer(player)->currentSelection); if (town) { - BOOST_FOREACH (CBuildingHandler::TBuildingsMap::value_type &build, VLC->buildh->buildings[town->subID]) + BOOST_FOREACH (auto & build, town->town->buildings) { if (!vstd::contains(town->builtBuildings, build.first) && !build.second->Name().empty())