diff --git a/config/factions/conflux.json b/config/factions/conflux.json index 6de579017..c18302986 100644 --- a/config/factions/conflux.json +++ b/config/factions/conflux.json @@ -178,7 +178,16 @@ "horde1": { "id" : 18, "upgrades" : "dwellingLvl1" }, "horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" }, "ship": { "id" : 20, "upgrades" : "shipyard" }, - "special2": { "requires" : [ "mageGuild1" ], "marketModes" : ["resource-skill"] }, + "special2": { + "requires" : [ "mageGuild1" ], + "marketModes" : ["resource-skill"], + "marketOffer" : [ + "fireMagic", + "airMagic", + "waterMagic", + "earthMagic" + ] + }, "grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }}, "extraTownHall": { "id" : 27, "requires" : [ "townHall" ], "mode" : "auto" }, "extraCityHall": { "id" : 28, "requires" : [ "cityHall" ], "mode" : "auto" }, diff --git a/config/schemas/townBuilding.json b/config/schemas/townBuilding.json index 691089b99..b8c5e7e5c 100644 --- a/config/schemas/townBuilding.json +++ b/config/schemas/townBuilding.json @@ -134,5 +134,13 @@ }, "description" : "List of modes available in this market" } + + "marketOffer" : { + "type" : "array", + "items" : { + "type" : "string" + }, + "description" : "List of predefined items available on market from this building" + } } } diff --git a/docs/modders/Entities_Format/Town_Building_Format.md b/docs/modders/Entities_Format/Town_Building_Format.md index c97b87c7b..b9950730c 100644 --- a/docs/modders/Entities_Format/Town_Building_Format.md +++ b/docs/modders/Entities_Format/Town_Building_Format.md @@ -213,6 +213,10 @@ These are just a couple of examples of what can be done in VCMI. See vcmi config // If the building is a market, it requires market mode. "marketModes" : [ "resource-resource", "resource-player" ], + + // Required if building offers resource-skill trade. + // NOTE: multiple resource-skill buildings in the same town are not supported + "marketOffer" : [ "fireMagic", "airMagic", "waterMagic", "earthMagic" ], } ``` diff --git a/lib/entities/building/CBuilding.h b/lib/entities/building/CBuilding.h index ed8a71f3b..3aab24c49 100644 --- a/lib/entities/building/CBuilding.h +++ b/lib/entities/building/CBuilding.h @@ -15,6 +15,7 @@ #include "../../LogicalExpression.h" #include "../../ResourceSet.h" #include "../../bonuses/BonusList.h" +#include "../../networkPacks/TradeItem.h" #include "../../rewardable/Info.h" VCMI_LIB_NAMESPACE_BEGIN @@ -39,6 +40,7 @@ public: ArtifactID warMachine; TownFortifications fortifications; std::set marketModes; + std::vector marketOffer; BuildingID bid; //structure ID BuildingID upgrade; /// indicates that building "upgrade" can be improved by this, -1 = empty diff --git a/lib/entities/faction/CTownHandler.cpp b/lib/entities/faction/CTownHandler.cpp index b07442b95..d9ba913e2 100644 --- a/lib/entities/faction/CTownHandler.cpp +++ b/lib/entities/faction/CTownHandler.cpp @@ -386,7 +386,23 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons for(const auto & element : source["marketModes"].Vector()) { if(MappedKeys::MARKET_NAMES_TO_TYPES.count(element.String())) - ret->marketModes.insert(MappedKeys::MARKET_NAMES_TO_TYPES.at(element.String())); + { + auto mode = MappedKeys::MARKET_NAMES_TO_TYPES.at(element.String()); + ret->marketModes.insert(mode); + + if (mode == EMarketMode::RESOURCE_SKILL) + { + const auto & items = source["marketOffer"].Vector(); + ret->marketOffer.resize(items.size()); + for (int i = 0; i < items.size(); ++i) + { + LIBRARY->identifiers()->requestIdentifier("secondarySkill", items[i], [ret, i](si32 identifier) + { + ret->marketOffer[i] = SecondarySkill(identifier); + }); + } + } + } } registerObject(source.getModScope(), ret->town->getBuildingScope(), ret->identifier, ret->bid.getNum()); diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index 327c06d37..1b2a45db3 100644 --- a/lib/gameState/CGameState.cpp +++ b/lib/gameState/CGameState.cpp @@ -787,12 +787,6 @@ void CGameState::initTowns(vstd::RNG & randomGenerator) if (campaign) campaign->initTowns(); - map->townUniversitySkills.clear(); - map->townUniversitySkills.push_back(SecondarySkill(SecondarySkill::FIRE_MAGIC)); - map->townUniversitySkills.push_back(SecondarySkill(SecondarySkill::AIR_MAGIC)); - map->townUniversitySkills.push_back(SecondarySkill(SecondarySkill::WATER_MAGIC)); - map->townUniversitySkills.push_back(SecondarySkill(SecondarySkill::EARTH_MAGIC)); - for (const auto & townID : map->getAllTowns()) { auto vti = getTown(townID); diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index 4d39ab2d6..b5753da0e 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -683,7 +683,15 @@ std::vector CGTownInstance::availableItemsIds(EMarketMode mode) co } else if ( mode == EMarketMode::RESOURCE_SKILL ) { - return cb->gameState().getMap().townUniversitySkills; + for (const auto & buildingID : builtBuildings) + { + const auto * buildingPtr = getTown()->buildings.at(buildingID).get(); + if (vstd::contains(buildingPtr->marketModes, mode)) + return buildingPtr->marketOffer; + } + + logMod->warn("Town has resource-skill trade but has no skills to offer!"); + return {}; } else return IMarket::availableItemsIds(mode); diff --git a/lib/mapping/CMap.h b/lib/mapping/CMap.h index 743f7e8fb..5671b2484 100644 --- a/lib/mapping/CMap.h +++ b/lib/mapping/CMap.h @@ -272,7 +272,6 @@ public: std::map obelisksVisited; //map: team_id => how many obelisks has been visited std::vector townMerchantArtifacts; - std::vector townUniversitySkills; void overrideGameSettings(const JsonNode & input); void overrideGameSetting(EGameSettings option, const JsonNode & input); @@ -345,7 +344,11 @@ public: h & obeliskCount; h & obelisksVisited; h & townMerchantArtifacts; - h & townUniversitySkills; + if (!h.hasFeature(Handler::Version::STORE_UID_COUNTER_IN_CMAP)) + { + std::vector townUniversitySkills; + h & townUniversitySkills; + } h & instanceNames; h & *gameSettings; diff --git a/lib/serializer/ESerializationVersion.h b/lib/serializer/ESerializationVersion.h index 709c8b8f9..3b3821fac 100644 --- a/lib/serializer/ESerializationVersion.h +++ b/lib/serializer/ESerializationVersion.h @@ -45,8 +45,9 @@ enum class ESerializationVersion : int32_t CUSTOM_BONUS_ICONS, // support for custom icons in bonuses SERVER_STATISTICS, // statistics now only saved on server OPPOSITE_SIDE_LIMITER_OWNER, // opposite side limiter no longer stores owner in itself + UNIVERSITY_CONFIG, // town university is configurable - CURRENT = OPPOSITE_SIDE_LIMITER_OWNER, + CURRENT = UNIVERSITY_CONFIG, }; static_assert(ESerializationVersion::MINIMAL <= ESerializationVersion::CURRENT, "Invalid serialization version definition!");