1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

IMarket now able to store artifacts

This commit is contained in:
SoundSSGood 2024-08-16 18:00:02 +03:00
parent fd45b5144d
commit 39bb6d5f39
14 changed files with 123 additions and 74 deletions

View File

@ -804,10 +804,10 @@ void CGameState::initTowns()
//init buildings //init buildings
if(vstd::contains(vti->builtBuildings, BuildingID::DEFAULT)) //give standard set of buildings if(vstd::contains(vti->builtBuildings, BuildingID::DEFAULT)) //give standard set of buildings
{ {
vti->builtBuildings.erase(BuildingID::DEFAULT); vti->removeBuilding(BuildingID::DEFAULT);
vti->builtBuildings.insert(BuildingID::VILLAGE_HALL); vti->addBuilding(BuildingID::VILLAGE_HALL);
if(vti->tempOwner != PlayerColor::NEUTRAL) if(vti->tempOwner != PlayerColor::NEUTRAL)
vti->builtBuildings.insert(BuildingID::TAVERN); vti->addBuilding(BuildingID::TAVERN);
auto definesBuildingsChances = VLC->settings()->getVector(EGameSettings::TOWNS_STARTING_DWELLING_CHANCES); auto definesBuildingsChances = VLC->settings()->getVector(EGameSettings::TOWNS_STARTING_DWELLING_CHANCES);
@ -815,32 +815,32 @@ void CGameState::initTowns()
{ {
if((getRandomGenerator().nextInt(1,100) <= definesBuildingsChances[i])) if((getRandomGenerator().nextInt(1,100) <= definesBuildingsChances[i]))
{ {
vti->builtBuildings.insert(basicDwellings[i]); vti->addBuilding(basicDwellings[i]);
} }
} }
} }
// village hall must always exist // village hall must always exist
vti->builtBuildings.insert(BuildingID::VILLAGE_HALL); vti->addBuilding(BuildingID::VILLAGE_HALL);
//init hordes //init hordes
for (int i = 0; i < vti->town->creatures.size(); i++) for (int i = 0; i < vti->town->creatures.size(); i++)
{ {
if (vstd::contains(vti->builtBuildings, hordes[i])) //if we have horde for this level if (vstd::contains(vti->builtBuildings, hordes[i])) //if we have horde for this level
{ {
vti->builtBuildings.erase(hordes[i]);//remove old ID vti->removeBuilding(hordes[i]);//remove old ID
if (vti->getTown()->hordeLvl.at(0) == i)//if town first horde is this one if (vti->getTown()->hordeLvl.at(0) == i)//if town first horde is this one
{ {
vti->builtBuildings.insert(BuildingID::HORDE_1);//add it vti->addBuilding(BuildingID::HORDE_1);//add it
//if we have upgraded dwelling as well //if we have upgraded dwelling as well
if (vstd::contains(vti->builtBuildings, upgradedDwellings[i])) if (vstd::contains(vti->builtBuildings, upgradedDwellings[i]))
vti->builtBuildings.insert(BuildingID::HORDE_1_UPGR);//add it as well vti->addBuilding(BuildingID::HORDE_1_UPGR);//add it as well
} }
if (vti->getTown()->hordeLvl.at(1) == i)//if town second horde is this one if (vti->getTown()->hordeLvl.at(1) == i)//if town second horde is this one
{ {
vti->builtBuildings.insert(BuildingID::HORDE_2); vti->addBuilding(BuildingID::HORDE_2);
if (vstd::contains(vti->builtBuildings, upgradedDwellings[i])) if (vstd::contains(vti->builtBuildings, upgradedDwellings[i]))
vti->builtBuildings.insert(BuildingID::HORDE_2_UPGR); vti->addBuilding(BuildingID::HORDE_2_UPGR);
} }
} }
} }
@ -853,7 +853,7 @@ void CGameState::initTowns()
}); });
if (vstd::contains(vti->builtBuildings, BuildingID::SHIPYARD) && vti->shipyardStatus()==IBoatGenerator::TILE_BLOCKED) if (vstd::contains(vti->builtBuildings, BuildingID::SHIPYARD) && vti->shipyardStatus()==IBoatGenerator::TILE_BLOCKED)
vti->builtBuildings.erase(BuildingID::SHIPYARD);//if we have harbor without water - erase it (this is H3 behaviour) vti->removeBuilding(BuildingID::SHIPYARD);//if we have harbor without water - erase it (this is H3 behaviour)
//Early check for #1444-like problems //Early check for #1444-like problems
for([[maybe_unused]] const auto & building : vti->builtBuildings) for([[maybe_unused]] const auto & building : vti->builtBuildings)

