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

Trading Post handling.

This commit is contained in:
Michał W. Urbańczyk 2010-05-18 07:01:54 +00:00
parent 71b73bad53
commit 1002bd2b4f
22 changed files with 372 additions and 102 deletions

View File

@ -732,25 +732,6 @@ std::vector < const CGObjectInstance * > CCallback::getVisitableObjs( int3 pos )
return ret;
}
void CCallback::getMarketOffer( int t1, int t2, int &give, int &rec, int mode/*=0*/ ) const
{
if(mode) return; //TODO - support
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
//if(gs->resVals[t1] >= gs->resVals[t2])
float r = gs->resVals[t1], //price of given resource
g = gs->resVals[t2] / gs->getMarketEfficiency(player,mode); //price of wanted resource
if(r>g) //if given resource is more expensive than wanted
{
rec = ceil(r / g);
give = 1;
}
else //if wanted resource is more expensive
{
give = ceil(g / r);
rec = 1;
}
}
std::vector < const CGObjectInstance * > CCallback::getFlaggableObjects(int3 pos) const
{
if(!isVisible(pos))
@ -772,11 +753,15 @@ int3 CCallback::getMapSize() const
return CGI->mh->sizes;
}
void CCallback::trade( int mode, int id1, int id2, int val1 )
void CCallback::trade(const CGObjectInstance *market, int mode, int id1, int id2, int val1, const CGHeroInstance *hero/* = NULL*/)
{
int p1, p2;
getMarketOffer(id1,id2,p1,p2,mode);
TradeOnMarketplace pack(player,mode,id1,id2,val1);
TradeOnMarketplace pack;
pack.market = market;
pack.hero = hero;
pack.mode = mode;
pack.r1 = id1;
pack.r2 = id2;
pack.val = val1;
sendRequest(&pack);
}

View File

@ -84,7 +84,7 @@ public:
virtual bool upgradeCreature(const CArmedInstance *obj, int stackPos, int newID=-1)=0; //if newID==-1 then best possible upgrade will be made
virtual void swapGarrisonHero(const CGTownInstance *town)=0;
virtual void trade(int mode, int id1, int id2, int val1)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce
virtual void trade(const CGObjectInstance *market, int mode, int id1, int id2, int val1, const CGHeroInstance *hero = NULL)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce
virtual void selectionMade(int selection, int asker) =0;
virtual int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)=0;//swaps creatures between two posiibly different garrisons // TODO: AI-unsafe code - fix it!
@ -146,7 +146,6 @@ public:
virtual std::vector<const CGHeroInstance *> getAvailableHeroes(const CGTownInstance * town) const =0; //heroes that can be recruited
virtual int canBuildStructure(const CGTownInstance *t, int ID) =0;//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
virtual std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID) =0;
virtual void getMarketOffer(int t1, int t2, int &give, int &rec, int mode=0)const =0; //t1 - type of given resource, t2 - type of received resource; give is the amount of resource t1 that can be traded for amount rec of resource t2 (one of them is 1)
virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const = 0;
virtual UpgradeInfo getUpgradeInfo(const CArmedInstance *obj, int stackPos)const =0;
@ -226,7 +225,7 @@ public:
void endTurn();
void swapGarrisonHero(const CGTownInstance *town);
void buyArtifact(const CGHeroInstance *hero, int aid);
void trade(int mode, int id1, int id2, int val1);
void trade(const CGObjectInstance *market, int mode, int id1, int id2, int val1, const CGHeroInstance *hero = NULL);
void setFormation(const CGHeroInstance * hero, bool tight);
void setSelection(const CArmedInstance * obj);
void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero);
@ -265,7 +264,6 @@ public:
std::vector < const CGObjectInstance * > getBlockingObjs(int3 pos) const;
std::vector < const CGObjectInstance * > getVisitableObjs(int3 pos) const;
void getMarketOffer(int t1, int t2, int &give, int &rec, int mode=0) const; //t1 - type of given resource, t2 - type of received resource; give is the amount of resource t1 that can be traded for amount rec of resource t2 (one of them is 1)
std::vector < const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map
std::vector<const CGHeroInstance *> getAvailableHeroes(const CGTownInstance * town) const; //heroes that can be recruited

