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

* Freelancer's Guild support (both town structure and adventure map object)

* fixed crashes on r-click on hero in tavern and adv map
* fixed descync issue
* allow free movement FROM guarded tile
This commit is contained in:
Michał W. Urbańczyk 2010-05-26 09:47:53 +00:00
parent 6541e89f90
commit 8bda10b695
14 changed files with 335 additions and 104 deletions

View File

@ -38,12 +38,14 @@ TOWNS:
* Support for new town structures:
- Lighthouse
- Colossus
- Freelancer's Guild
- Guardian Spirit
- Necromancy Amplifier
- Soul Prison
OBJECTS:
New object supported:
- Freelancer's Guild
- Trading Post
- War Machine Factory

View File

@ -23,6 +23,7 @@
#include <boost/lexical_cast.hpp>
#include <cmath>
#include <sstream>
#include <boost/format.hpp>
using namespace boost::assign;
using namespace CSDL_Ext;
@ -557,6 +558,8 @@ void CCastleInterface::buildingClicked(int building)
building = town->town->hordeLvl[1] + 30;
}
const CBuilding *b = CGI->buildh->buildings[town->subID][building];
if(building >= 30)
{
showRecruitmentWindow(building);
@ -635,7 +638,7 @@ void CCastleInterface::buildingClicked(int building)
break;
case 14: //marketplace
{
CMarketplaceWindow *cmw = new CMarketplaceWindow(town);
CMarketplaceWindow *cmw = new CMarketplaceWindow(town, town->visitingHero);
GH.pushInt(cmw);
break;
}
@ -648,13 +651,13 @@ void CCastleInterface::buildingClicked(int building)
{
switch(town->subID)
{
/*Rampart*/ case 1://Mystic Pond
/*Rampart*/ case 1://Mystic Pond
enterFountain(building);
break;
/*Tower*/ case 2://Artifact Merchant
/*Dungeon*/ case 5://Artifact Merchant
/*Conflux*/ case 8://Artifact Merchant
tlog4<<"Artifact Merchant not handled\n";
/*Tower*/ case 2://Artifact Merchant
/*Dungeon*/ case 5://Artifact Merchant
/*Conflux*/ case 8://Artifact Merchant
GH.pushInt(new CMarketplaceWindow(town, town->visitingHero, RESOURCE_ARTIFACT));
break;
default:
defaultBuildingClicked(building);
@ -671,13 +674,16 @@ void CCastleInterface::buildingClicked(int building)
{
switch(town->subID)
{
/*Rampart*/ case 1: //Fountain of Fortune
/*Rampart*/ case 1: //Fountain of Fortune
enterFountain(building);
break;
/*Stronghold*/ case 6: //Freelancer's Guild
tlog4<<"Freelancer's Guild not handled\n";
/*Stronghold*/case 6: //Freelancer's Guild
if(town->visitingHero)
GH.pushInt(new CMarketplaceWindow(town, town->visitingHero, CREATURE_RESOURCE));
else
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % b->Name())); //Only visiting heroes may use the %s.
break;
/*Conflux*/ case 8: //Magic University
/*Conflux*/ case 8: //Magic University
tlog4<<"Magic University not handled\n";
break;
default:

View File

@ -478,11 +478,15 @@ void CPlayerInterface::garrisonChanged(const CGObjectInstance * obj)
wwg->garr->recreateSlots();
wasGarrison = true;
}
else
else if(CKingdomInterface *cki = dynamic_cast<CKingdomInterface*>(*i))
{//a cheat for Kingdom Overview window (it has CWindowWithGarrison-childrens which are not present in ListInt)
CKingdomInterface *cki = dynamic_cast<CKingdomInterface*>(*i);//need to create "Garrison Holder" class thingy
if (cki)
cki->updateAllGarrisons();
//need to create "Garrison Holder" class thingy
cki->updateAllGarrisons();
}
else if(CMarketplaceWindow *cmw = dynamic_cast<CMarketplaceWindow*>(*i))
{
if(obj == cmw->hero)
cmw->garrisonChanged();
}
}
@ -1977,6 +1981,6 @@ void CPlayerInterface::stopMovement()
void CPlayerInterface::showMarketWindow(const IMarket *market, const CGHeroInstance *visitor)
{
CMarketplaceWindow *cmw = new CMarketplaceWindow(market, market->availableModes().front());
CMarketplaceWindow *cmw = new CMarketplaceWindow(market, visitor, market->availableModes().front());
GH.pushInt(cmw);
}

View File

@ -2581,8 +2581,9 @@ CCustomImgComponent::~CCustomImgComponent()
SDL_FreeSurface(bmp);
}
CMarketplaceWindow::CTradeableItem::CTradeableItem( int Type, int ID, bool Left)
CMarketplaceWindow::CTradeableItem::CTradeableItem( EType Type, int ID, bool Left, int Serial)
{
serial = Serial;
left = Left;
type = Type;
id = ID;
@ -2639,24 +2640,29 @@ SDL_Surface * CMarketplaceWindow::CTradeableItem::getSurface()
return graphics->flags->ourImages[id].bitmap;
case ARTIFACT:
return graphics->artDefs->ourImages[id].bitmap;
case CREATURE:
return graphics->bigImgs[id];
default:
return NULL;
}
}
static void initItems( std::vector<CMarketplaceWindow::CTradeableItem*> &i, std::vector<Rect> &p, int type, int amount, bool left, std::vector<int> *ids/*=NULL*/ )
static void initItems( std::vector<CMarketplaceWindow::CTradeableItem*> &i, std::vector<Rect> &p, CMarketplaceWindow::EType type, int amount, bool left, std::vector<int> *ids/*=NULL*/ )
{
if(ids)
amin(amount, ids->size());
i.resize(amount);
for(int j=0;j<amount;j++)
{
i[j] = new CMarketplaceWindow::CTradeableItem(type,(ids && ids->size()>j) ? (*ids)[j] : j, left);
i[j]->pos = p[j] + i[j]->pos;
int id = (ids && ids->size()>j) ? (*ids)[j] : j;
if(id < 0)
continue;
i.push_back(new CMarketplaceWindow::CTradeableItem(type, id, left, j));
i.back()->pos = p[j] + i.back()->pos;
}
}
CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, EMarketMode Mode)
:market(Market)
CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstance *Hero, EMarketMode Mode)
:market(Market), hero(Hero), hLeft(NULL), hRight(NULL), readyToTrade(false)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
type = BLOCK_ADV_HOTKEYS;
@ -2675,6 +2681,7 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, EMarketMode Mode)
ltype = RESOURCE;
rtype = RESOURCE;
break;
case RESOURCE_PLAYER:
bgName = "TPMRKPTS.bmp";
ltype = RESOURCE;
@ -2685,13 +2692,40 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, EMarketMode Mode)
if(i != LOCPLINT->playerID && LOCPLINT->cb->getPlayerStatus(i) == PlayerState::INGAME)
rIds->push_back(i);
break;
case CREATURE_RESOURCE:
bgName = "TPMRKCRS.bmp";
ltype = CREATURE;
rtype = RESOURCE;
lIds = new std::vector<int>;
for(int i = 0; i < 7; i++)
{
if(const CCreature *c = hero->getCreature(i))
lIds->push_back(c->idNumber);
else
lIds->push_back(-1);
}
break;
}
bg = new CPicture(bgName);
bg->colorizeAndConvert(LOCPLINT->playerID);
printAtMiddle(CGI->generaltexth->allTexts[158],300,27,FONT_BIG,tytulowy,*bg); //title
printAtMiddle(CGI->generaltexth->allTexts[270],154,148,FONT_SMALL,zwykly,*bg); //kingdom res.
if(market->o->ID == 99 || market->o->ID == 221)
{
printAtMiddle(CGI->generaltexth->allTexts[159],300,27,FONT_BIG,tytulowy,*bg); //title
}
else if(mode == CREATURE_RESOURCE)
{
if(market->o->ID == TOWNI_TYPE)
printAtMiddle(CGI->buildh->buildings[6][21]->Name(), 300, 27, FONT_BIG, tytulowy, *bg); //title
else
printAtMiddle(market->o->getHoverText(), 300, 27, FONT_BIG, tytulowy, *bg); //title
}
else
{
printAtMiddle(CGI->generaltexth->allTexts[158],300,27,FONT_BIG,tytulowy,*bg); //trading post
}
std::vector<Rect> lpos, rpos;
getPositionsFor(lpos, false, ltype);
@ -2705,28 +2739,44 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, EMarketMode Mode)
//slider and buttons must be created after bg
slider = new CSlider(231,490,137,boost::bind(&CMarketplaceWindow::sliderMoved,this,_1),0,0);
hLeft = hRight = NULL;
ok = new AdventureMapButton("","",boost::bind(&CGuiHandler::popIntTotally,&GH,this),516,520,"IOK6432.DEF",SDLK_RETURN);
ok->assignedKeys.insert(SDLK_ESCAPE);
deal = new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::makeDeal,this),307,520,"TPMRKB.DEF");
max = new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMax,this),229,520,"IRCBTNS.DEF");
//left side
switch(Mode)
{
case RESOURCE_RESOURCE:
{
new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, RESOURCE_PLAYER), 18, 520,"TPMRKBU1.DEF");
printAtMiddle(CGI->generaltexth->allTexts[168],445,147,FONT_SMALL,zwykly,*bg); //available for trade
}
break;
case RESOURCE_PLAYER:
{
new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, RESOURCE_RESOURCE), 516, 450,"TPMRKBU5.DEF");
printAtMiddle(CGI->generaltexth->allTexts[169],445,55,FONT_SMALL,zwykly,*bg); //players
}
printAtMiddle(CGI->generaltexth->allTexts[270],154,148,FONT_SMALL,zwykly,*bg); //kingdom res.
break;
case CREATURE_RESOURCE:
printAtMiddle(boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->name), 152, 102, FONT_SMALL, zwykly, *bg); //%s's Creatures
break;
}
//right side
switch(Mode)
{
case RESOURCE_RESOURCE:
case CREATURE_RESOURCE:
printAtMiddle(CGI->generaltexth->allTexts[168],445,148,FONT_SMALL,zwykly,*bg); //available for trade
break;
case RESOURCE_PLAYER:
printAtMiddle(CGI->generaltexth->allTexts[169],445,55,FONT_SMALL,zwykly,*bg); //players
break;
}
if(printButtonFor(RESOURCE_PLAYER))
new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, RESOURCE_PLAYER), 18, 520,"TPMRKBU1.DEF");
if(printButtonFor(RESOURCE_RESOURCE))
new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, RESOURCE_RESOURCE), 516, 450,"TPMRKBU5.DEF");
if(printButtonFor(CREATURE_RESOURCE))
new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, CREATURE_RESOURCE), 516, 450,"TPMRKBU4.DEF");
max->block(true);
deal->block(true);
}
@ -2745,9 +2795,9 @@ CMarketplaceWindow::~CMarketplaceWindow()
bg = NULL;
}
void CMarketplaceWindow::show(SDL_Surface * to)
void CMarketplaceWindow::showAll(SDL_Surface * to)
{
CIntObject::show(to);
CIntObject::showAll(to);
if(hRight)
@ -2756,49 +2806,62 @@ void CMarketplaceWindow::show(SDL_Surface * to)
CSDL_Ext::drawBorder(to,hLeft->pos.x-1,hLeft->pos.y-1,hLeft->pos.w+2,hLeft->pos.h+2,int3(255,231,148));
//left side
if(mode == RESOURCE_RESOURCE || mode == RESOURCE_PLAYER)
switch(ltype)
{
case RESOURCE:
for(int i=0;i<left.size();i++)
printAtMiddle(boost::lexical_cast<std::string>(LOCPLINT->cb->getResourceAmount(i)),
left[i]->pos.x+36,left[i]->pos.y+57,FONT_SMALL,zwykly,to);
printAtMiddle(boost::lexical_cast<std::string>(LOCPLINT->cb->getResourceAmount(i)), left[i]->pos.x+36,left[i]->pos.y+57,FONT_SMALL,zwykly,to);
if(hLeft && hRight && (hLeft->id != hRight->id || mode != RESOURCE_RESOURCE))
if(readyToTrade)
{
blitAt(hLeft->getSurface(),pos.x+141,pos.y+457,to);
printAtMiddle(boost::lexical_cast<std::string>( slider->value * r1 ),pos.x+156,pos.y+505,FONT_SMALL,zwykly,to);
}
break;
case CREATURE:
BOOST_FOREACH(CTradeableItem *t, left)
printAtMiddle(boost::lexical_cast<std::string>(hero->getAmount(t->serial)), t->pos.x+29, t->pos.y+76, FONT_SMALL, zwykly, to);
if(readyToTrade)
{
blitAt(hLeft->getSurface(),pos.x+128,pos.y+450,to);
printAtMiddle(boost::lexical_cast<std::string>( slider->value * r1 ),pos.x+160,pos.y+527,FONT_SMALL,zwykly,to);
}
break;
}
if(mode == RESOURCE_RESOURCE)
//right side
switch(rtype)
{
case RESOURCE:
if(hLeft) //print prices
{
for(int i=0; i<right.size();i++)
{
if(right[i]->id != hLeft->id)
if(right[i]->id != hLeft->id || mode != RESOURCE_RESOURCE)
printAtMiddle(rSubs[i],right[i]->pos.x+36,right[i]->pos.y+57,FONT_SMALL,zwykly,to);
else
printAtMiddle(CGI->generaltexth->allTexts[164],right[i]->pos.x+36,right[i]->pos.y+57,FONT_SMALL,zwykly,to);
}
}
if(hLeft && hRight && (hLeft->id != hRight->id))
if(readyToTrade)
{
blitAt(hRight->getSurface(),pos.x+429,pos.y+457,to);
printAtMiddle(boost::lexical_cast<std::string>( slider->value * r2 ),pos.x+443,pos.y+505,FONT_SMALL,zwykly,to);
}
}
else if(mode == RESOURCE_PLAYER)
{
break;
case PLAYER:
BOOST_FOREACH(CTradeableItem *i, right)
printAtMiddle(CGI->generaltexth->capColors[i->id], i->pos.x + 31, i->pos.y + 76, FONT_SMALL, zwykly, to);
if(hLeft && hRight)
if(readyToTrade)
{
blitAt(hRight->getSurface(),pos.x+417,pos.y+451,to);
printAtMiddle(CGI->generaltexth->capColors[hRight->id], pos.x+417 + 31, pos.y+451 + 76, FONT_SMALL, zwykly, to);
}
break;
}
}
@ -2809,30 +2872,44 @@ void CMarketplaceWindow::setMax()
void CMarketplaceWindow::makeDeal()
{
LOCPLINT->cb->trade(market->o, mode, hLeft->id, hRight->id, slider->value*r1);
if(!slider->value)
return;
int leftIdToSend = -1;
if(mode == CREATURE_RESOURCE)
leftIdToSend = hLeft->serial;
else
leftIdToSend = hLeft->id;
LOCPLINT->cb->trade(market->o, mode, leftIdToSend, hRight->id, slider->value*r1, hero);
slider->moveTo(0);
hLeft = NULL;
hRight = NULL;
selectionChanged(true);
}
void CMarketplaceWindow::sliderMoved( int to )
{
redraw();
}
void CMarketplaceWindow::selectionChanged(bool side)
{
if(hLeft && hRight && (hLeft->id!= hRight->id || mode != RESOURCE_RESOURCE))
readyToTrade = (hLeft && hRight && (hLeft->id!= hRight->id || mode != RESOURCE_RESOURCE));
if(readyToTrade)
{
if(mode == RESOURCE_RESOURCE)
{
market->getOffer(hLeft->id, hRight->id, r1, r2, mode);
slider->setAmount(LOCPLINT->cb->getResourceAmount(hLeft->id) / r1);
}
else if(mode == RESOURCE_PLAYER)
{
r1 = 1;
slider->setAmount(LOCPLINT->cb->getResourceAmount(hLeft->id));
}
int newAmount = -1;
market->getOffer(hLeft->id, hRight->id, r1, r2, mode);
if(ltype == RESOURCE)
newAmount = LOCPLINT->cb->getResourceAmount(hLeft->id);
else if(ltype == CREATURE)
newAmount = hero->getAmount(hLeft->serial) - (hero->Slots().size() == 1 && hero->needsLastStack());
else
assert(0);
slider->setAmount(newAmount / r1);
slider->moveTo(0);
max->block(false);
deal->block(false);
@ -2851,7 +2928,7 @@ 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);
market->getOffer(hLeft->id, i, h1, h2, mode);
std::ostringstream oss;
oss << h2;
@ -2860,35 +2937,84 @@ void CMarketplaceWindow::selectionChanged(bool side)
rSubs[i] = oss.str();
}
}
redraw();
}
void CMarketplaceWindow::getPositionsFor(std::vector<Rect> &poss, bool Right, EType type) const
{
if(type == RESOURCE)
{
poss += genRect(66,74,39 ,180), genRect(66,74,122,180), genRect(66,74,204,180),
genRect(66,74,39,259), genRect(66,74,122,259), genRect(66,74,204,259),
genRect(66,74,122,338);
if(Right)
BOOST_FOREACH(Rect &r, poss)
r.x += 288;
}
else if(type == PLAYER)
int h, w, x, y, dx, dy;
int leftToRightOffset = 288;
switch(type)
{
case RESOURCE:
dx = 82;
dy = 79;
x = 39;
y = 180;
h = 66;
w = 74;
break;
case PLAYER:
dx = 83;
dy = 118;
h = 64;
w = 58;
x = 44;
y = 83;
assert(Right);
poss += genRect(64, 58, 333, 84), genRect(64, 58, 333 + 83, 84), genRect(64, 58, 333 + 2 * 83, 84),
genRect(64, 58, 333, 84 + 118), genRect(64, 58, 333 + 83, 84 + 118), genRect(64, 58, 333 + 2 * 83, 84 + 118),
genRect(64, 58, 333 + 83, 84 + 2*118);
break;
case CREATURE://45,123
x = 45;
y = 123;
w = 58;
h = 64;
dx = 83;
dy = 98;
assert(!Right);
}
poss += genRect(h, w, x, y), genRect(h, w, x + dx, y), genRect(h, w, x + 2*dx, y),
genRect(h, w, x, y + dy), genRect(h, w, x + dx, y + dy), genRect(h, w, x + 2*dx, y + dy),
genRect(h, w, x + dx, y + 2*dy);
if(Right)
BOOST_FOREACH(Rect &r, poss)
r.x += leftToRightOffset;
}
void CMarketplaceWindow::setMode(EMarketMode Mode)
{
CMarketplaceWindow *nwindow = new CMarketplaceWindow(market, Mode);
CMarketplaceWindow *nwindow = new CMarketplaceWindow(market, hero, Mode);
GH.popIntTotally(this);
GH.pushInt(nwindow);
}
bool CMarketplaceWindow::printButtonFor(EMarketMode M) const
{
return market->allowsTrade(M) && M != mode && (hero || mode != CREATURE_RESOURCE);
}
void CMarketplaceWindow::garrisonChanged()
{
if(mode != CREATURE_RESOURCE)
return;
std::set<CTradeableItem *> toRemove;
BOOST_FOREACH(CTradeableItem *t, left)
if(!hero->getAmount(t->serial))
toRemove.insert(t);
BOOST_FOREACH(CTradeableItem *t, toRemove)
{
if(active)
t->deactivate();
left -= t;
delChild(t);
}
}
CSystemOptionsWindow::CSystemOptionsWindow(const SDL_Rect &pos, CPlayerInterface * owner)
{
this->pos = pos;

View File

@ -518,26 +518,29 @@ public:
class CMarketplaceWindow : public CIntObject
{
bool printButtonFor(EMarketMode M) const;
public:
enum EType
{
RESOURCE, PLAYER, ARTIFACT
RESOURCE, PLAYER, ARTIFACT, CREATURE
};
class CTradeableItem : public CIntObject
{
public:
int type; //0 - res, 1 - artif big, 2 - artif small, 3 - player flag
int id;
EType type;
int id;
int serial;
bool left;
CFunctionList<void()> callback;
void show(SDL_Surface * to);
void clickLeft(tribool down, bool previousState);
SDL_Surface *getSurface();
CTradeableItem(int Type, int ID, bool Left);
CTradeableItem(EType Type, int ID, bool Left, int Serial);
};
const IMarket *market;
const CGHeroInstance *hero;
CPicture *bg; //background
std::vector<CTradeableItem*> left, right;
std::vector<std::string> rSubs; //offer caption
@ -548,17 +551,20 @@ public:
int r1, r2; //suggested amounts of traded resources
AdventureMapButton *ok, *max, *deal;
CSlider *slider; //for choosing amount to be exchanged
bool readyToTrade;
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
void setMax();
void sliderMoved(int to);
void makeDeal();
void selectionChanged(bool side); //true == left
CMarketplaceWindow(const IMarket *Market, EMarketMode Mode = RESOURCE_RESOURCE); //c-tor
CMarketplaceWindow(const IMarket *Market, const CGHeroInstance *Hero = NULL, EMarketMode Mode = RESOURCE_RESOURCE); //c-tor
~CMarketplaceWindow(); //d-tor
void setMode(EMarketMode Mode); //mode setter
void getPositionsFor(std::vector<Rect> &poss, bool Right, EType type) const;
void garrisonChanged(); //removes creatures with count 0 from the list (apparently whole stack has been sold)
};
class CSystemOptionsWindow : public CIntObject

View File

@ -61,7 +61,7 @@ SDL_Surface * Graphics::drawHeroInfoWin(const InfoAboutHero &curh)
}
else
{
printAtMiddle(VLC->generaltexth->arraytxt[174 + 3*i->second.count],slotsPos[(*i).first].first+17,slotsPos[(*i).first].second+41,FONT_TINY,zwykly,ret);
printAtMiddle(VLC->generaltexth->arraytxt[174 + 3*(i->second.count-1)],slotsPos[(*i).first].first+17,slotsPos[(*i).first].second+41,FONT_TINY,zwykly,ret);
}
}

