1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-15 20:03:15 +02:00

Implement markets

This commit is contained in:
nordsoft
2023-04-28 05:16:10 +04:00
committed by Nordsoft91
parent 4b1b58b617
commit 3d20538c1e
7 changed files with 148 additions and 72 deletions

View File

@@ -585,6 +585,16 @@ namespace BuildingSubID
}; };
} }
namespace EMarketMode
{
enum EMarketMode
{
RESOURCE_RESOURCE, RESOURCE_PLAYER, CREATURE_RESOURCE, RESOURCE_ARTIFACT,
ARTIFACT_RESOURCE, ARTIFACT_EXP, CREATURE_EXP, CREATURE_UNDEAD, RESOURCE_SKILL,
MARTKET_AFTER_LAST_PLACEHOLDER
};
}
namespace MappedKeys namespace MappedKeys
{ {
@@ -634,6 +644,19 @@ namespace MappedKeys
{ "lighthouse", BuildingSubID::LIGHTHOUSE }, { "lighthouse", BuildingSubID::LIGHTHOUSE },
{ "treasury", BuildingSubID::TREASURY } { "treasury", BuildingSubID::TREASURY }
}; };
static const std::map<std::string, EMarketMode::EMarketMode> MARKET_NAMES_TO_TYPES =
{
{ "resource-resource", EMarketMode::RESOURCE_RESOURCE },
{ "resource-player", EMarketMode::RESOURCE_PLAYER },
{ "creature-resource", EMarketMode::CREATURE_RESOURCE },
{ "resource-artifact", EMarketMode::RESOURCE_ARTIFACT },
{ "artifact-resource", EMarketMode::ARTIFACT_RESOURCE },
{ "artifact-experience", EMarketMode::ARTIFACT_EXP },
{ "creature-experience", EMarketMode::CREATURE_EXP },
{ "creature-undead", EMarketMode::CREATURE_UNDEAD },
{ "resource-skill", EMarketMode::RESOURCE_SKILL },
};
} }
namespace EAiTactic namespace EAiTactic
@@ -670,16 +693,6 @@ namespace ESpellCastProblem
}; };
} }
namespace EMarketMode
{
enum EMarketMode
{
RESOURCE_RESOURCE, RESOURCE_PLAYER, CREATURE_RESOURCE, RESOURCE_ARTIFACT,
ARTIFACT_RESOURCE, ARTIFACT_EXP, CREATURE_EXP, CREATURE_UNDEAD, RESOURCE_SKILL,
MARTKET_AFTER_LAST_PLACEHOLDER
};
}
namespace ECommander namespace ECommander
{ {
enum SecondarySkills {ATTACK, DEFENSE, HEALTH, DAMAGE, SPEED, SPELL_POWER, CASTS, RESISTANCE}; enum SecondarySkills {ATTACK, DEFENSE, HEALTH, DAMAGE, SPEED, SPELL_POWER, CASTS, RESISTANCE};

View File

@@ -19,6 +19,7 @@
#include "CGTownInstance.h" #include "CGTownInstance.h"
#include "../GameSettings.h" #include "../GameSettings.h"
#include "../CSkillHandler.h" #include "../CSkillHandler.h"
#include "CObjectClassesHandler.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
@@ -158,23 +159,10 @@ std::vector<int> IMarket::availableItemsIds(EMarketMode::EMarketMode mode) const
const IMarket * IMarket::castFrom(const CGObjectInstance *obj, bool verbose) const IMarket * IMarket::castFrom(const CGObjectInstance *obj, bool verbose)
{ {
switch(obj->ID) auto * imarket = dynamic_cast<const IMarket *>(obj);
{ if(verbose && !imarket)
case Obj::TOWN: logGlobal->error("Cannot cast to IMarket object type %s", obj->typeName);
return dynamic_cast<const CGTownInstance *>(obj); return imarket;
case Obj::ALTAR_OF_SACRIFICE:
case Obj::BLACK_MARKET:
case Obj::TRADING_POST:
case Obj::TRADING_POST_SNOW:
case Obj::FREELANCERS_GUILD:
return dynamic_cast<const CGMarket *>(obj);
case Obj::UNIVERSITY:
return dynamic_cast<const CGUniversity *>(obj);
default:
if(verbose)
logGlobal->error("Cannot cast to IMarket object with ID %d", obj->ID);
return nullptr;
}
} }
IMarket::IMarket() IMarket::IMarket()
@@ -191,43 +179,24 @@ std::vector<EMarketMode::EMarketMode> IMarket::availableModes() const
return ret; return ret;
} }
void CGMarket::initObj(CRandomGenerator & rand)
{
VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand);
}
void CGMarket::onHeroVisit(const CGHeroInstance * h) const void CGMarket::onHeroVisit(const CGHeroInstance * h) const
{ {
openWindow(EOpenWindowMode::MARKET_WINDOW,id.getNum(),h->id.getNum()); openWindow(EOpenWindowMode::MARKET_WINDOW, id.getNum(), h->id.getNum());
} }
int CGMarket::getMarketEfficiency() const int CGMarket::getMarketEfficiency() const
{ {
return 5; return marketEfficacy;
} }
bool CGMarket::allowsTrade(EMarketMode::EMarketMode mode) const bool CGMarket::allowsTrade(EMarketMode::EMarketMode mode) const
{ {
switch(mode) return marketModes.count(mode);
{
case EMarketMode::RESOURCE_RESOURCE:
case EMarketMode::RESOURCE_PLAYER:
switch(ID)
{
case Obj::TRADING_POST:
case Obj::TRADING_POST_SNOW:
return true;
default:
return false;
}
case EMarketMode::CREATURE_RESOURCE:
return ID == Obj::FREELANCERS_GUILD;
//case ARTIFACT_RESOURCE:
case EMarketMode::RESOURCE_ARTIFACT:
return ID == Obj::BLACK_MARKET;
case EMarketMode::ARTIFACT_EXP:
case EMarketMode::CREATURE_EXP:
return ID == Obj::ALTAR_OF_SACRIFICE; //TODO? check here for alignment of visiting hero? - would not be coherent with other checks here
case EMarketMode::RESOURCE_SKILL:
return ID == Obj::UNIVERSITY;
default:
return false;
}
} }
int CGMarket::availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial) const int CGMarket::availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial) const
@@ -237,14 +206,9 @@ int CGMarket::availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial
std::vector<int> CGMarket::availableItemsIds(EMarketMode::EMarketMode mode) const std::vector<int> CGMarket::availableItemsIds(EMarketMode::EMarketMode mode) const
{ {
switch(mode) if(allowsTrade(mode))
{
case EMarketMode::RESOURCE_RESOURCE:
case EMarketMode::RESOURCE_PLAYER:
return IMarket::availableItemsIds(mode); return IMarket::availableItemsIds(mode);
default: return std::vector<int>();
return std::vector<int>();
}
} }
CGMarket::CGMarket() CGMarket::CGMarket()
@@ -290,22 +254,26 @@ void CGBlackMarket::newTurn(CRandomGenerator & rand) const
void CGUniversity::initObj(CRandomGenerator & rand) void CGUniversity::initObj(CRandomGenerator & rand)
{ {
CGMarket::initObj(rand);
std::vector<int> toChoose; std::vector<int> toChoose;
int skillsNeeded = skillsTotal - skills.size();
for(int i = 0; i < VLC->skillh->size(); ++i) for(int i = 0; i < VLC->skillh->size(); ++i)
{ {
if(cb->isAllowed(2, i)) if(!vstd::contains(skills, i) && cb->isAllowed(2, i))
{ {
toChoose.push_back(i); toChoose.push_back(i);
} }
} }
if(toChoose.size() < 4) if(toChoose.size() < skillsNeeded)
{ {
logGlobal->warn("Warning: less then 4 available skills was found by University initializer!"); logGlobal->warn("Warning: less then %d available skills was found by University initializer!", skillsTotal);
return; return;
} }
// get 4 skills // get 4 skills, excluding predefined
for(int i = 0; i < 4; ++i)
for(int i = 0; i < skillsNeeded; ++i)
{ {
// move randomly one skill to selected and remove from list // move randomly one skill to selected and remove from list
auto it = RandomGeneratorUtil::nextItem(toChoose, rand); auto it = RandomGeneratorUtil::nextItem(toChoose, rand);
@@ -322,7 +290,7 @@ std::vector<int> CGUniversity::availableItemsIds(EMarketMode::EMarketMode mode)
return skills; return skills;
default: default:
return std::vector <int> (); return std::vector<int>();
} }
} }