View File

@ -31,6 +31,7 @@ class CGDwelling;
class CCreatureSet;
class CArmedInstance;
class IShipyard;
class IMarket;
struct BattleResult;
struct BattleAttack;
struct BattleStackAttacked;
@ -81,6 +82,7 @@ public:
virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
virtual void showPuzzleMap(){};
virtual void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor){};
virtual void advmapSpellCast(const CGHeroInstance * caster, int spellID){}; //called when a hero casts a spell
virtual void tileHidden(const std::set<int3> &pos){};
virtual void tileRevealed(const std::set<int3> &pos){};

View File

@ -2,6 +2,7 @@
GENERAL:
* It's possible to start campaign
* Support for build grail victory condition
* New artifacts supported: Angel's Wings and Boots of levitation
ADVENTURE MAP:
* Creatures now guard surrounding tiles
@ -9,6 +10,8 @@ ADVENTURE MAP:
- Summon Boat
- Scuttle Boat
- Dimension Door
- Fly
- Water walk
BATTLES:
* A number of new creature abilities supported
@ -33,6 +36,7 @@ TOWNS:
OBJECTS:
New object supported:
- Trading Post
- War Machine Factory
0.75 -> 0.8 (Mar 01 2010)

View File

@ -28,6 +28,7 @@
#include "CPreGame.h"
#include "../lib/VCMI_Lib.h"
#include "../hch/CSpellHandler.h"
#include <boost/foreach.hpp>
#ifdef _MSC_VER
#pragma warning (disable : 4355)
@ -1521,15 +1522,19 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
//act on key down if marketplace windows is not already opened
if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) return;
//check if we have aby marketplace
std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo();
size_t i = 0;
for(; i<towns.size(); i++)
if(vstd::contains(towns[i]->builtBuildings, 14))
//check if we have any marketplace
const CGTownInstance *townWithMarket = NULL;
BOOST_FOREACH(const CGTownInstance *t, LOCPLINT->cb->getTownsInfo())
{
if(vstd::contains(t->builtBuildings, 14))
{
townWithMarket = t;
break;
}
}
if(i != towns.size()) //if any town has marketplace, open window
GH.pushInt(new CMarketplaceWindow);
if(townWithMarket) //if any town has marketplace, open window
GH.pushInt(new CMarketplaceWindow(townWithMarket));
else //if not - complain
LOCPLINT->showInfoDialog("No available marketplace!", std::vector<SComponent*>(), soundBase::sound_todo);
return;

View File

@ -635,7 +635,7 @@ void CCastleInterface::buildingClicked(int building)
break;
case 14: //marketplace
{
CMarketplaceWindow *cmw = new CMarketplaceWindow();
CMarketplaceWindow *cmw = new CMarketplaceWindow(town);
GH.pushInt(cmw);
break;
}

View File

@ -1974,3 +1974,9 @@ void CPlayerInterface::stopMovement()
if(stillMoveHero.get() == DURING_MOVE)//if we are in the middle of hero movement
stillMoveHero.setn(STOP_MOVE); //after showing dialog movement will be stopped
}
void CPlayerInterface::showMarketWindow(const IMarket *market, const CGHeroInstance *visitor)
{
CMarketplaceWindow *cmw = new CMarketplaceWindow(market, market->availableModes().front());
GH.pushInt(cmw);
}

View File

@ -161,6 +161,7 @@ public:
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd);
void showArtifactAssemblyDialog(ui32 artifactID, ui32 assembleTo, bool assemble, CFunctionList<void()> onYes, CFunctionList<void()> onNo);
void showPuzzleMap();
void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor);
void advmapSpellCast(const CGHeroInstance * caster, int spellID); //called when a hero casts a spell
void tileHidden(const std::set<int3> &pos); //called when given tiles become hidden under fog of war
void tileRevealed(const std::set<int3> &pos); //called when fog of war disappears from given tiles