View File

@ -79,7 +79,7 @@ void IObjectInterface::preInit()
void CPlayersVisited::setPropertyDer( ui8 what, ui32 val )
{
if(what == 10)
players.insert(val);
players.insert((ui8)val);
}
bool CPlayersVisited::hasVisited( ui8 player ) const
@ -1162,6 +1162,7 @@ void CGHeroInstance::pushPrimSkill(int which, int val)
void CGHeroInstance::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
{
#define FOREACH_OWNER_TOWN(town) if(const PlayerState *p = cb->getPlayerState(tempOwner)) BOOST_FOREACH(const CGTownInstance *town, p->towns)
CArmedInstance::getBonuses(out, selector, root);
//TODO eliminate by moving secondary skills effects to bonus system
@ -1172,7 +1173,7 @@ void CGHeroInstance::getBonuses(BonusList &out, const CSelector &selector, const
out.push_back(Bonus(Bonus::PERMANENT, Bonus::LUCK, Bonus::SECONDARY_SKILL, luckSkill, 9, VLC->generaltexth->arraytxt[73+luckSkill]));
//guardian spirit
BOOST_FOREACH(const CGTownInstance *t, cb->getPlayerState(tempOwner)->towns)
FOREACH_OWNER_TOWN(t)
if(t->subID ==1 && vstd::contains(t->builtBuildings,26)) //rampart with grail
out.push_back(Bonus(Bonus::PERMANENT, Bonus::LUCK, Bonus::TOWN_STRUCTURE, +2, 26, VLC->generaltexth->buildings[1][26].first + " +2"));
}
@ -1180,7 +1181,7 @@ void CGHeroInstance::getBonuses(BonusList &out, const CSelector &selector, const
if(Selector::matchesType(selector, Bonus::SEA_MOVEMENT))
{
//lighthouses
BOOST_FOREACH(const CGTownInstance *t, cb->getPlayerState(tempOwner)->towns)
FOREACH_OWNER_TOWN(t)
if(t->subID == 0 && vstd::contains(t->builtBuildings,17)) //castle
out.push_back(Bonus(Bonus::PERMANENT, Bonus::SEA_MOVEMENT, Bonus::TOWN_STRUCTURE, +500, 17, VLC->generaltexth->buildings[0][17].first + " +500"));
}
@ -1192,14 +1193,14 @@ void CGHeroInstance::getBonuses(BonusList &out, const CSelector &selector, const
out.push_back(Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::SECONDARY_SKILL, moraleSkill, 6, VLC->generaltexth->arraytxt[104+moraleSkill]));
//colossus
BOOST_FOREACH(const CGTownInstance *t, cb->getPlayerState(tempOwner)->towns)
FOREACH_OWNER_TOWN(t)
if(t->subID == 0 && vstd::contains(t->builtBuildings,26)) //castle
out.push_back(Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::TOWN_STRUCTURE, +2, 26, VLC->generaltexth->buildings[0][26].first + " +2"));
}
if(Selector::matchesTypeSubtype(selector, Bonus::SECONDARY_SKILL_PREMY, 12)) //necromancy
{
BOOST_FOREACH(const CGTownInstance *t, cb->getPlayerState(tempOwner)->towns)
FOREACH_OWNER_TOWN(t)
{
if(t->subID == 4) //necropolis
{
@ -5932,7 +5933,30 @@ bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode)
val2 = 1;
}
}
break;
case CREATURE_RESOURCE:
{
const float effectivenessArray[] = {0, 0.3, 0.45, 0.50, 0.65, 0.7, 0.85, 0.9, 1};
float effectiveness = effectivenessArray[std::min(getMarketEfficiency(), 8)];
float r = VLC->creh->creatures[id1]->cost[6], //value of given creature in gold
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;
case RESOURCE_PLAYER:
val1 = 1;
val2 = 1;
break;
default:
assert(0);
@ -5949,19 +5973,29 @@ bool IMarket::allowsTrade(EMarketMode mode) const
int IMarket::availableUnits(EMarketMode mode, int marketItemSerial) const
{
if(mode == RESOURCE_RESOURCE || ARTIFACT_RESOURCE || CREATURE_RESOURCE)
return -1;
else
return 1;
switch(mode)
{
case RESOURCE_RESOURCE:
case ARTIFACT_RESOURCE:
case CREATURE_RESOURCE:
return -1;
default:
return 1;
}
}
std::vector<int> IMarket::availableItemsIds(EMarketMode mode) const
{
std::vector<int> ret;
if(mode == RESOURCE_RESOURCE || ARTIFACT_RESOURCE || CREATURE_RESOURCE)
switch(mode)
{
case RESOURCE_RESOURCE:
case ARTIFACT_RESOURCE:
case CREATURE_RESOURCE:
for (int i = 0; i < 7; i++)
ret.push_back(i);
break;
}
return ret;
}
@ -5971,8 +6005,10 @@ const IMarket * IMarket::castFrom(const CGObjectInstance *obj)
{
case TOWNI_TYPE:
return static_cast<const CGTownInstance*>(obj);
case 7: //Black Market
case 99: //Trading Post
case 221: //Trading Post (snow)
case 213: //Freelancer's Guild
return static_cast<const CGMarket*>(obj);
default:
tlog1 << "Cannot cast to IMarket object with ID " << obj->ID << std::endl;
@ -6034,7 +6070,10 @@ bool CGMarket::allowsTrade(EMarketMode mode) const
default:
return false;
}
case CREATURE_RESOURCE:
return ID == 213; //Freelancer's Guild
}
return false;
}
int CGMarket::availableUnits(EMarketMode mode, int marketItemSerial) const