View File

@@ -33,9 +33,14 @@ public:
class DLL_LINKAGE CGMarket : public CGObjectInstance, public IMarket class DLL_LINKAGE CGMarket : public CGObjectInstance, public IMarket
{ {
public: public:
std::set<EMarketMode::EMarketMode> marketModes;
int marketEfficacy = 5;
CGMarket(); CGMarket();
///IObjectIntercae ///IObjectInterface
void onHeroVisit(const CGHeroInstance * h) const override; //open trading window void onHeroVisit(const CGHeroInstance * h) const override; //open trading window
void initObj(CRandomGenerator & rand) override;//set skills for trade
///IMarket ///IMarket
int getMarketEfficiency() const override; int getMarketEfficiency() const override;
@@ -46,6 +51,8 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & static_cast<CGObjectInstance&>(*this); h & static_cast<CGObjectInstance&>(*this);
h & marketModes;
h & marketEfficacy;
} }
}; };
@@ -67,8 +74,13 @@ public:
class DLL_LINKAGE CGUniversity : public CGMarket class DLL_LINKAGE CGUniversity : public CGMarket
{ {
public: public:
int skillsTotal = 4;
std::vector<int> skills; //available skills std::vector<int> skills; //available skills
//window variables
std::string title;
std::string speech;
std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const override; std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const override;
void initObj(CRandomGenerator & rand) override;//set skills for trade void initObj(CRandomGenerator & rand) override;//set skills for trade
void onHeroVisit(const CGHeroInstance * h) const override; //open window void onHeroVisit(const CGHeroInstance * h) const override; //open window
@@ -77,6 +89,8 @@ public:
{ {
h & static_cast<CGMarket&>(*this); h & static_cast<CGMarket&>(*this);
h & skills; h & skills;
h & title;
h & speech;
} }
}; };