View File

@ -2655,7 +2655,8 @@ static void initItems( std::vector<CMarketplaceWindow::CTradeableItem*> &i, std:
i[j]->pos = p[j] + i[j]->pos;
}
}
CMarketplaceWindow::CMarketplaceWindow(int Mode)
CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, EMarketMode Mode)
:market(Market)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
type = BLOCK_ADV_HOTKEYS;
@ -2808,7 +2809,7 @@ void CMarketplaceWindow::setMax()
void CMarketplaceWindow::makeDeal()
{
LOCPLINT->cb->trade(mode,hLeft->id,hRight->id,slider->value*r1);
LOCPLINT->cb->trade(market->o, mode, hLeft->id, hRight->id, slider->value*r1);
slider->moveTo(0);
hLeft = NULL;
selectionChanged(true);
@ -2824,7 +2825,7 @@ void CMarketplaceWindow::selectionChanged(bool side)
{
if(mode == RESOURCE_RESOURCE)
{
LOCPLINT->cb->getMarketOffer(hLeft->id,hRight->id,r1,r2,0);
market->getOffer(hLeft->id, hRight->id, r1, r2, mode);
slider->setAmount(LOCPLINT->cb->getResourceAmount(hLeft->id) / r1);
}
else if(mode == RESOURCE_PLAYER)
@ -2850,8 +2851,9 @@ void CMarketplaceWindow::selectionChanged(bool side)
int h1, h2;
for(int i=0;i<right.size();i++)
{
market->getOffer(hLeft->id, i, h1, h2, RESOURCE_RESOURCE);
std::ostringstream oss;
LOCPLINT->cb->getMarketOffer(hLeft->id,i,h1,h2,0);
oss << h2;
if(h1!=1)
oss << "/" << h1;
@ -2880,10 +2882,11 @@ void CMarketplaceWindow::getPositionsFor(std::vector<Rect> &poss, bool Right, ET
}
}
void CMarketplaceWindow::setMode(int Mode)
void CMarketplaceWindow::setMode(EMarketMode Mode)
{
CMarketplaceWindow *nwindow = new CMarketplaceWindow(market, Mode);
GH.popIntTotally(this);
GH.pushInt(new CMarketplaceWindow(Mode));
GH.pushInt(nwindow);
}
CSystemOptionsWindow::CSystemOptionsWindow(const SDL_Rect &pos, CPlayerInterface * owner)

View File

@ -65,6 +65,7 @@ class CResDataBar;
struct SPuzzleInfo;
class CGGarrison;
class CStackInstance;
class IMarket;
extern SDL_Color tytulowy, tlo, zwykly ;
@ -536,14 +537,15 @@ public:
CTradeableItem(int Type, int ID, bool Left);
};
const IMarket *market;
CPicture *bg; //background
std::vector<CTradeableItem*> left, right;
std::vector<std::string> rSubs; //offer caption
CTradeableItem *hLeft, *hRight; //highlighted items (NULL if no highlight)
EType ltype, rtype;
int mode,//0 - res<->res; 1 - res<->plauer; 2 - buy artifact; 3 - sell artifact
r1, r2; //suggested amounts of traded resources
EMarketMode mode;//0 - res<->res; 1 - res<->plauer; 2 - buy artifact; 3 - sell artifact
int r1, r2; //suggested amounts of traded resources
AdventureMapButton *ok, *max, *deal;
CSlider *slider; //for choosing amount to be exchanged
@ -552,9 +554,9 @@ public:
void sliderMoved(int to);
void makeDeal();
void selectionChanged(bool side); //true == left
CMarketplaceWindow(int Mode = RESOURCE_RESOURCE); //c-tor
CMarketplaceWindow(const IMarket *Market, EMarketMode Mode = RESOURCE_RESOURCE); //c-tor
~CMarketplaceWindow(); //d-tor
void setMode(int Mode); //mode setter
void setMode(EMarketMode Mode); //mode setter
void getPositionsFor(std::vector<Rect> &poss, bool Right, EType type) const;
};