View File

@ -664,10 +664,10 @@ void CGameStateCampaign::initTowns()
if (newBuilding == BuildingID::NONE) if (newBuilding == BuildingID::NONE)
break; break;
if (town->builtBuildings.count(newBuilding) != 0) if(town->hasBuilt(newBuilding))
break; break;
town->builtBuildings.insert(newBuilding); town->addBuilding(newBuilding);
auto building = town->town->buildings.at(newBuilding); auto building = town->town->buildings.at(newBuilding);
newBuilding = building->upgrade; newBuilding = building->upgrade;

View File

@ -248,7 +248,7 @@ CGMarket * MarketInstanceConstructor::createObject(IGameCallback * cb) const
void MarketInstanceConstructor::initializeObject(CGMarket * market) const void MarketInstanceConstructor::initializeObject(CGMarket * market) const
{ {
market->marketModes = marketModes; market->addMarketMode(marketModes);
market->marketEfficiency = marketEfficiency; market->marketEfficiency = marketEfficiency;
if(auto univercity = dynamic_cast<CGUniversity*>(market)) if(auto univercity = dynamic_cast<CGUniversity*>(market))

View File

@ -38,11 +38,6 @@ int CGMarket::getMarketEfficiency() const
return marketEfficiency; return marketEfficiency;
} }
bool CGMarket::allowsTrade(EMarketMode mode) const
{
return marketModes.count(mode);
}
int CGMarket::availableUnits(EMarketMode mode, int marketItemSerial) const int CGMarket::availableUnits(EMarketMode mode, int marketItemSerial) const
{ {
return -1; return -1;

View File

@ -18,8 +18,6 @@ VCMI_LIB_NAMESPACE_BEGIN
class DLL_LINKAGE CGMarket : public CGObjectInstance, public IMarket class DLL_LINKAGE CGMarket : public CGObjectInstance, public IMarket
{ {
public: public:
std::set<EMarketMode> marketModes;
int marketEfficiency; int marketEfficiency;
CGMarket(IGameCallback *cb); CGMarket(IGameCallback *cb);
@ -29,7 +27,6 @@ public:
///IMarket ///IMarket
int getMarketEfficiency() const override; int getMarketEfficiency() const override;
bool allowsTrade(EMarketMode mode) const override;
int availableUnits(EMarketMode mode, int marketItemSerial) const override; //-1 if unlimited int availableUnits(EMarketMode mode, int marketItemSerial) const override; //-1 if unlimited
std::vector<TradeItemBuy> availableItemsIds(EMarketMode mode) const override; std::vector<TradeItemBuy> availableItemsIds(EMarketMode mode) const override;
@ -37,7 +34,6 @@ public:
{ {
h & static_cast<CGObjectInstance&>(*this); h & static_cast<CGObjectInstance&>(*this);
h & static_cast<IMarket&>(*this); h & static_cast<IMarket&>(*this);
h & marketModes;
h & marketEfficiency; h & marketEfficiency;
} }
}; };

View File

@ -690,35 +690,6 @@ int CGTownInstance::getMarketEfficiency() const
return marketCount; return marketCount;
} }
bool CGTownInstance::allowsTrade(EMarketMode mode) const
{
switch(mode)
{
case EMarketMode::RESOURCE_RESOURCE:
case EMarketMode::RESOURCE_PLAYER:
return hasBuilt(BuildingID::MARKETPLACE);
case EMarketMode::ARTIFACT_RESOURCE:
case EMarketMode::RESOURCE_ARTIFACT:
return hasBuilt(BuildingSubID::ARTIFACT_MERCHANT);
case EMarketMode::CREATURE_RESOURCE:
return hasBuilt(BuildingSubID::FREELANCERS_GUILD);
case EMarketMode::CREATURE_UNDEAD:
return hasBuilt(BuildingSubID::CREATURE_TRANSFORMER);
case EMarketMode::RESOURCE_SKILL:
return hasBuilt(BuildingSubID::MAGIC_UNIVERSITY);
case EMarketMode::CREATURE_EXP:
case EMarketMode::ARTIFACT_EXP:
return false;
default:
assert(0);
return false;
}
}
std::vector<TradeItemBuy> CGTownInstance::availableItemsIds(EMarketMode mode) const std::vector<TradeItemBuy> CGTownInstance::availableItemsIds(EMarketMode mode) const
{ {
if(mode == EMarketMode::RESOURCE_ARTIFACT) if(mode == EMarketMode::RESOURCE_ARTIFACT)
@ -962,6 +933,55 @@ bool CGTownInstance::hasBuilt(const BuildingID & buildingID, FactionID townID) c
return false; return false;
} }
void CGTownInstance::addBuilding(const BuildingID & buildingID)
{
if(buildingID == BuildingID::NONE)
return;
builtBuildings.insert(buildingID);
marketBuildingModeMapper(buildingID, [this](const EMarketMode mode) {addMarketMode(mode);});
}
void CGTownInstance::removeBuilding(const BuildingID & buildingID)
{
if(!vstd::contains(builtBuildings, buildingID))
return;
builtBuildings.erase(buildingID);
marketBuildingModeMapper(buildingID, [this](const EMarketMode mode) {removeMarketMode(mode);});
}
void CGTownInstance::marketBuildingModeMapper(const BuildingID & buildingID, const std::function<void(const EMarketMode)> & func)
{
const auto townType = (*VLC->townh)[getFaction()]->town;
if(townType->buildings.find(buildingID) == townType->buildings.end())
return;
// TODO how to remove hardcoded buildings?
if(buildingID == BuildingID::MARKETPLACE)
{
func(EMarketMode::RESOURCE_RESOURCE);
func(EMarketMode::RESOURCE_PLAYER);
}
else if(townType->buildings.at(buildingID)->subId == BuildingSubID::ARTIFACT_MERCHANT)
{
func(EMarketMode::ARTIFACT_RESOURCE);
func(EMarketMode::RESOURCE_ARTIFACT);
}
else if(townType->buildings.at(buildingID)->subId == BuildingSubID::FREELANCERS_GUILD)
{
func(EMarketMode::CREATURE_RESOURCE);
}
else if(townType->buildings.at(buildingID)->subId == BuildingSubID::CREATURE_TRANSFORMER)
{
func(EMarketMode::CREATURE_UNDEAD);
}
else if(townType->buildings.at(buildingID)->subId == BuildingSubID::MAGIC_UNIVERSITY)
{
func(EMarketMode::RESOURCE_SKILL);
}
}
TResources CGTownInstance::getBuildingCost(const BuildingID & buildingID) const TResources CGTownInstance::getBuildingCost(const BuildingID & buildingID) const
{ {
if (vstd::contains(town->buildings, buildingID)) if (vstd::contains(town->buildings, buildingID))
@ -1132,23 +1152,23 @@ void CGTownInstance::serializeJsonOptions(JsonSerializeFormat & handler)
{ {
handler.serializeLIC("buildings", buildingsLIC); handler.serializeLIC("buildings", buildingsLIC);
builtBuildings.insert(BuildingID::VILLAGE_HALL); addBuilding(BuildingID::VILLAGE_HALL);
if(buildingsLIC.none.empty() && buildingsLIC.all.empty()) if(buildingsLIC.none.empty() && buildingsLIC.all.empty())
{ {
builtBuildings.insert(BuildingID::DEFAULT); addBuilding(BuildingID::DEFAULT);
bool hasFort = false; bool hasFort = false;
handler.serializeBool("hasFort",hasFort); handler.serializeBool("hasFort",hasFort);
if(hasFort) if(hasFort)
builtBuildings.insert(BuildingID::FORT); addBuilding(BuildingID::FORT);
} }
else else
{ {
for(const si32 item : buildingsLIC.none) for(const si32 item : buildingsLIC.none)
forbiddenBuildings.insert(BuildingID(item)); forbiddenBuildings.insert(BuildingID(item));
for(const si32 item : buildingsLIC.all) for(const si32 item : buildingsLIC.all)
builtBuildings.insert(BuildingID(item)); addBuilding(BuildingID(item));
} }
} }
} }