View File

@@ -40,6 +40,7 @@ CObjectClassesHandler::CObjectClassesHandler()
SET_HANDLER_CLASS("town", CTownInstanceConstructor); SET_HANDLER_CLASS("town", CTownInstanceConstructor);
SET_HANDLER_CLASS("bank", CBankInstanceConstructor); SET_HANDLER_CLASS("bank", CBankInstanceConstructor);
SET_HANDLER_CLASS("boat", BoatInstanceConstructor); SET_HANDLER_CLASS("boat", BoatInstanceConstructor);
SET_HANDLER_CLASS("market", MarketInstanceConstructor);
SET_HANDLER_CLASS("static", CObstacleConstructor); SET_HANDLER_CLASS("static", CObstacleConstructor);
SET_HANDLER_CLASS("", CObstacleConstructor); SET_HANDLER_CLASS("", CObstacleConstructor);
@@ -54,7 +55,6 @@ CObjectClassesHandler::CObjectClassesHandler()
SET_HANDLER("generic", CGObjectInstance); SET_HANDLER("generic", CGObjectInstance);
SET_HANDLER("cartographer", CCartographer); SET_HANDLER("cartographer", CCartographer);
SET_HANDLER("artifact", CGArtifact); SET_HANDLER("artifact", CGArtifact);
SET_HANDLER("blackMarket", CGBlackMarket);
SET_HANDLER("borderGate", CGBorderGate); SET_HANDLER("borderGate", CGBorderGate);
SET_HANDLER("borderGuard", CGBorderGuard); SET_HANDLER("borderGuard", CGBorderGuard);
SET_HANDLER("monster", CGCreature); SET_HANDLER("monster", CGCreature);
@@ -65,7 +65,6 @@ CObjectClassesHandler::CObjectClassesHandler()
SET_HANDLER("keymaster", CGKeymasterTent); SET_HANDLER("keymaster", CGKeymasterTent);
SET_HANDLER("lighthouse", CGLighthouse); SET_HANDLER("lighthouse", CGLighthouse);
SET_HANDLER("magi", CGMagi); SET_HANDLER("magi", CGMagi);
SET_HANDLER("market", CGMarket);
SET_HANDLER("mine", CGMine); SET_HANDLER("mine", CGMine);
SET_HANDLER("obelisk", CGObelisk); SET_HANDLER("obelisk", CGObelisk);
SET_HANDLER("observatory", CGObservatory); SET_HANDLER("observatory", CGObservatory);
@@ -82,7 +81,6 @@ CObjectClassesHandler::CObjectClassesHandler()
SET_HANDLER("monolith", CGMonolith); SET_HANDLER("monolith", CGMonolith);
SET_HANDLER("subterraneanGate", CGSubterraneanGate); SET_HANDLER("subterraneanGate", CGSubterraneanGate);
SET_HANDLER("whirlpool", CGWhirlpool); SET_HANDLER("whirlpool", CGWhirlpool);
SET_HANDLER("university", CGUniversity);
SET_HANDLER("witch", CGWitchHut); SET_HANDLER("witch", CGWitchHut);
SET_HANDLER("terrain", CGTerrainPatch); SET_HANDLER("terrain", CGTerrainPatch);