View File

@ -720,6 +720,15 @@ void OpenWindow::applyCl(CClient *cl)
GH.pushInt( new CThievesGuildWindow(obj) );
}
break;
case MARKET_WINDOW:
{
//displays Thieves' Guild window (when hero enters Den of Thieves)
const CGObjectInstance *obj = cl->getObj(id1);
const CGHeroInstance *hero = cl->getHero(id2);
const IMarket *market = IMarket::castFrom(obj);
INTERFACE_CALL_IF_PRESENT(cl->getTile(obj->visitablePos())->visitableObjects.back()->tempOwner, showMarketWindow, market, hero);
}
break;
case PUZZLE_MAP:
{
INTERFACE_CALL_IF_PRESENT(id1, showPuzzleMap);

View File

@ -107,7 +107,8 @@ const int SPELL_LEVELS = 5;
enum EMarketMode
{
RESOURCE_RESOURCE, RESOURCE_PLAYER, CREATURE_RESOURCE, ARTIFACT_RESOURCE
RESOURCE_RESOURCE, RESOURCE_PLAYER, CREATURE_RESOURCE, ARTIFACT_RESOURCE, RESOURCE_ARTIFACT, ARTIFACT_EXP, CREATURE_EXP,
MARTKET_AFTER_LAST_PLACEHOLDER
};
//uncomment to make it work

View File

@ -144,7 +144,23 @@ void CObjectHandler::loadObjects()
cregens[dw]=cr;
}
tlog5 << "\t\tDone loading objects!\n";
ifs.close();
ifs.clear();
int k = -1;
ifs.open(DATA_DIR "/config/resources.txt");
ifs >> k;
int pom;
for(int i=0;i<k;i++)
{
ifs >> pom;
resVals.push_back(pom);
}
tlog5 << "\t\tDone loading resource prices!\n";
}
std::ifstream istr;
istr.open(DATA_DIR "/config/bankconfig.txt", std::ios_base::binary);
@ -1567,7 +1583,7 @@ bool CGTownInstance::hasCapitol() const
return (builtBuildings.find(13))!=builtBuildings.end();
}
CGTownInstance::CGTownInstance()
:IShipyard(this)
:IShipyard(this), IMarket(this)
{
builded=-1;
destroyed=-1;
@ -1802,6 +1818,39 @@ void CGTownInstance::getBonuses(BonusList &out, const CSelector &selector, const
}
}
int CGTownInstance::getMarketEfficiency() const
{
if(!vstd::contains(builtBuildings, 14))
return 0;
const PlayerState *p = cb->getPlayerState(tempOwner);
assert(p);
int marketCount = 0;
BOOST_FOREACH(const CGTownInstance *t, p->towns)
if(vstd::contains(t->builtBuildings, 14))
marketCount++;
return marketCount;
}
bool CGTownInstance::allowsTrade(EMarketMode mode) const
{
switch(mode)
{
case RESOURCE_RESOURCE:
case RESOURCE_PLAYER:
return vstd::contains(builtBuildings, 14); // marketplace
case ARTIFACT_RESOURCE:
return (subID == 2 || subID == 5 || subID == 8) && vstd::contains(builtBuildings, 17);//artifact merchants
case CREATURE_RESOURCE:
return subID == 6 && vstd::contains(builtBuildings, 21); //Freelancer's guild
default:
assert(0);
return false;
}
}
void CGVisitableOPH::onHeroVisit( const CGHeroInstance * h ) const
{
if(visitors.find(h->id)==visitors.end())
@ -5860,3 +5909,152 @@ void CArmedInstance::getBonuses(BonusList &out, const CSelector &selector, const
}
}
}
bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode) const
{
switch(mode)
{
case RESOURCE_RESOURCE:
{
float effectiveness = std::min(((float)getMarketEfficiency()+1.0f) / 20.0f, 0.5f);
float r = VLC->objh->resVals[id1], //value of given resource
g = VLC->objh->resVals[id2] / effectiveness; //value of wanted resource
if(r>g) //if given resource is more expensive than wanted
{
val2 = ceil(r / g);
val1 = 1;
}
else //if wanted resource is more expensive
{
val1 = (g / r) + 0.5f;
val2 = 1;
}
}
break;
default:
assert(0);
return false;
}
return true;
}
bool IMarket::allowsTrade(EMarketMode mode) const
{
return false;
}
int IMarket::availableUnits(EMarketMode mode, int marketItemSerial) const
{
if(mode == RESOURCE_RESOURCE || ARTIFACT_RESOURCE || CREATURE_RESOURCE)
return -1;
else
return 1;
}
std::vector<int> IMarket::availableItemsIds(EMarketMode mode) const
{
std::vector<int> ret;
if(mode == RESOURCE_RESOURCE || ARTIFACT_RESOURCE || CREATURE_RESOURCE)
for (int i = 0; i < 7; i++)
ret.push_back(i);
return ret;
}
const IMarket * IMarket::castFrom(const CGObjectInstance *obj)
{
switch(obj->ID)
{
case TOWNI_TYPE:
return static_cast<const CGTownInstance*>(obj);
case 99: //Trading Post
case 221: //Trading Post (snow)
return static_cast<const CGMarket*>(obj);
default:
tlog1 << "Cannot cast to IMarket object with ID " << obj->ID << std::endl;
return NULL;
}
}
IMarket::IMarket(const CGObjectInstance *O)
:o(O)
{
}
std::vector<EMarketMode> IMarket::availableModes() const
{
std::vector<EMarketMode> ret;
for (int i = 0; i < MARTKET_AFTER_LAST_PLACEHOLDER; i++)
if(allowsTrade((EMarketMode)i))
ret.push_back((EMarketMode)i);
return ret;
}
void CGMarket::onHeroVisit(const CGHeroInstance * h) const
{
OpenWindow ow;
ow.id1 = id;
ow.id2 = h->id;
ow.window = OpenWindow::MARKET_WINDOW;
cb->sendAndApply(&ow);
}
void CGMarket::initObj()
{
}
void CGMarket::newTurn() const
{
}
int CGMarket::getMarketEfficiency() const
{
return 5;
}
bool CGMarket::allowsTrade(EMarketMode mode) const
{
switch(mode)
{
case RESOURCE_RESOURCE:
case RESOURCE_PLAYER:
switch(ID)
{
case 99: //Trading Post
case 221: //Trading Post (snow)
return true;
default:
return false;
}
}
}
int CGMarket::availableUnits(EMarketMode mode, int marketItemSerial) const
{
return -1;
}
std::vector<int> CGMarket::availableItemsIds(EMarketMode mode) const
{
switch(mode)
{
case RESOURCE_RESOURCE:
case RESOURCE_PLAYER:
return IMarket::availableItemsIds(mode);
default:
return std::vector<int>();
}
}
CGMarket::CGMarket()
:IMarket(this)
{
}

