2015-12-02 21:05:10 +02:00
|
|
|
/*
|
2014-06-05 20:26:50 +03:00
|
|
|
* CGMarket.cpp, part of VCMI engine
|
2014-06-05 19:52:14 +03:00
|
|
|
*
|
|
|
|
* Authors: listed in file AUTHORS in main folder
|
|
|
|
*
|
|
|
|
* License: GNU General Public License v2.0 or later
|
|
|
|
* Full text of license available in license.txt file, in main folder
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "StdInc.h"
|
|
|
|
#include "CGMarket.h"
|
|
|
|
|
2014-06-05 20:26:50 +03:00
|
|
|
#include "../NetPacks.h"
|
|
|
|
#include "../CGeneralTextHandler.h"
|
2014-06-25 17:11:07 +03:00
|
|
|
#include "../IGameCallback.h"
|
|
|
|
#include "../CCreatureHandler.h"
|
|
|
|
#include "../CGameState.h"
|
2015-12-02 21:05:10 +02:00
|
|
|
#include "CGTownInstance.h"
|
2023-03-15 21:34:29 +02:00
|
|
|
#include "../GameSettings.h"
|
2018-03-31 07:56:40 +02:00
|
|
|
#include "../CSkillHandler.h"
|
2014-06-05 19:52:14 +03:00
|
|
|
|
2022-07-26 15:07:42 +02:00
|
|
|
VCMI_LIB_NAMESPACE_BEGIN
|
|
|
|
|
2014-06-05 19:52:14 +03:00
|
|
|
bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode::EMarketMode mode) const
|
|
|
|
{
|
|
|
|
switch(mode)
|
|
|
|
{
|
|
|
|
case EMarketMode::RESOURCE_RESOURCE:
|
|
|
|
{
|
|
|
|
double effectiveness = std::min((getMarketEfficiency() + 1.0) / 20.0, 0.5);
|
|
|
|
|
2023-02-12 22:39:17 +02:00
|
|
|
double r = VLC->objh->resVals[id1]; //value of given resource
|
|
|
|
double g = VLC->objh->resVals[id2] / effectiveness; //value of wanted resource
|
2014-06-05 19:52:14 +03:00
|
|
|
|
|
|
|
if(r>g) //if given resource is more expensive than wanted
|
|
|
|
{
|
2023-02-12 22:39:17 +02:00
|
|
|
val2 = static_cast<int>(ceil(r / g));
|
2014-06-05 19:52:14 +03:00
|
|
|
val1 = 1;
|
|
|
|
}
|
|
|
|
else //if wanted resource is more expensive
|
|
|
|
{
|
2023-02-12 22:39:17 +02:00
|
|
|
val1 = static_cast<int>((g / r) + 0.5);
|
2014-06-05 19:52:14 +03:00
|
|
|
val2 = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EMarketMode::CREATURE_RESOURCE:
|
|
|
|
{
|
|
|
|
const double effectivenessArray[] = {0.0, 0.3, 0.45, 0.50, 0.65, 0.7, 0.85, 0.9, 1.0};
|
|
|
|
double effectiveness = effectivenessArray[std::min(getMarketEfficiency(), 8)];
|
|
|
|
|
2023-02-12 22:39:17 +02:00
|
|
|
double r = VLC->creh->objects[id1]->cost[6]; //value of given creature in gold
|
|
|
|
double g = VLC->objh->resVals[id2] / effectiveness; //value of wanted resource
|
2014-06-05 19:52:14 +03:00
|
|
|
|
|
|
|
if(r>g) //if given resource is more expensive than wanted
|
|
|
|
{
|
2023-02-12 22:39:17 +02:00
|
|
|
val2 = static_cast<int>(ceil(r / g));
|
2014-06-05 19:52:14 +03:00
|
|
|
val1 = 1;
|
|
|
|
}
|
|
|
|
else //if wanted resource is more expensive
|
|
|
|
{
|
2023-02-12 22:39:17 +02:00
|
|
|
val1 = static_cast<int>((g / r) + 0.5);
|
2014-06-05 19:52:14 +03:00
|
|
|
val2 = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EMarketMode::RESOURCE_PLAYER:
|
|
|
|
val1 = 1;
|
|
|
|
val2 = 1;
|
|
|
|
break;
|
|
|
|
case EMarketMode::RESOURCE_ARTIFACT:
|
|
|
|
{
|
|
|
|
double effectiveness = std::min((getMarketEfficiency() + 3.0) / 20.0, 0.6);
|
2023-02-12 22:39:17 +02:00
|
|
|
double r = VLC->objh->resVals[id1]; //value of offered resource
|
|
|
|
double g = VLC->artifacts()->getByIndex(id2)->getPrice() / effectiveness; //value of bought artifact in gold
|
2014-06-05 19:52:14 +03:00
|
|
|
|
|
|
|
if(id1 != 6) //non-gold prices are doubled
|
|
|
|
r /= 2;
|
|
|
|
|
2023-02-12 22:39:17 +02:00
|
|
|
val1 = std::max(1, static_cast<int>((g / r) + 0.5)); //don't sell arts for less than 1 resource
|
2014-06-05 19:52:14 +03:00
|
|
|
val2 = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EMarketMode::ARTIFACT_RESOURCE:
|
|
|
|
{
|
|
|
|
double effectiveness = std::min((getMarketEfficiency() + 3.0) / 20.0, 0.6);
|
2023-02-12 22:39:17 +02:00
|
|
|
double r = VLC->artifacts()->getByIndex(id1)->getPrice() * effectiveness;
|
|
|
|
double g = VLC->objh->resVals[id2];
|
2014-06-05 19:52:14 +03:00
|
|
|
|
|
|
|
// if(id2 != 6) //non-gold prices are doubled
|
|
|
|
// r /= 2;
|
|
|
|
|
|
|
|
val1 = 1;
|
2023-02-12 22:39:17 +02:00
|
|
|
val2 = std::max(1, static_cast<int>((r / g) + 0.5)); //at least one resource is given in return
|
2014-06-05 19:52:14 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EMarketMode::CREATURE_EXP:
|
|
|
|
{
|
|
|
|
val1 = 1;
|
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
|
|
|
val2 = (VLC->creh->objects[id1]->AIValue / 40) * 5;
|
2014-06-05 19:52:14 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EMarketMode::ARTIFACT_EXP:
|
|
|
|
{
|
|
|
|
val1 = 1;
|
|
|
|
|
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
|
|
|
int givenClass = VLC->arth->objects[id1]->getArtClassSerial();
|
2014-06-05 19:52:14 +03:00
|
|
|
if(givenClass < 0 || givenClass > 3)
|
|
|
|
{
|
|
|
|
val2 = 0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-02-12 22:39:17 +02:00
|
|
|
static constexpr int expPerClass[] = {1000, 1500, 3000, 6000};
|
2014-06-05 19:52:14 +03:00
|
|
|
val2 = expPerClass[givenClass];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IMarket::allowsTrade(EMarketMode::EMarketMode mode) const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int IMarket::availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial) const
|
|
|
|
{
|
|
|
|
switch(mode)
|
|
|
|
{
|
|
|
|
case EMarketMode::RESOURCE_RESOURCE:
|
|
|
|
case EMarketMode::ARTIFACT_RESOURCE:
|
|
|
|
case EMarketMode::CREATURE_RESOURCE:
|
|
|
|
return -1;
|
|
|
|
default:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<int> IMarket::availableItemsIds(EMarketMode::EMarketMode mode) const
|
|
|
|
{
|
|
|
|
std::vector<int> ret;
|
|
|
|
switch(mode)
|
|
|
|
{
|
|
|
|
case EMarketMode::RESOURCE_RESOURCE:
|
|
|
|
case EMarketMode::ARTIFACT_RESOURCE:
|
|
|
|
case EMarketMode::CREATURE_RESOURCE:
|
|
|
|
for (int i = 0; i < 7; i++)
|
|
|
|
ret.push_back(i);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-07-15 13:08:20 +02:00
|
|
|
const IMarket * IMarket::castFrom(const CGObjectInstance *obj, bool verbose)
|
2014-06-05 19:52:14 +03:00
|
|
|
{
|
|
|
|
switch(obj->ID)
|
|
|
|
{
|
|
|
|
case Obj::TOWN:
|
2023-02-12 22:39:17 +02:00
|
|
|
return dynamic_cast<const CGTownInstance *>(obj);
|
2014-06-05 19:52:14 +03:00
|
|
|
case Obj::ALTAR_OF_SACRIFICE:
|
|
|
|
case Obj::BLACK_MARKET:
|
|
|
|
case Obj::TRADING_POST:
|
|
|
|
case Obj::TRADING_POST_SNOW:
|
|
|
|
case Obj::FREELANCERS_GUILD:
|
2023-02-12 22:39:17 +02:00
|
|
|
return dynamic_cast<const CGMarket *>(obj);
|
2014-06-05 19:52:14 +03:00
|
|
|
case Obj::UNIVERSITY:
|
2023-02-12 22:39:17 +02:00
|
|
|
return dynamic_cast<const CGUniversity *>(obj);
|
2014-06-05 19:52:14 +03:00
|
|
|
default:
|
|
|
|
if(verbose)
|
2017-08-11 19:03:05 +02:00
|
|
|
logGlobal->error("Cannot cast to IMarket object with ID %d", obj->ID);
|
2014-06-05 19:52:14 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IMarket::IMarket(const CGObjectInstance *O)
|
|
|
|
:o(O)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<EMarketMode::EMarketMode> IMarket::availableModes() const
|
|
|
|
{
|
|
|
|
std::vector<EMarketMode::EMarketMode> ret;
|
|
|
|
for (int i = 0; i < EMarketMode::MARTKET_AFTER_LAST_PLACEHOLDER; i++)
|
2023-02-12 22:39:17 +02:00
|
|
|
if(allowsTrade(static_cast<EMarketMode::EMarketMode>(i)))
|
|
|
|
ret.push_back(static_cast<EMarketMode::EMarketMode>(i));
|
2014-06-05 19:52:14 +03:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGMarket::onHeroVisit(const CGHeroInstance * h) const
|
|
|
|
{
|
2023-03-08 00:32:21 +02:00
|
|
|
openWindow(EOpenWindowMode::MARKET_WINDOW,id.getNum(),h->id.getNum());
|
2014-06-05 19:52:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int CGMarket::getMarketEfficiency() const
|
|
|
|
{
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CGMarket::allowsTrade(EMarketMode::EMarketMode mode) const
|
|
|
|
{
|
|
|
|
switch(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
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<int> CGMarket::availableItemsIds(EMarketMode::EMarketMode mode) const
|
|
|
|
{
|
|
|
|
switch(mode)
|
|
|
|
{
|
|
|
|
case EMarketMode::RESOURCE_RESOURCE:
|
|
|
|
case EMarketMode::RESOURCE_PLAYER:
|
|
|
|
return IMarket::availableItemsIds(mode);
|
|
|
|
default:
|
|
|
|
return std::vector<int>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CGMarket::CGMarket()
|
|
|
|
:IMarket(this)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<int> CGBlackMarket::availableItemsIds(EMarketMode::EMarketMode mode) const
|
|
|
|
{
|
|
|
|
switch(mode)
|
|
|
|
{
|
|
|
|
case EMarketMode::ARTIFACT_RESOURCE:
|
|
|
|
return IMarket::availableItemsIds(mode);
|
|
|
|
case EMarketMode::RESOURCE_ARTIFACT:
|
|
|
|
{
|
|
|
|
std::vector<int> ret;
|
|
|
|
for(const CArtifact *a : artifacts)
|
|
|
|
if(a)
|
2023-01-02 15:58:56 +02:00
|
|
|
ret.push_back(a->getId());
|
2014-06-05 19:52:14 +03:00
|
|
|
else
|
|
|
|
ret.push_back(-1);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return std::vector<int>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-09 19:30:36 +02:00
|
|
|
void CGBlackMarket::newTurn(CRandomGenerator & rand) const
|
2014-06-05 19:52:14 +03:00
|
|
|
{
|
2023-03-15 23:47:26 +02:00
|
|
|
int resetPeriod = VLC->settings()->getInteger(EGameSettings::MARKETS_BLACK_MARKET_RESTOCK_PERIOD);
|
|
|
|
|
|
|
|
if(resetPeriod == 0) //check if feature changing OH3 behavior is enabled
|
2017-07-14 23:46:18 +02:00
|
|
|
return;
|
|
|
|
|
2023-03-15 23:47:26 +02:00
|
|
|
if (((cb->getDate(Date::DAY)-1) % resetPeriod) != 0)
|
2014-06-05 19:52:14 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
SetAvailableArtifacts saa;
|
|
|
|
saa.id = id.getNum();
|
2016-09-09 19:30:36 +02:00
|
|
|
cb->pickAllowedArtsSet(saa.arts, rand);
|
2014-06-05 19:52:14 +03:00
|
|
|
cb->sendAndApply(&saa);
|
|
|
|
}
|
|
|
|
|
2016-09-09 19:30:36 +02:00
|
|
|
void CGUniversity::initObj(CRandomGenerator & rand)
|
2014-06-05 19:52:14 +03:00
|
|
|
{
|
|
|
|
std::vector<int> toChoose;
|
2018-03-31 07:56:40 +02:00
|
|
|
for(int i = 0; i < VLC->skillh->size(); ++i)
|
2014-06-05 19:52:14 +03:00
|
|
|
{
|
|
|
|
if(cb->isAllowed(2, i))
|
|
|
|
{
|
|
|
|
toChoose.push_back(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(toChoose.size() < 4)
|
|
|
|
{
|
2017-08-10 18:39:27 +02:00
|
|
|
logGlobal->warn("Warning: less then 4 available skills was found by University initializer!");
|
2014-06-05 19:52:14 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get 4 skills
|
|
|
|
for(int i = 0; i < 4; ++i)
|
|
|
|
{
|
|
|
|
// move randomly one skill to selected and remove from list
|
2016-09-09 19:30:36 +02:00
|
|
|
auto it = RandomGeneratorUtil::nextItem(toChoose, rand);
|
2014-06-05 19:52:14 +03:00
|
|
|
skills.push_back(*it);
|
|
|
|
toChoose.erase(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<int> CGUniversity::availableItemsIds(EMarketMode::EMarketMode mode) const
|
|
|
|
{
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case EMarketMode::RESOURCE_SKILL:
|
|
|
|
return skills;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return std::vector <int> ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGUniversity::onHeroVisit(const CGHeroInstance * h) const
|
|
|
|
{
|
2023-03-08 00:32:21 +02:00
|
|
|
openWindow(EOpenWindowMode::UNIVERSITY_WINDOW,id.getNum(),h->id.getNum());
|
2014-06-05 19:52:14 +03:00
|
|
|
}
|
2022-07-26 15:07:42 +02:00
|
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_END
|