View File

@ -153,7 +153,6 @@ public:
EGeneratorState shipyardStatus() const override; EGeneratorState shipyardStatus() const override;
const IObjectInterface * getObject() const override; const IObjectInterface * getObject() const override;
int getMarketEfficiency() const override; //=market count int getMarketEfficiency() const override; //=market count
bool allowsTrade(EMarketMode mode) const override;
std::vector<TradeItemBuy> availableItemsIds(EMarketMode mode) const override; std::vector<TradeItemBuy> availableItemsIds(EMarketMode mode) const override;
void updateAppearance(); void updateAppearance();
@ -175,6 +174,8 @@ public:
//checks if building is constructed and town has same subID //checks if building is constructed and town has same subID
bool hasBuilt(const BuildingID & buildingID) const; bool hasBuilt(const BuildingID & buildingID) const;
bool hasBuilt(const BuildingID & buildingID, FactionID townID) const; bool hasBuilt(const BuildingID & buildingID, FactionID townID) const;
void addBuilding(const BuildingID & buildingID);
void removeBuilding(const BuildingID & buildingID);
TResources getBuildingCost(const BuildingID & buildingID) const; TResources getBuildingCost(const BuildingID & buildingID) const;
TResources dailyIncome() const; //calculates daily income of this town TResources dailyIncome() const; //calculates daily income of this town
@ -227,6 +228,7 @@ protected:
void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override; void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override;
void serializeJsonOptions(JsonSerializeFormat & handler) override; void serializeJsonOptions(JsonSerializeFormat & handler) override;
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override; void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
void marketBuildingModeMapper(const BuildingID & buildingID, const std::function<void(const EMarketMode)> & func);
private: private:
FactionID randomizeFaction(vstd::RNG & rand); FactionID randomizeFaction(vstd::RNG & rand);