View File

@ -141,18 +141,22 @@ public:
static IShipyard *castFrom(CGObjectInstance *obj);
};
/*class DLL_EXPORT IMarket
{
public:
class DLL_EXPORT IMarket
{
virtual int getMarketEfficiency() const =0;
public:
const CGObjectInstance *o;
IMarket(const CGObjectInstance *O);
virtual bool allowsMode(EMarketMode mode);
virtual float getEfficiency(EMarketMode mode);
virtual bool allowsTrade(EMarketMode mode) const;
virtual int availableUnits(EMarketMode mode, int marketItemSerial) const; //-1 if unlimited
virtual std::vector<int> availableItemsIds(EMarketMode mode) const;
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;
static const IMarket *castFrom(const CGObjectInstance *obj);
static IMarket castFrom(CGObjectInstance *obj);
};*/
};
class DLL_EXPORT CGObjectInstance : public IObjectInterface
{
@ -446,6 +450,7 @@ public:
h & visitors;
}
};
class DLL_EXPORT CTownBonus : public CGTownBuilding
{
///used for one-time bonusing structures
@ -463,7 +468,8 @@ public:
h & visitors;
}
};
class DLL_EXPORT CGTownInstance : public CGDwelling, public IShipyard
class DLL_EXPORT CGTownInstance : public CGDwelling, public IShipyard, public IMarket
{
public:
CTown * town;
@ -505,6 +511,8 @@ public:
int getSightRadious() const; //returns sight distance
int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed
int getMarketEfficiency() const; //=market count
bool allowsTrade(EMarketMode mode) const;
void setPropertyDer(ui8 what, ui32 val);
void newTurn() const;
@ -1121,7 +1129,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CPlayersVisited&>(*this);;
h & static_cast<CPlayersVisited&>(*this);
}
};
@ -1134,11 +1142,30 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);;
h & static_cast<CGObjectInstance&>(*this);
}
void giveBonusTo( ui8 player ) const;
};
class DLL_EXPORT CGMarket : public CGObjectInstance, public IMarket
{
public:
CGMarket();
void onHeroVisit(const CGHeroInstance * h) const; //open trading window
void initObj();
void newTurn() const; //reset artifacts for black market every month
int getMarketEfficiency() const;
bool allowsTrade(EMarketMode mode) const;
int availableUnits(EMarketMode mode, int marketItemSerial) const; //-1 if unlimited
std::vector<int> availableItemsIds(EMarketMode mode) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
}
};
struct BankConfig
{
BankConfig() {level = chance = upgradeChance = combatValue = value = rewardDifficulty = easiest = 0; };
@ -1166,12 +1193,13 @@ public:
std::vector<si32> cregens; //type 17. dwelling subid -> creature ID
std::map <ui32, std::vector <BankConfig*> > banksInfo; //[index][preset]
std::map <ui32, std::string> creBanksNames; //[crebank index] -> name of this creature bank
std::vector<ui32> resVals; //default values of resources in gold
void loadObjects();
template <typename Handler> void serialize(Handler &h, const int version)
{
h & cregens & banksInfo & creBanksNames;
h & cregens & banksInfo & creBanksNames & resVals;
}
};