View File

@@ -291,6 +291,66 @@ void BoatInstanceConstructor::configureObject(CGObjectInstance * object, CRandom
} }
void MarketInstanceConstructor::initTypeData(const JsonNode & input)
{
for(auto & element : input["modes"].Vector())
{
if(MappedKeys::MARKET_NAMES_TO_TYPES.count(element.String()))
marketModes.insert(MappedKeys::MARKET_NAMES_TO_TYPES.at(element.String()));
}
marketEfficacy = input["efficacy"].isNull() ? -1 : input["efficacy"].Integer();
predefinedOffer = input["offer"];
title = input["title"].String();
speech = input["speech"].String();
}
CGObjectInstance * MarketInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
{
CGMarket * market = nullptr;
if(marketModes.size() == 1)
{
switch(*marketModes.begin())
{
case EMarketMode::ARTIFACT_RESOURCE:
case EMarketMode::RESOURCE_ARTIFACT:
market = new CGBlackMarket;
break;
case EMarketMode::RESOURCE_SKILL:
market = new CGUniversity;
break;
}
}
if(!market)
market = new CGMarket;
preInitObject(market);
if(tmpl)
market->appearance = tmpl;
market->marketModes = marketModes;
if(marketEfficacy >= 0)
market->marketEfficacy = marketEfficacy;
return market;
}
void MarketInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
{
if(auto * university = dynamic_cast<CGUniversity *>(object))
{
for(auto skill : JsonRandom::loadSecondary(predefinedOffer, rng))
university->skills.push_back(skill.first.getNum());
university->title = VLC->generaltexth->translate(title);
university->speech = VLC->generaltexth->translate(speech);
}
}
bool CBankInstanceConstructor::hasNameTextID() const bool CBankInstanceConstructor::hasNameTextID() const
{ {
return true; return true;

View File

@@ -255,4 +255,27 @@ public:
} }
}; };
class MarketInstanceConstructor : public CDefaultObjectTypeHandler<CGMarket>
{
protected:
void initTypeData(const JsonNode & config) override;
std::set<EMarketMode::EMarketMode> marketModes;
JsonNode predefinedOffer;
int marketEfficacy;
std::string title, speech;
public:
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CDefaultObjectTypeHandler<CGMarket>&>(*this);
h & marketModes;
h & marketEfficacy;
}
};
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@@ -89,12 +89,12 @@ void registerTypesMapObjectTypes(Serializer &s)
s.template registerType<AObjectTypeHandler, CDwellingInstanceConstructor>(); s.template registerType<AObjectTypeHandler, CDwellingInstanceConstructor>();
s.template registerType<AObjectTypeHandler, CBankInstanceConstructor>(); s.template registerType<AObjectTypeHandler, CBankInstanceConstructor>();
s.template registerType<AObjectTypeHandler, BoatInstanceConstructor>(); s.template registerType<AObjectTypeHandler, BoatInstanceConstructor>();
s.template registerType<AObjectTypeHandler, MarketInstanceConstructor>();
s.template registerType<AObjectTypeHandler, CObstacleConstructor>(); s.template registerType<AObjectTypeHandler, CObstacleConstructor>();
#define REGISTER_GENERIC_HANDLER(TYPENAME) s.template registerType<AObjectTypeHandler, CDefaultObjectTypeHandler<TYPENAME> >() #define REGISTER_GENERIC_HANDLER(TYPENAME) s.template registerType<AObjectTypeHandler, CDefaultObjectTypeHandler<TYPENAME> >()
REGISTER_GENERIC_HANDLER(CGObjectInstance); REGISTER_GENERIC_HANDLER(CGObjectInstance);
REGISTER_GENERIC_HANDLER(CGMarket);
REGISTER_GENERIC_HANDLER(CCartographer); REGISTER_GENERIC_HANDLER(CCartographer);
REGISTER_GENERIC_HANDLER(CGArtifact); REGISTER_GENERIC_HANDLER(CGArtifact);
REGISTER_GENERIC_HANDLER(CGBlackMarket); REGISTER_GENERIC_HANDLER(CGBlackMarket);