View File

@ -20,6 +20,11 @@
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
bool IMarket::allowsTrade(const EMarketMode mode) const
{
return marketModes.count(mode) > 0;
}
bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode) const bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode) const
{ {
switch(mode) switch(mode)
@ -135,6 +140,28 @@ int IMarket::availableUnits(const EMarketMode mode, const int marketItemSerial)
} }
} }
void IMarket::addMarketMode(const EMarketMode mode)
{
marketModes.insert(mode);
if(mode == EMarketMode::ARTIFACT_EXP)
altarArtifacts = std::make_shared<CArtifactSetAltar>();
}
void IMarket::addMarketMode(const std::set<EMarketMode> & modes)
{
for(const auto & mode : modes)
addMarketMode(mode);
}
void IMarket::removeMarketMode(const EMarketMode mode)
{
marketModes.erase(mode);
if(mode == EMarketMode::ARTIFACT_EXP)
altarArtifacts.reset();
}
std::vector<TradeItemBuy> IMarket::availableItemsIds(const EMarketMode mode) const std::vector<TradeItemBuy> IMarket::availableItemsIds(const EMarketMode mode) const
{ {
std::vector<TradeItemBuy> ret; std::vector<TradeItemBuy> ret;

View File

@ -25,22 +25,27 @@ public:
}; };
virtual int getMarketEfficiency() const = 0; virtual int getMarketEfficiency() const = 0;
virtual bool allowsTrade(const EMarketMode mode) const = 0; virtual bool allowsTrade(const EMarketMode mode) const;
virtual int availableUnits(const EMarketMode mode, const int marketItemSerial) const; //-1 if unlimited virtual int availableUnits(const EMarketMode mode, const int marketItemSerial) const; //-1 if unlimited
virtual std::vector<TradeItemBuy> availableItemsIds(const EMarketMode mode) const; virtual std::vector<TradeItemBuy> availableItemsIds(const EMarketMode mode) const;
void addMarketMode(const EMarketMode mode);
void addMarketMode(const std::set<EMarketMode> & modes);
void removeMarketMode(const EMarketMode mode);
bool getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode) const; //val1 - how many units of id1 player has to give to receive val2 units bool getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode) const; //val1 - how many units of id1 player has to give to receive val2 units
std::vector<EMarketMode> availableModes() const; std::vector<EMarketMode> availableModes() const;
template <typename Handler> void serialize(Handler & h) template <typename Handler> void serialize(Handler & h)
{ {
if(h.loadingGamestate) h & marketModes;
{
} if(h.loadingGamestate && vstd::contains(marketModes, EMarketMode::ARTIFACT_EXP))
altarArtifacts = std::make_shared<CArtifactSetAltar>();
} }
private: private:
std::shared_ptr<CArtifactSetAltar> altarArtifacts; std::shared_ptr<CArtifactSetAltar> altarArtifacts;
std::set<EMarketMode> marketModes;
}; };
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@ -2198,18 +2198,20 @@ CGObjectInstance * CMapLoaderH3M::readTown(const int3 & position, std::shared_pt
bool hasCustomBuildings = reader->readBool(); bool hasCustomBuildings = reader->readBool();
if(hasCustomBuildings) if(hasCustomBuildings)
{ {
reader->readBitmaskBuildings(object->builtBuildings, faction); object->subID = faction.value();
reader->readBitmaskBuildings(object->forbiddenBuildings, faction); for(const auto & building : reader->readBitmaskBuildings(faction))
object->addBuilding(building);
object->forbiddenBuildings = reader->readBitmaskBuildings(faction);
} }
// Standard buildings // Standard buildings
else else
{ {
bool hasFort = reader->readBool(); bool hasFort = reader->readBool();
if(hasFort) if(hasFort)
object->builtBuildings.insert(BuildingID::FORT); object->addBuilding(BuildingID::FORT);
//means that set of standard building should be included //means that set of standard building should be included
object->builtBuildings.insert(BuildingID::DEFAULT); object->addBuilding(BuildingID::DEFAULT);
} }
if(features.levelAB) if(features.levelAB)
@ -2257,7 +2259,7 @@ CGObjectInstance * CMapLoaderH3M::readTown(const int3 & position, std::shared_pt
reader->skipZero(17); reader->skipZero(17);
// New buildings // New buildings
reader->readBitmaskBuildings(event.buildings, faction); event.buildings = reader->readBitmaskBuildings(faction);
event.creatures.resize(7); event.creatures.resize(7);
for(int i = 0; i < 7; ++i) for(int i = 0; i < 7; ++i)

View File

@ -257,9 +257,10 @@ PlayerColor MapReaderH3M::readPlayer32()
return PlayerColor(value); return PlayerColor(value);
} }
void MapReaderH3M::readBitmaskBuildings(std::set<BuildingID> & dest, std::optional<FactionID> faction) std::set<BuildingID> MapReaderH3M::readBitmaskBuildings(std::optional<FactionID> faction)
{ {
std::set<BuildingID> h3m; std::set<BuildingID> h3m;
std::set<BuildingID> dest;
readBitmask(h3m, features.buildingsBytes, features.buildingsCount, false); readBitmask(h3m, features.buildingsBytes, features.buildingsCount, false);
for (auto const & h3mEntry : h3m) for (auto const & h3mEntry : h3m)
@ -269,6 +270,7 @@ void MapReaderH3M::readBitmaskBuildings(std::set<BuildingID> & dest, std::option
if (mapped != BuildingID::NONE) // artifact merchant may be set in random town, but not present in actual town if (mapped != BuildingID::NONE) // artifact merchant may be set in random town, but not present in actual town
dest.insert(mapped); dest.insert(mapped);
} }
return dest;
} }
void MapReaderH3M::readBitmaskFactions(std::set<FactionID> & dest, bool invert) void MapReaderH3M::readBitmaskFactions(std::set<FactionID> & dest, bool invert)