View File

@ -1347,14 +1347,6 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
(*i).second.resources[x] = startres[x];
}
tis.open(DATA_DIR "/config/resources.txt");
tis >> k;
int pom;
for(int i=0;i<k;i++)
{
tis >> pom;
resVals.push_back(pom);
}
/*************************HEROES************************************************/
std::set<int> hids;
@ -1735,18 +1727,6 @@ UpgradeInfo CGameState::getUpgradeInfo(const CArmedInstance *obj, int stackPos)
return ret;
}
float CGameState::getMarketEfficiency( int player, int mode/*=0*/ )
{
boost::shared_lock<boost::shared_mutex> lock(*mx);
if(mode) return -1; //todo - support other modes
int mcount = 0;
for(unsigned int i=0;i<getPlayer(player)->towns.size();i++)
if(vstd::contains(getPlayer(player)->towns[i]->builtBuildings,14))
mcount++;
float ret = std::min(((float)mcount+1.0f)/20.0f,0.5f);
return ret;
}
void CGameState::loadTownDInfos()
{
for(int i=0;i<F_NUMBER;i++)

View File

@ -378,7 +378,6 @@ public:
Mapa * map;
std::map<ui8, PlayerState> players; //ID <-> player state
std::map<int, CGDefInfo*> villages, forts, capitols; //def-info for town graphics
std::vector<ui32> resVals; //default values of resources in gold
CBonusSystemNode globalEffects;
struct DLL_EXPORT HeroesPool
@ -417,7 +416,7 @@ public:
si8 battleMaxSpellLevel(); //calculates maximum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, SPELL_LEVELS is returned
bool battleCanShoot(int ID, int dest); //determines if stack with given ID shoot at the selected destination
UpgradeInfo getUpgradeInfo(const CArmedInstance *obj, int stackPos);
float getMarketEfficiency(int player, int mode=0);
//float getMarketEfficiency(int player, int mode=0);
std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID);
int canBuildStructure(const CGTownInstance *t, int ID);// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if src tile is visitable from dst tile
@ -441,7 +440,7 @@ public:
int getDate(int mode=0) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
template <typename Handler> void serialize(Handler &h, const int version)
{
h & scenarioOps & seed & currentPlayer & day & map & players & resVals & hpool & globalEffects & campaign;
h & scenarioOps & seed & currentPlayer & day & map & players & hpool & globalEffects & campaign;
if(!h.saving)
{
loadTownDInfos();

View File

@ -615,7 +615,7 @@ struct OpenWindow : public CPackForClient //517
OpenWindow(){type = 517;};
void applyCl(CClient *cl);
enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL, SHIPYARD_WINDOW, THIEVES_GUILD, PUZZLE_MAP};
enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL, SHIPYARD_WINDOW, THIEVES_GUILD, PUZZLE_MAP, MARKET_WINDOW};
ui8 window;
ui32 id1, id2;
@ -673,7 +673,7 @@ struct NewTurn : public CPackForClient //101
struct Component : public CPack //2002 helper for object scrips informations
{
enum {PRIM_SKILL, SEC_SKILL, RESOURCE, CREATURE, ARTIFACT, EXPERIENCE, SPELL, MORALE=8, LUCK, BUILDING, HERO, FLAG};
enum EComponentType {PRIM_SKILL, SEC_SKILL, RESOURCE, CREATURE, ARTIFACT, EXPERIENCE, SPELL, MORALE=8, LUCK, BUILDING, HERO, FLAG};
ui16 id, subtype; //id uses ^^^ enums, when id==EXPPERIENCE subtype==0 means exp points and subtype==1 levels)
si32 val; // + give; - take
si16 when; // 0 - now; +x - within x days; -x - per x days
@ -1361,18 +1361,17 @@ struct BuyArtifact : public CPackForServer
struct TradeOnMarketplace : public CPackForServer
{
TradeOnMarketplace(){};
TradeOnMarketplace(ui8 Player, ui8 Mode, /*si32 ID, */ui32 R1, ui32 R2, ui32 Val)
:player(Player),mode(Mode),/*id(ID),*/r1(R1),r2(R2),val(Val){};
ui8 player;
const CGObjectInstance *market;
const CGHeroInstance *hero; //needed when trading artifacts / creatures
ui8 mode;//0 - res<->res;
//si32 id; //object id
ui32 r1, r2; //mode 0: r1 - sold resource, r2 - bought res
ui32 val; //units of sold resource
bool applyGh(CGameHandler *gh);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & player & mode & /*id & */r1 & r2 & val;
h & market & hero & mode & r1 & r2 & val;
}
};