View File

@ -192,6 +192,7 @@ void CCreatureSet::setFormation(bool tight)
void CCreatureSet::setStackCount(TSlot slot, TQuantity count)
{
assert(vstd::contains(slots, slot));
assert(count > 0);
slots[slot].count = count;
}

View File

@ -80,7 +80,7 @@ public:
virtual bool needsLastStack() const; //true if last stack cannot be taken
int getArmyStrength() const; //sum of AI values of creatures
ui64 getPower (TSlot slot) const; //value of specific stack
std::string getRoughAmount (TSlot slot) const; //rought size of specific stack
std::string getRoughAmount (TSlot slot) const; //rough size of specific stack
bool contains(const CStackInstance *stack) const;

View File

@ -1752,7 +1752,7 @@ void CGameState::getNeighbours( const TerrainTile &srct, int3 tile, std::vector<
const TerrainTile &hlpt = map->getTile(hlp);
//we cannot visit things from blocked tiles
if(srct.blocked && hlpt.visitable)
if(srct.blocked && hlpt.visitable && srct.blockingObjects.front()->ID != HEROI_TYPE)
{
continue;
}
@ -2216,6 +2216,8 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
CGPathNode *cp = mq.front();
mq.pop();
const int3 guardPosition = guardingCreaturePosition(cp->coord);
const bool guardedPosition = (guardPosition != int3(-1, -1, -1) && cp->coord != src);
const TerrainTile &ct = map->getTile(cp->coord);
int movement = cp->moveRemains, turn = cp->turns;
if(!movement)
@ -2252,7 +2254,6 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
remains = moveAtNextTile - cost;
}
const bool guardedPosition = guardingCreaturePosition(cp->coord) != int3(-1, -1, -1);
const bool neighborIsGuard = guardingCreaturePosition(cp->coord) == dp.coord;
if((dp.turns==0xff //we haven't been here before
@ -2267,10 +2268,10 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
dp.theNodeBefore = cp;
const bool guardedNeighbor = guardingCreaturePosition(dp.coord) != int3(-1, -1, -1);
const bool positionIsGuard = guardingCreaturePosition(cp->coord) == cp->coord;
//const bool positionIsGuard = guardingCreaturePosition(cp->coord) == cp->coord; //can this be true? hero never passes from monster tile...
if (dp.accessible == CGPathNode::ACCESSIBLE || dp.accessible == CGPathNode::FLYABLE
|| (guardedNeighbor && !positionIsGuard)) // Can step into a hostile tile once.
|| (guardedNeighbor && !guardedPosition)) // Can step into a hostile tile once.
{
mq.push(&dp);
}
@ -3851,7 +3852,7 @@ void InfoAboutHero::initFromHero( const CGHeroInstance *h, bool detailed )
//hide info about hero stacks counts using descriptives names ids
for(TSlots::const_iterator i = army.Slots().begin(); i != army.Slots().end(); ++i)
{
army.setStackCount(i->first, i->second.getQuantityID());
army.setStackCount(i->first, i->second.getQuantityID()+1);
}
}
}