View File

@ -48,7 +48,7 @@ public:
PlayerColor readPlayer(); PlayerColor readPlayer();
PlayerColor readPlayer32(); PlayerColor readPlayer32();
void readBitmaskBuildings(std::set<BuildingID> & dest, std::optional<FactionID> faction); std::set<BuildingID> readBitmaskBuildings(std::optional<FactionID> faction);
void readBitmaskFactions(std::set<FactionID> & dest, bool invert); void readBitmaskFactions(std::set<FactionID> & dest, bool invert);
void readBitmaskPlayers(std::set<PlayerColor> & dest, bool invert); void readBitmaskPlayers(std::set<PlayerColor> & dest, bool invert);
void readBitmaskResources(std::set<GameResID> & dest, bool invert); void readBitmaskResources(std::set<GameResID> & dest, bool invert);

View File

@ -1332,7 +1332,7 @@ void NewStructures::applyGs(CGameState *gs)
for(const auto & id : bid) for(const auto & id : bid)
{ {
assert(t->town->buildings.at(id) != nullptr); assert(t->town->buildings.at(id) != nullptr);
t->builtBuildings.insert(id); t->addBuilding(id);
} }
t->updateAppearance(); t->updateAppearance();
t->built = built; t->built = built;
@ -1344,7 +1344,7 @@ void RazeStructures::applyGs(CGameState *gs)
CGTownInstance *t = gs->getTown(tid); CGTownInstance *t = gs->getTown(tid);
for(const auto & id : bid) for(const auto & id : bid)
{ {
t->builtBuildings.erase(id); t->removeBuilding(id);
t->updateAppearance(); t->updateAppearance();
} }