View File

@ -62,6 +62,7 @@ void registerTypes1(Serializer &s)
s.template registerType<CGDenOfthieves>();
s.template registerType<CGObelisk>();
s.template registerType<CGLighthouse>();
s.template registerType<CGMarket>();
}
template<typename Serializer> DLL_EXPORT

View File

@ -1935,6 +1935,16 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
nobj->tempOwner = readNormalNr(bufor,i); i+=4;
break;
}
case 2: //Altar of Sacrifice
case 7: //Black Market
case 99: //Trading Post
case 213: //Freelancer's Guild
case 221: //Trading Post (snow)
{
nobj = new CGMarket();
break;
}
default: //any other object
{
nobj = new CGObjectInstance();

View File

@ -2968,24 +2968,38 @@ bool CGameHandler::buyArtifact( ui32 hid, si32 aid )
return false;
}
bool CGameHandler::tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 )
bool CGameHandler::tradeResources(const IMarket *market, ui32 val, ui8 player, ui32 id1, ui32 id2)
{
val = std::min(si32(val),gs->getPlayer(player)->resources[id1]);
double yield = (double)gs->resVals[id1] * val * gs->getMarketEfficiency(player);
yield /= gs->resVals[id2];
int r1 = gs->getPlayer(player)->resources[id1],
r2 = gs->getPlayer(player)->resources[id2];
amin(val, r1); //can't trade more resources than have
int b1, b2; //base quantities for trade
market->getOffer(id1, id2, b1, b2, RESOURCE_RESOURCE);
int units = val / b1; //how many base quantities we trade
if(val%b1) //all offered units of resource should be used, if not -> somewhere in calculations must be an error
{
//TODO: complain?
assert(0);
}
SetResource sr;
sr.player = player;
sr.resid = id1;
sr.val = gs->getPlayer(player)->resources[id1] - val;
sr.val = r1 - b1 * units;
sendAndApply(&sr);
sr.resid = id2;
sr.val = gs->getPlayer(player)->resources[id2] + (int)yield;
sr.val = r2 + b2 * units;
sendAndApply(&sr);
return true;
}
bool CGameHandler::sendResources(ui32 val, ui8 player, ui32 r1, ui32 r2)
{
const PlayerState *p2 = gs->getPlayer(r2, false);

View File

@ -36,6 +36,8 @@ struct SetResource;
struct SetResources;
struct NewStructures;
class CGHeroInstance;
class IMarket;
extern std::map<ui32, CFunctionList<void(ui32)> > callbacks; //question id => callback functions - for selection dialogs
extern boost::mutex gsm;
@ -163,7 +165,7 @@ public:
bool hireHero( ui32 tid, ui8 hid );
bool buildBoat( ui32 objid );
bool setFormation( si32 hid, ui8 formation );
bool tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 );
bool tradeResources(const IMarket *market, ui32 val, ui8 player, ui32 id1, ui32 id2);
bool sendResources(ui32 val, ui8 player, ui32 r1, ui32 r2);
bool assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assemble, ui32 assembleTo);
bool buyArtifact( ui32 hid, si32 aid );