View File

@ -1064,7 +1064,7 @@ void CGameHandler::newTurn()
}
}
}
void CGameHandler::run(bool resume)
void CGameHandler::run(bool resume, const StartInfo *si /*= NULL*/)
{
using namespace boost::posix_time;
BOOST_FOREACH(CConnection *cc, conns)
@ -1072,7 +1072,7 @@ void CGameHandler::run(bool resume)
ui8 quantity, pom;
//ui32 seed;
if(!resume)
(*cc) << gs->scenarioOps << gs->map->checksum << gs->seed;
(*cc) << si << gs->map->checksum << gs->seed; // gs->scenarioOps
(*cc) >> quantity; //how many players will be handled at that client
for(int i=0;i<quantity;i++)
@ -3028,6 +3028,46 @@ bool CGameHandler::tradeResources(const IMarket *market, ui32 val, ui8 player, u
return true;
}
bool CGameHandler::sellCreatures(ui32 count, const IMarket *market, const CGHeroInstance * hero, ui32 slot, ui32 resourceID)
{
if(!vstd::contains(hero->Slots(), slot))
COMPLAIN_RET("Hero doesn't have any creature in that slot!");
const CStackInstance &s = hero->getStack(slot);
if(s.count < count //can't sell more creatures than have
|| hero->Slots().size() == 1 && hero->needsLastStack() && s.count == count) //can't sell last stack
{
COMPLAIN_RET("Not enough creatures in army!");
}
int b1, b2; //base quantities for trade
market->getOffer(s.type->idNumber, resourceID, b1, b2, CREATURE_RESOURCE);
int units = count / b1; //how many base quantities we trade
if(count%b1) //all offered units of resource should be used, if not -> somewhere in calculations must be an error
{
//TODO: complain?
assert(0);
}
SetGarrisons sg;
sg.garrs[hero->id] = hero->getArmy();
if(s.count > count)
sg.garrs[hero->id].setStackCount(slot, s.count - count);
else
sg.garrs[hero->id].eraseStack(slot);
sendAndApply(&sg);
SetResource sr;
sr.player = hero->tempOwner;
sr.resid = resourceID;
sr.val = getResource(hero->tempOwner, resourceID) + b2 * units;
sendAndApply(&sr);
return true;
}
bool CGameHandler::sendResources(ui32 val, ui8 player, ui32 r1, ui32 r2)
{

View File

@ -167,6 +167,7 @@ public:
bool setFormation( si32 hid, ui8 formation );
bool tradeResources(const IMarket *market, ui32 val, ui8 player, ui32 id1, ui32 id2);
bool sendResources(ui32 val, ui8 player, ui32 r1, ui32 r2);
bool sellCreatures(ui32 count, const IMarket *market, const CGHeroInstance * hero, ui32 slot, ui32 resourceID);
bool assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assemble, ui32 assembleTo);
bool buyArtifact( ui32 hid, si32 aid );
bool swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, ui16 destSlot);
@ -203,7 +204,7 @@ public:
void sendAndApply(SetResources * info);
void sendAndApply(NewStructures * info);
void run(bool resume);
void run(bool resume, const StartInfo *si = NULL);
void newTurn();
void handleAfterAttackCasting( const BattleAttack & bat );
friend class CVCMIServer;

View File

@ -92,6 +92,7 @@ void CVCMIServer::newGame(CConnection *c)
*c << ui8(0); //OK!
}
StartInfo startInfoCpy = *si;
gh.init(si,rand());
c->setGS(gh.gs);
@ -118,7 +119,7 @@ void CVCMIServer::newGame(CConnection *c)
gh.conns.insert(cc);
}
gh.run(false);
gh.run(false, &startInfoCpy);
}
void CVCMIServer::start()
{

View File

@ -141,6 +141,10 @@ bool TradeOnMarketplace::applyGh( CGameHandler *gh )
return gh->tradeResources(m, val, player, r1, r2);
case RESOURCE_PLAYER:
return gh->sendResources(val, player, r1, r2);
case CREATURE_RESOURCE:
if(!hero)
COMPLAIN_AND_RETURN("Only hero can sell creatures!");
return gh->sellCreatures(val, m, hero, r1, r2);
default:
gh->complain("Unknown exchange mode!");
ERROR_AND_RETURN;