View File

@ -79,8 +79,8 @@ void TownPlacer::placeTowns(ObjectManager & manager)
CGTownInstance * town = dynamic_cast<CGTownInstance *>(townFactory->create(map.mapInstance->cb, nullptr)); CGTownInstance * town = dynamic_cast<CGTownInstance *>(townFactory->create(map.mapInstance->cb, nullptr));
town->tempOwner = player; town->tempOwner = player;
town->builtBuildings.insert(BuildingID::FORT); town->addBuilding(BuildingID::FORT);
town->builtBuildings.insert(BuildingID::DEFAULT); town->addBuilding(BuildingID::DEFAULT);
for(auto spellID : VLC->spellh->getDefaultAllowed()) //add all regular spells to town for(auto spellID : VLC->spellh->getDefaultAllowed()) //add all regular spells to town
@ -203,8 +203,8 @@ void TownPlacer::addNewTowns(int count, bool hasFort, const PlayerColor & player
town->tempOwner = player; town->tempOwner = player;
if (hasFort) if (hasFort)
town->builtBuildings.insert(BuildingID::FORT); town->addBuilding(BuildingID::FORT);
town->builtBuildings.insert(BuildingID::DEFAULT); town->addBuilding(BuildingID::DEFAULT);
for(auto spellID : VLC->spellh->getDefaultAllowed()) //add all regular spells to town for(auto spellID : VLC->spellh->getDefaultAllowed()) //add all regular spells to town
town->possibleSpells.push_back(spellID); town->possibleSpells.push_back(spellID);