View File

@ -1,5 +1,8 @@
#include "../lib/NetPacks.h"
#include "CGameHandler.h"
#include "../hch/CObjectHandler.h"
#include "../lib/IGameCallback.h"
#include "../lib/map.h"
#define PLAYER_OWNS(id) (gh->getPlayerAt(c)==gh->getOwner(id))
@ -7,6 +10,7 @@
tlog1<<"Player is not allowed to perform this action!\n"; \
return false;}
#define ERROR_IF_NOT_OWNS(id) if(!PLAYER_OWNS(id)) ERROR_AND_RETURN
#define COMPLAIN_AND_RETURN(txt) { gh->complain(txt); ERROR_AND_RETURN }
/*
* NetPacksServer.cpp, part of VCMI engine
@ -111,11 +115,30 @@ bool BuyArtifact::applyGh( CGameHandler *gh )
bool TradeOnMarketplace::applyGh( CGameHandler *gh )
{
if(gh->getPlayerAt(c) != player) ERROR_AND_RETURN;
//market must be owned or visited
const IMarket *m = IMarket::castFrom(market);
if(!m)
COMPLAIN_AND_RETURN("market is not-a-market! :/");
ui8 player = market->tempOwner;
if(player >= PLAYER_LIMIT)
player = gh->getTile(market->visitablePos())->visitableObjects.back()->tempOwner;
if(player >= PLAYER_LIMIT)
COMPLAIN_AND_RETURN("No player can use this market!");
if(hero && (player != hero->tempOwner || hero->visitablePos() != market->visitablePos()))
COMPLAIN_AND_RETURN("This hero can't use this marketplace!");
if(gh->getPlayerAt(c) != player)
ERROR_AND_RETURN;
switch(mode)
{
case RESOURCE_RESOURCE:
return gh->tradeResources(val,player,r1,r2);
return gh->tradeResources(m, val, player, r1, r2);
case RESOURCE_PLAYER:
return gh->sendResources(val, player, r1, r2);
default: