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
if(vstd::contains(vti->builtBuildings, BuildingID::DEFAULT)) //give standard set of buildings
{
vti->builtBuildings.erase(BuildingID::DEFAULT);
vti->builtBuildings.insert(BuildingID::VILLAGE_HALL);
vti->removeBuilding(BuildingID::DEFAULT);
vti->addBuilding(BuildingID::VILLAGE_HALL);
if(vti->tempOwner != PlayerColor::NEUTRAL)
vti->builtBuildings.insert(BuildingID::TAVERN);
vti->addBuilding(BuildingID::TAVERN);
auto definesBuildingsChances = VLC->settings()->getVector(EGameSettings::TOWNS_STARTING_DWELLING_CHANCES);
@ -815,32 +815,32 @@ void CGameState::initTowns()
{
if((getRandomGenerator().nextInt(1,100) <= definesBuildingsChances[i]))
{
vti->builtBuildings.insert(basicDwellings[i]);
vti->addBuilding(basicDwellings[i]);
}
}
}
// village hall must always exist
vti->builtBuildings.insert(BuildingID::VILLAGE_HALL);
vti->addBuilding(BuildingID::VILLAGE_HALL);
//init hordes
for (int i = 0; i < vti->town->creatures.size(); i++)
{
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
{
vti->builtBuildings.insert(BuildingID::HORDE_1);//add it
vti->addBuilding(BuildingID::HORDE_1);//add it
//if we have upgraded dwelling as well
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
{
vti->builtBuildings.insert(BuildingID::HORDE_2);
vti->addBuilding(BuildingID::HORDE_2);
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)
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
for([[maybe_unused]] const auto & building : vti->builtBuildings)

View File

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

View File

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

View File

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

View File

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

View File

@ -690,35 +690,6 @@ int CGTownInstance::getMarketEfficiency() const
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
{
if(mode == EMarketMode::RESOURCE_ARTIFACT)
@ -962,6 +933,55 @@ bool CGTownInstance::hasBuilt(const BuildingID & buildingID, FactionID townID) c
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
{
if (vstd::contains(town->buildings, buildingID))
@ -1132,23 +1152,23 @@ void CGTownInstance::serializeJsonOptions(JsonSerializeFormat & handler)
{
handler.serializeLIC("buildings", buildingsLIC);
builtBuildings.insert(BuildingID::VILLAGE_HALL);
addBuilding(BuildingID::VILLAGE_HALL);
if(buildingsLIC.none.empty() && buildingsLIC.all.empty())
{
builtBuildings.insert(BuildingID::DEFAULT);
addBuilding(BuildingID::DEFAULT);
bool hasFort = false;
handler.serializeBool("hasFort",hasFort);
if(hasFort)
builtBuildings.insert(BuildingID::FORT);
addBuilding(BuildingID::FORT);
}
else
{
for(const si32 item : buildingsLIC.none)
forbiddenBuildings.insert(BuildingID(item));
for(const si32 item : buildingsLIC.all)
builtBuildings.insert(BuildingID(item));
addBuilding(BuildingID(item));
}
}
}

View File

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

View File

@ -20,6 +20,11 @@
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
{
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> ret;

View File

@ -25,22 +25,27 @@ public:
};
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 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
std::vector<EMarketMode> availableModes() const;
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:
std::shared_ptr<CArtifactSetAltar> altarArtifacts;
std::set<EMarketMode> marketModes;
};
VCMI_LIB_NAMESPACE_END

View File

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

View File

@ -257,9 +257,10 @@ PlayerColor MapReaderH3M::readPlayer32()
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> dest;
readBitmask(h3m, features.buildingsBytes, features.buildingsCount, false);
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
dest.insert(mapped);
}
return dest;
}
void MapReaderH3M::readBitmaskFactions(std::set<FactionID> & dest, bool invert)

View File

@ -48,7 +48,7 @@ public:
PlayerColor readPlayer();
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 readBitmaskPlayers(std::set<PlayerColor> & 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)
{
assert(t->town->buildings.at(id) != nullptr);
t->builtBuildings.insert(id);
t->addBuilding(id);
}
t->updateAppearance();
t->built = built;
@ -1344,7 +1344,7 @@ void RazeStructures::applyGs(CGameState *gs)
CGTownInstance *t = gs->getTown(tid);
for(const auto & id : bid)
{
t->builtBuildings.erase(id);
t->removeBuilding(id);
t->updateAppearance();
}

View File

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