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

Fourth part of sailing code.

Support for Shipyard (both for town and adventure map versions). Improved boat displaying code. Minor changes.
This commit is contained in:
Michał W. Urbańczyk 2009-07-26 03:33:13 +00:00
parent 7853a19b54
commit 9fd4b5bb62
23 changed files with 527 additions and 52 deletions

View File

@ -732,6 +732,13 @@ void CCallback::sendMessage(const std::string &mess)
*cl->serv << &pm; *cl->serv << &pm;
} }
void CCallback::buildBoat( const IShipyard *obj )
{
BuildBoat bb;
bb.objid = obj->o->id;
*cl->serv << &bb;
}
InfoAboutHero::InfoAboutHero() InfoAboutHero::InfoAboutHero()
{ {
details = NULL; details = NULL;

View File

@ -37,6 +37,7 @@ struct lua_State;
class CClient; class CClient;
struct TerrainTile; struct TerrainTile;
class CHeroClass; class CHeroClass;
class IShipyard;
struct InfoAboutHero struct InfoAboutHero
{ {
@ -102,6 +103,7 @@ public:
virtual void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero)=0; virtual void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero)=0;
virtual void save(const std::string &fname) = 0; virtual void save(const std::string &fname) = 0;
virtual void sendMessage(const std::string &mess) = 0; virtual void sendMessage(const std::string &mess) = 0;
virtual void buildBoat(const IShipyard *obj) = 0;
//get info //get info
virtual bool verifyPath(CPath * path, bool blockSea)const =0; virtual bool verifyPath(CPath * path, bool blockSea)const =0;
@ -196,6 +198,7 @@ public:
void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero); void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero);
void save(const std::string &fname); void save(const std::string &fname);
void sendMessage(const std::string &mess); void sendMessage(const std::string &mess);
void buildBoat(const IShipyard *obj);
//get info //get info
bool verifyPath(CPath * path, bool blockSea) const; bool verifyPath(CPath * path, bool blockSea) const;

View File

@ -31,6 +31,7 @@ class CGObjectInstance;
class CGDwelling; class CGDwelling;
class CCreatureSet; class CCreatureSet;
class CArmedInstance; class CArmedInstance;
class IShipyard;
struct BattleResult; struct BattleResult;
struct BattleAttack; struct BattleAttack;
struct BattleStackAttacked; struct BattleStackAttacked;
@ -83,12 +84,14 @@ public:
virtual void receivedResource(int type, int val){}; virtual void receivedResource(int type, int val){};
virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID){}; virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID){};
virtual void showRecruitmentDialog(const CGDwelling *dwelling, int level){} virtual void showRecruitmentDialog(const CGDwelling *dwelling, int level){}
virtual void showShipyardDialog(const IShipyard *obj){} //obj may be town or shipyard; state: 0 - can buid, 1 - lack of resources, 2 - dest tile is blocked, 3 - no water
//virtual void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){}; //virtual void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
//virtual void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){}; //virtual void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
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 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, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
virtual void tileHidden(const std::set<int3> &pos){}; virtual void tileHidden(const std::set<int3> &pos){};
virtual void tileRevealed(const std::set<int3> &pos){}; virtual void tileRevealed(const std::set<int3> &pos){};
virtual void newObject(const CGObjectInstance * obj){}; //eg. ship built in shipyard
virtual void yourTurn(){}; virtual void yourTurn(){};
virtual void availableCreaturesChanged(const CGTownInstance *town){}; virtual void availableCreaturesChanged(const CGTownInstance *town){};
virtual void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain){};//if gain hero received bonus, else he lost it virtual void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain){};//if gain hero received bonus, else he lost it

View File

@ -393,6 +393,7 @@ public:
CCastleInterface::CCastleInterface(const CGTownInstance * Town, int listPos) CCastleInterface::CCastleInterface(const CGTownInstance * Town, int listPos)
:hslotup(241,387,0,Town->garrisonHero,this),hslotdown(241,483,1,Town->visitingHero,this) :hslotup(241,387,0,Town->garrisonHero,this),hslotdown(241,483,1,Town->visitingHero,this)
{ {
showing = false;
bars = CDefHandler::giveDefEss("TPTHBAR.DEF"); bars = CDefHandler::giveDefEss("TPTHBAR.DEF");
status = CDefHandler::giveDefEss("TPTHCHK.DEF"); status = CDefHandler::giveDefEss("TPTHCHK.DEF");
LOCPLINT->castleInt = this; LOCPLINT->castleInt = this;
@ -579,7 +580,11 @@ void CCastleInterface::buildingClicked(int building)
break; break;
} }
//TODO: case 6: //shipyard case 6: //shipyard
{
LOCPLINT->showShipyardDialog(town);
break;
}
case 7: case 8: case 9: //fort/citadel/castle case 7: case 8: case 9: //fort/citadel/castle
{ {
CFortScreen *fs = new CFortScreen(this); CFortScreen *fs = new CFortScreen(this);
@ -622,7 +627,9 @@ void CCastleInterface::buildingClicked(int building)
//TODO: case 17: //special 1 //TODO: case 17: //special 1
//TODO: case 18: //basic horde 1 //TODO: case 18: //basic horde 1
//TODO: case 19: //upg horde 1 //TODO: case 19: //upg horde 1
//TODO: case 20: //ship at shipyard case 20: //ship at shipyard
//Do nothing.
break;
//TODO: case 21: //special 2 //TODO: case 21: //special 2
case 22: //special 3 case 22: //special 3
{ {
@ -886,6 +893,19 @@ void CCastleInterface::recreateBuildings()
else else
break; break;
} }
//ship in shipyard
if(vstd::contains(town->builtBuildings,6))
{
std::vector <const CGObjectInstance *> vobjs = LOCPLINT->cb->getVisitableObjs(town->bestLocation());
if(vobjs.size() && vobjs.front()->ID == 8) //there is visitable obj at shipyard output tile and it's a boat
{
Structure * st = CGI->townh->structures[town->subID][20];
buildings.push_back(new CBuildingRect(st));
s.insert(std::pair<int,int>(st->group,st->ID));
}
}
std::sort(buildings.begin(),buildings.end(),srthlp); std::sort(buildings.begin(),buildings.end(),srthlp);
//code for Mana Vortex (there are two sets of animation frames - one without mage guild and one with //code for Mana Vortex (there are two sets of animation frames - one without mage guild and one with
@ -934,6 +954,10 @@ void CCastleInterface::recreateBuildings()
shipyard->max = 1; shipyard->max = 1;
} }
} }
if(showing)
for(size_t i=0;i<buildings.size();i++)
buildings[i]->activate();
} }
CRecruitmentWindow * CCastleInterface::showRecruitmentWindow( int building ) CRecruitmentWindow * CCastleInterface::showRecruitmentWindow( int building )

View File

@ -1726,6 +1726,7 @@ const CGHeroInstance * CPlayerInterface::getWHero( int pos )
void CPlayerInterface::showRecruitmentDialog(const CGDwelling *dwelling, int level) void CPlayerInterface::showRecruitmentDialog(const CGDwelling *dwelling, int level)
{ {
waitWhileDialog(); waitWhileDialog();
boost::unique_lock<boost::recursive_mutex> un(*pim);
std::vector<std::pair<int,int> > cres; std::vector<std::pair<int,int> > cres;
for(int i = 0; i < dwelling->creatures.size(); i++) for(int i = 0; i < dwelling->creatures.size(); i++)
{ {
@ -1744,6 +1745,30 @@ void CPlayerInterface::waitWhileDialog()
showingDialog->cond.wait(un); showingDialog->cond.wait(un);
} }
void CPlayerInterface::showShipyardDialog(const IShipyard *obj)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
int state = obj->state();
std::vector<si32> cost;
obj->getBoatCost(cost);
CShipyardWindow *csw = new CShipyardWindow(cost, state, boost::bind(&CCallback::buildBoat, cb, obj));
pushInt(csw);
}
void CPlayerInterface::newObject( const CGObjectInstance * obj )
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
CGI->mh->printObject(obj);
//we might have built a boat in shipyard in opened town screen
if(obj->ID == 8
&& LOCPLINT->castleInt
&& obj->pos-obj->getVisitableOffset() == LOCPLINT->castleInt->town->bestLocation())
{
CGI->soundh->playSound(soundBase::newBuilding);
LOCPLINT->castleInt->recreateBuildings();
}
}
void SystemOptions::setMusicVolume( int newVolume ) void SystemOptions::setMusicVolume( int newVolume )
{ {
musicVolume = newVolume; musicVolume = newVolume;

View File

@ -163,10 +163,12 @@ public:
void receivedResource(int type, int val); void receivedResource(int type, int val);
void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID); void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID);
void showRecruitmentDialog(const CGDwelling *dwelling, int level); void showRecruitmentDialog(const CGDwelling *dwelling, int level);
void showShipyardDialog(const IShipyard *obj); //obj may be town or shipyard;
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel); //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. void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel); //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.
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd); void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd);
void tileHidden(const std::set<int3> &pos); //called when given tiles become hidden under fog of war 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 void tileRevealed(const std::set<int3> &pos); //called when fog of war disappears from given tiles
void newObject(const CGObjectInstance * obj);
void yourTurn(); void yourTurn();
void availableCreaturesChanged(const CGTownInstance *town); void availableCreaturesChanged(const CGTownInstance *town);
void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain);//if gain hero received bonus, else he lost it void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain);//if gain hero received bonus, else he lost it
@ -206,7 +208,7 @@ public:
void handleMouseMotion(SDL_Event *sEvent); void handleMouseMotion(SDL_Event *sEvent);
void init(ICallback * CB); void init(ICallback * CB);
int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
void showInfoDialog(const std::string &text, const std::vector<SComponent*> & components, int soundID); void showInfoDialog(const std::string &text, const std::vector<SComponent*> & components = std::vector<SComponent*>(), int soundID = 0);
void showYesNoDialog(const std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close void showYesNoDialog(const std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close
bool moveHero(const CGHeroInstance *h, CPath path); bool moveHero(const CGHeroInstance *h, CPath path);

View File

@ -3976,4 +3976,67 @@ CExchangeWindow::~CExchangeWindow() //d-tor
} }
} }
void CShipyardWindow::activate()
{
build->activate();
quit->activate();
}
void CShipyardWindow::deactivate()
{
build->deactivate();
quit->deactivate();
}
void CShipyardWindow::show( SDL_Surface * to )
{
blitAt(bg,pos,to);
CSDL_Ext::blit8bppAlphaTo24bpp(graphics->boatAnims[1]->ourImages[21 + frame++/8%8].bitmap, NULL, to, &genRect(64, 96, pos.x+110, pos.y+85));
build->show(to);
quit->show(to);
}
CShipyardWindow::~CShipyardWindow()
{
delete build;
delete quit;
}
CShipyardWindow::CShipyardWindow(const std::vector<si32> &cost, int state, const boost::function<void()> &onBuy)
{
frame = 0;
SDL_Surface * bgtemp; //loaded as 8bpp surface
bgtemp = BitmapHandler::loadBitmap("TPSHIP.bmp");
pos.x = screen->w/2 - bgtemp->w/2;
pos.y = screen->h/2 - bgtemp->h/2;
pos.w = bgtemp->w;
pos.h = bgtemp->h;
SDL_SetColorKey(bgtemp,SDL_SRCCOLORKEY,SDL_MapRGB(bgtemp->format,0,255,255));
graphics->blueToPlayersAdv(bgtemp, LOCPLINT->playerID);
bg = SDL_ConvertSurface(bgtemp, screen->format, screen->flags); //to 24 bpp
SDL_FreeSurface(bgtemp);
bgtemp = BitmapHandler::loadBitmap("TPSHIPBK.bmp");
blitAt(bgtemp, 100, 69, bg);
SDL_FreeSurface(bgtemp);
bool affordable = true;
for(int i = 0; i < cost.size(); i++)
{
if(cost[i] > LOCPLINT->cb->getResourceAmount(i))
{
affordable = false;
break;
}
}
quit = new AdventureMapButton(CGI->generaltexth->allTexts[599], "", boost::bind(&CPlayerInterface::popIntTotally, LOCPLINT, this), pos.x+224, pos.y+312, "ICANCEL.DEF", SDLK_RETURN);
build = new AdventureMapButton(CGI->generaltexth->allTexts[598], "", boost::bind(&CPlayerInterface::popIntTotally, LOCPLINT, this), pos.x+42, pos.y+312, "IBY6432.DEF", SDLK_RETURN);
build->callback += onBuy;
if(!affordable)
build->block(true);
printAtMiddle(CGI->generaltexth->jktexts[15], 165, 26, GEOR13, zwykly, bg); //Resource cost:
printAtMiddle(CGI->generaltexth->jktexts[14], 165, 218, GEOR16, tytulowy, bg); //Build A New Ship
}

View File

@ -700,5 +700,20 @@ public:
~CExchangeWindow(); //d-tor ~CExchangeWindow(); //d-tor
}; };
class CShipyardWindow : public CIntObject, public IShowActivable
{
public:
CStatusBar *bar;
SDL_Surface *bg; //background
AdventureMapButton *build, *quit;
unsigned char frame; //frame of the boat animation
void activate();
void deactivate();
void show(SDL_Surface * to);
CShipyardWindow(const std::vector<si32> &cost, int state, const boost::function<void()> &onBuy);
~CShipyardWindow();
};
#endif //__GUICLASSES_H__ #endif //__GUICLASSES_H__

View File

@ -16,6 +16,7 @@
#include "../lib/VCMI_Lib.h" #include "../lib/VCMI_Lib.h"
#include "../CCallback.h" #include "../CCallback.h"
#include "../hch/CTownHandler.h" #include "../hch/CTownHandler.h"
#include "../hch/CDefObjInfoHandler.h"
using namespace boost::assign; using namespace boost::assign;
using namespace CSDL_Ext; using namespace CSDL_Ext;
#ifdef min #ifdef min
@ -360,6 +361,9 @@ void Graphics::loadHeroAnims()
loadHeroAnim("AB01_.DEF", rotations, &Graphics::boatAnims); loadHeroAnim("AB01_.DEF", rotations, &Graphics::boatAnims);
loadHeroAnim("AB02_.DEF", rotations, &Graphics::boatAnims); loadHeroAnim("AB02_.DEF", rotations, &Graphics::boatAnims);
loadHeroAnim("AB03_.DEF", rotations, &Graphics::boatAnims); loadHeroAnim("AB03_.DEF", rotations, &Graphics::boatAnims);
VLC->dobjinfo->gobjs[8][0]->handler = boatAnims[0];
VLC->dobjinfo->gobjs[8][1]->handler = boatAnims[1];
VLC->dobjinfo->gobjs[8][2]->handler = boatAnims[2];
} }
void Graphics::loadHeroAnim( const std::string &name, const std::vector<std::pair<int,int> > &rotations, std::vector<CDefEssential *> Graphics::*dst ) void Graphics::loadHeroAnim( const std::string &name, const std::vector<std::pair<int,int> > &rotations, std::vector<CDefEssential *> Graphics::*dst )

View File

@ -488,6 +488,28 @@ void OpenWindow::applyCl(CClient *cl)
const CGDwelling *dw = dynamic_cast<const CGDwelling*>(cl->getObj(id1)); const CGDwelling *dw = dynamic_cast<const CGDwelling*>(cl->getObj(id1));
INTERFACE_CALL_IF_PRESENT(dw->tempOwner,showRecruitmentDialog, dw, 0); INTERFACE_CALL_IF_PRESENT(dw->tempOwner,showRecruitmentDialog, dw, 0);
} }
break;
case SHIPYARD_WINDOW:
{
const IShipyard *sy = IShipyard::castFrom(cl->getObj(id1));
INTERFACE_CALL_IF_PRESENT(sy->o->tempOwner, showShipyardDialog, sy);
}
break;
} }
} }
void NewObject::applyCl(CClient *cl)
{
const CGObjectInstance *obj = cl->getObj(id);
//notify interfaces about move
for(std::map<ui8, CGameInterface*>::iterator i=cl->playerint.begin();i!=cl->playerint.end();i++)
{
//TODO: check if any covered tile is visible
if(i->first >= PLAYER_LIMIT) continue;
if(GS(cl)->players[i->first].fogOfWarMap[obj->pos.x][obj->pos.y][obj->pos.z])
{
i->second->newObject(obj);
}
}
}

View File

@ -9,6 +9,7 @@
#include "CSpellHandler.h" #include "CSpellHandler.h"
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include <boost/assign/std/vector.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/random/linear_congruential.hpp> #include <boost/random/linear_congruential.hpp>
#include "CTownHandler.h" #include "CTownHandler.h"
@ -20,6 +21,7 @@
#include "../lib/NetPacks.h" #include "../lib/NetPacks.h"
#include "../StartInfo.h" #include "../StartInfo.h"
#include "../lib/map.h" #include "../lib/map.h"
using namespace boost::assign;
/* /*
* CObjectHandler.cpp, part of VCMI engine * CObjectHandler.cpp, part of VCMI engine
@ -291,6 +293,10 @@ void CGObjectInstance::giveDummyBonus(int heroID, ui8 duration) const
cb->giveHeroBonus(&gbonus); cb->giveHeroBonus(&gbonus);
} }
void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const
{
}
static int lowestSpeed(const CGHeroInstance * chi) static int lowestSpeed(const CGHeroInstance * chi)
{ {
if(!chi->army.slots.size()) if(!chi->army.slots.size())
@ -1222,6 +1228,7 @@ bool CGTownInstance::hasCapitol() const
return (builtBuildings.find(13))!=builtBuildings.end(); return (builtBuildings.find(13))!=builtBuildings.end();
} }
CGTownInstance::CGTownInstance() CGTownInstance::CGTownInstance()
:IShipyard(this)
{ {
builded=-1; builded=-1;
destroyed=-1; destroyed=-1;
@ -1283,6 +1290,11 @@ int3 CGTownInstance::getSightCenter() const
return pos - int3(2,0,0); return pos - int3(2,0,0);
} }
void CGTownInstance::getOutOffsets( std::vector<int3> &offsets ) const
{
offsets += int3(-1,3,0), int3(-3,3,0);
}
void CGVisitableOPH::onHeroVisit( const CGHeroInstance * h ) const void CGVisitableOPH::onHeroVisit( const CGHeroInstance * h ) const
{ {
if(visitors.find(h->id)==visitors.end()) if(visitors.find(h->id)==visitors.end())
@ -2498,6 +2510,7 @@ void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
{ {
case 11: //buoy case 11: //buoy
messageID = 21; messageID = 21;
sound = soundBase::MORALE;
gbonus.bonus.type = HeroBonus::MORALE; gbonus.bonus.type = HeroBonus::MORALE;
gbonus.bonus.val = +1; gbonus.bonus.val = +1;
gbonus.bdescr << std::pair<ui8,ui32>(6,94); gbonus.bdescr << std::pair<ui8,ui32>(6,94);
@ -3412,4 +3425,122 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
} }
} }
cb->showInfoDialog(&iw); cb->showInfoDialog(&iw);
}
void IShipyard::getBoatCost( std::vector<si32> &cost ) const
{
cost.resize(RESOURCE_QUANTITY);
cost[0] = 10;
cost[6] = 1000;
}
//bool IShipyard::validLocation() const
//{
// std::vector<int3> offsets;
// getOutOffsets(offsets);
//
// TerrainTile *tile;
// for(int i = 0; i < offsets.size(); i++)
// if((tile = IObjectInterface::cb->getTile(o->pos + offsets[i])) && tile->tertype == TerrainTile::water) //tile is in the map and is water
// return true;
// return false;
//}
int3 IShipyard::bestLocation() const
{
std::vector<int3> offsets;
getOutOffsets(offsets);
TerrainTile *tile;
for(int i = 0; i < offsets.size(); i++)
if((tile = IObjectInterface::cb->getTile(o->pos + offsets[i])) && tile->tertype == TerrainTile::water) //tile is in the map and is water
return o->pos + offsets[i];
return int3(-1,-1,-1);
}
IShipyard::IShipyard(const CGObjectInstance *O)
: o(O)
{
}
int IShipyard::state() const
{
int3 tile = bestLocation();
TerrainTile *t = IObjectInterface::cb->getTile(tile);
if(!t)
return 3; //no water
else if(!t->blockingObjects.size())
return 0; //OK
else if(t->blockingObjects.front()->ID == 8)
return 1; //blocked with boat
else
return 2; //blocked
}
IShipyard * IShipyard::castFrom( CGObjectInstance *obj )
{
if(obj->ID == TOWNI_TYPE)
{
return static_cast<CGTownInstance*>(obj);
}
else if(obj->ID == 87)
{
return static_cast<CGShipyard*>(obj);
}
else
{
tlog1 << "Cannot cast to IShipyar object with ID " << obj->ID << std::endl;
return NULL;
}
}
const IShipyard * IShipyard::castFrom( const CGObjectInstance *obj )
{
return castFrom(const_cast<CGObjectInstance*>(obj));
}
CGShipyard::CGShipyard()
:IShipyard(this)
{
}
void CGShipyard::getOutOffsets( std::vector<int3> &offsets ) const
{
offsets += int3(1,0,0), int3(-3,0,0), int3(1,1,0), int3(-3,1,0), int3(1,-1,0), int3(-3,-1,0),
int3(-2,-1,0), int3(0,-1,0), int3(-1,-1,0), int3(-2,1,0), int3(0,1,0), int3(-1,1,0);
}
void CGShipyard::onHeroVisit( const CGHeroInstance * h ) const
{
if(tempOwner != h->tempOwner)
cb->setOwner(id, h->tempOwner);
int s = state();
if(s)
{
InfoWindow iw;
iw.player = tempOwner;
switch(s)
{
case 1:
iw.text.addTxt(MetaString::GENERAL_TXT, 51);
break;
case 2:
iw.text.addTxt(MetaString::ADVOB_TXT, 189);
break;
case 3:
tlog1 << "Shipyard without water!!! " << pos << "\t" << id << std::endl;
return;
}
cb->showInfoDialog(&iw);
}
else
{
OpenWindow ow;
ow.id1 = id;
ow.id2 = h->id;
ow.window = OpenWindow::SHIPYARD_WINDOW;
cb->sendAndApply(&ow);
}
} }

View File

@ -104,6 +104,22 @@ public:
virtual void setProperty(ui8 what, ui32 val);//synchr virtual void setProperty(ui8 what, ui32 val);//synchr
}; };
class DLL_EXPORT IShipyard
{
public:
const CGObjectInstance *o;
IShipyard(const CGObjectInstance *O);
void getBoatCost(std::vector<si32> &cost) const;
virtual void getOutOffsets(std::vector<int3> &offsets) const =0; //offsets to obj pos when we boat can be placed
//virtual bool validLocation() const; //returns true if there is a water tile near where boat can be placed
int3 bestLocation() const; //returns location when the boat should be placed
int state() const; //0 - can buid, 1 - there is already a boat at dest tile, 2 - dest tile is blocked, 3 - no water
static const IShipyard *castFrom(const CGObjectInstance *obj);
static IShipyard *castFrom(CGObjectInstance *obj);
};
class DLL_EXPORT CGObjectInstance : protected IObjectInterface class DLL_EXPORT CGObjectInstance : protected IObjectInterface
{ {
protected: protected:
@ -139,6 +155,7 @@ public:
virtual const std::string & getHoverText() const; virtual const std::string & getHoverText() const;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void initObj(); void initObj();
void onHeroVisit(const CGHeroInstance * h) const;
void setProperty(ui8 what, ui32 val);//synchr void setProperty(ui8 what, ui32 val);//synchr
virtual void setPropertyDer(ui8 what, ui32 val);//synchr virtual void setPropertyDer(ui8 what, ui32 val);//synchr
@ -309,7 +326,7 @@ public:
void wantsFight(const CGHeroInstance *h, ui32 answer) const; void wantsFight(const CGHeroInstance *h, ui32 answer) const;
}; };
class DLL_EXPORT CGTownInstance : public CGDwelling class DLL_EXPORT CGTownInstance : public CGDwelling, public IShipyard
{ {
public: public:
CTown * town; CTown * town;
@ -357,6 +374,7 @@ public:
int3 getSightCenter() const; //"center" tile from which the sight distance is calculated int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
int getSightRadious() const; //returns sight distance int getSightRadious() const; //returns sight distance
void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -777,7 +795,13 @@ public:
} }
}; };
class CGShipyard : public CGObjectInstance, public IShipyard
{
public:
void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed
CGShipyard();
void onHeroVisit(const CGHeroInstance * h) const;
};
class DLL_EXPORT CObjectHandler class DLL_EXPORT CObjectHandler
{ {

View File

@ -145,3 +145,10 @@ void IGameCallback::getAllowed(std::vector<CArtifact*> &out, int flags)
if(flags & CArtifact::ART_RELIC) if(flags & CArtifact::ART_RELIC)
getAllowedArts(out,&CArtHandler::relics); getAllowedArts(out,&CArtHandler::relics);
} }
TerrainTile * IGameCallback::getTile( int3 pos )
{
if(!gs->map->isInTheMap(pos))
return NULL;
return &gs->map->getTile(pos);
}

View File

@ -32,6 +32,7 @@ struct CPackForClient;
class CArtHandler; class CArtHandler;
class CArtifact; class CArtifact;
class CArmedInstance; class CArmedInstance;
struct TerrainTile;
class DLL_EXPORT IGameCallback class DLL_EXPORT IGameCallback
{ {
@ -55,6 +56,7 @@ public:
virtual bool isAllowed(int type, int id); //type: 0 - spell; 1- artifact virtual bool isAllowed(int type, int id); //type: 0 - spell; 1- artifact
virtual void getAllowedArts(std::vector<CArtifact*> &out, std::vector<CArtifact*> CArtHandler::*arts); virtual void getAllowedArts(std::vector<CArtifact*> &out, std::vector<CArtifact*> CArtHandler::*arts);
virtual void getAllowed(std::vector<CArtifact*> &out, int flags); //flags: bitfield uses EartClass virtual void getAllowed(std::vector<CArtifact*> &out, int flags); //flags: bitfield uses EartClass
virtual TerrainTile * getTile(int3 pos);
//do sth //do sth
virtual void changeSpells(int hid, bool give, const std::set<ui32> &spells)=0; virtual void changeSpells(int hid, bool give, const std::set<ui32> &spells)=0;

View File

@ -518,7 +518,7 @@ struct OpenWindow : public CPackForClient //517
OpenWindow(){type = 517;}; OpenWindow(){type = 517;};
void applyCl(CClient *cl); void applyCl(CClient *cl);
enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL}; enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL, SHIPYARD_WINDOW};
ui8 window; ui8 window;
ui32 id1, id2; ui32 id1, id2;
@ -528,6 +528,23 @@ struct OpenWindow : public CPackForClient //517
} }
}; };
struct NewObject : public CPackForClient //518
{
NewObject(){type = 518;};
void applyCl(CClient *cl);
DLL_EXPORT void applyGs(CGameState *gs);
ui32 ID, subID;
int3 pos;
int id; //used internally
template <typename Handler> void serialize(Handler &h, const int version)
{
h & ID & subID & pos;
}
};
struct NewTurn : public CPackForClient //101 struct NewTurn : public CPackForClient //101
{ {
DLL_EXPORT void applyGs(CGameState *gs); DLL_EXPORT void applyGs(CGameState *gs);
@ -1118,6 +1135,19 @@ struct HireHero : public CPackForServer
} }
}; };
struct BuildBoat : public CPackForServer
{
BuildBoat(){};
si32 objid; //where player wants to buy a boat
bool applyGh(CGameHandler *gh);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & objid;
}
};
struct QueryReply : public CPackForServer struct QueryReply : public CPackForServer
{ {
QueryReply(){}; QueryReply(){};

View File

@ -490,6 +490,32 @@ DLL_EXPORT void GiveHero::applyGs( CGameState *gs )
h->inTownGarrison = false; h->inTownGarrison = false;
} }
DLL_EXPORT void NewObject::applyGs( CGameState *gs )
{
CGObjectInstance *o = NULL;
switch(ID)
{
case 8:
o = new CGBoat();
break;
default:
o = new CGObjectInstance();
break;
}
o->ID = ID;
o->subID = subID;
o->pos = pos;
o->defInfo = VLC->dobjinfo->gobjs[ID][subID];
id = o->id = gs->map->objects.size();
o->hoverName = VLC->generaltexth->names[ID];
gs->map->objects.push_back(o);
gs->map->addBlockVisTiles(o);
o->initObj();
assert(o->defInfo);
}
DLL_EXPORT void NewTurn::applyGs( CGameState *gs ) DLL_EXPORT void NewTurn::applyGs( CGameState *gs )
{ {
gs->day = day; gs->day = day;

View File

@ -45,6 +45,7 @@ void registerTypes1(Serializer &s)
s.template registerType<CGBoat>(); s.template registerType<CGBoat>();
s.template registerType<CGSirens>(); s.template registerType<CGSirens>();
s.template registerType<CGOnceVisitable>(); s.template registerType<CGOnceVisitable>();
s.template registerType<CGShipyard>();
s.template registerType<CGObjectInstance>(); s.template registerType<CGObjectInstance>();
} }
@ -96,6 +97,7 @@ void registerTypes2(Serializer &s)
s.template registerType<StacksInjured>(); s.template registerType<StacksInjured>();
s.template registerType<ShowInInfobox>(); s.template registerType<ShowInInfobox>();
s.template registerType<OpenWindow>(); s.template registerType<OpenWindow>();
s.template registerType<NewObject>();
s.template registerType<SaveGame>(); s.template registerType<SaveGame>();
s.template registerType<SetSelection>(); s.template registerType<SetSelection>();
@ -120,6 +122,7 @@ void registerTypes3(Serializer &s)
s.template registerType<TradeOnMarketplace>(); s.template registerType<TradeOnMarketplace>();
s.template registerType<SetFormation>(); s.template registerType<SetFormation>();
s.template registerType<HireHero>(); s.template registerType<HireHero>();
s.template registerType<BuildBoat>();
s.template registerType<QueryReply>(); s.template registerType<QueryReply>();
s.template registerType<MakeAction>(); s.template registerType<MakeAction>();
s.template registerType<MakeCustomAction>(); s.template registerType<MakeCustomAction>();

View File

@ -1688,7 +1688,6 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
break; break;
} }
case 42: //lighthouse case 42: //lighthouse
case 87: //shipyard
case 220://mine (?) case 220://mine (?)
{ {
nobj = new CGObjectInstance(); nobj = new CGObjectInstance();
@ -1881,6 +1880,12 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
nobj = new CGSirens(); nobj = new CGSirens();
break; break;
} }
case 87: //Shipyard
{
nobj = new CGShipyard();
nobj->setOwner(readNormalNr(bufor,i)); i+=4;
break;
}
case 214: //hero placeholder case 214: //hero placeholder
{ {
i+=3; //TODO: handle it more properly i+=3; //TODO: handle it more properly
@ -1945,7 +1950,7 @@ void Mapa::readEvents( unsigned char * bufor, int &i )
} }
} }
bool Mapa::isInTheMap( int3 pos ) bool Mapa::isInTheMap( int3 pos ) const
{ {
if(pos.x<0 || pos.y<0 || pos.z<0 || pos.x >= width || pos.y >= height || pos.z > twoLevel) if(pos.x<0 || pos.y<0 || pos.z<0 || pos.x >= width || pos.y >= height || pos.z > twoLevel)
return false; return false;
@ -2034,6 +2039,17 @@ TerrainTile & Mapa::getTile( int3 tile )
{ {
return terrain[tile.x][tile.y][tile.z]; return terrain[tile.x][tile.y][tile.z];
} }
const TerrainTile & Mapa::getTile( int3 tile ) const
{
return terrain[tile.x][tile.y][tile.z];
}
bool Mapa::isWaterTile( int3 pos ) const
{
return isInTheMap(pos) && getTile(pos).tertype == TerrainTile::water;
}
void CMapInfo::countPlayers() void CMapInfo::countPlayers()
{ {
playerAmnt=humenPlayers=0; playerAmnt=humenPlayers=0;

View File

@ -335,8 +335,10 @@ struct DLL_EXPORT Mapa : public CMapHeader
Mapa(); Mapa();
~Mapa(); ~Mapa();
TerrainTile &getTile(int3 tile); TerrainTile &getTile(int3 tile);
const TerrainTile &getTile(int3 tile) const;
CGHeroInstance * getHero(int ID, int mode=0); CGHeroInstance * getHero(int ID, int mode=0);
bool isInTheMap(int3 pos); bool isInTheMap(int3 pos) const;
bool isWaterTile(int3 pos) const; //out-of-pos safe
template <typename Handler> void serialize(Handler &h, const int formatVersion) template <typename Handler> void serialize(Handler &h, const int formatVersion)
{ {
h & static_cast<CMapHeader&>(*this); h & static_cast<CMapHeader&>(*this);

View File

@ -720,13 +720,13 @@ void CMapHandler::terrainRect(int3 top_tile, unsigned char anim, std::vector< st
for(int h=0; h < objects.size(); ++h) for(int h=0; h < objects.size(); ++h)
{ {
const CGObjectInstance *obj = objects[h].first;
ui8 color = obj->tempOwner;
//checking if object has non-empty graphic on this tile //checking if object has non-empty graphic on this tile
if(!objects[h].first->coveringAt(objects[h].first->pos.x - (top_tile.x + bx), top_tile.y + by - objects[h].first->pos.y + 5)) if(!obj->coveringAt(obj->pos.x - (top_tile.x + bx), top_tile.y + by - obj->pos.y + 5))
continue; continue;
//printing object
SDL_Rect sr; SDL_Rect sr;
sr.x = srx; sr.x = srx;
sr.y = sry; sr.y = sry;
sr.w = sr.h = 32; sr.w = sr.h = 32;
@ -735,73 +735,87 @@ void CMapHandler::terrainRect(int3 top_tile, unsigned char anim, std::vector< st
pp.h = sr.h; pp.h = sr.h;
pp.w = sr.w; pp.w = sr.w;
const CGHeroInstance * themp = (objects[h].first->ID != HEROI_TYPE const CGHeroInstance * themp = (obj->ID != HEROI_TYPE
? NULL ? NULL
: static_cast<const CGHeroInstance*>(objects[h].first)); : static_cast<const CGHeroInstance*>(obj));
if(themp && themp->moveDir) //it's hero //print hero / boat and flag
if(themp && themp->moveDir && themp->type || obj->ID == 8) //it's hero or boat
{ {
int imgVal = 8; const int IMGVAL = 8; //frames per group of movement animation
SDL_Surface * tb; ui8 dir;
if(themp->type==NULL) std::vector<Cimage> * iv = NULL;
continue;
//pick graphics of hero (or boat if hero is sailing)
std::vector<Cimage> & iv = (themp->boat)
? graphics->boatAnims[themp->boat->subID]->ourImages
: graphics->heroAnims[themp->type->heroType]->ourImages;
//pick appropriate flag set
std::vector<CDefEssential *> Graphics::*flg = NULL; std::vector<CDefEssential *> Graphics::*flg = NULL;
if(themp->boat) SDL_Surface * tb; //surface to blitted
if(themp) //hero
{ {
switch (themp->boat->subID) dir = themp->moveDir;
//pick graphics of hero (or boat if hero is sailing)
iv = (themp->boat)
? &graphics->boatAnims[themp->boat->subID]->ourImages
: &graphics->heroAnims[themp->type->heroType]->ourImages;
//pick appropriate flag set
if(themp->boat)
{ {
case 0: flg = &Graphics::flags1; break; switch (themp->boat->subID)
case 1: flg = &Graphics::flags2; break; {
case 2: flg = &Graphics::flags3; break; case 0: flg = &Graphics::flags1; break;
default: tlog1 << "Not supported boat subtype: " << themp->boat->subID << std::endl; case 1: flg = &Graphics::flags2; break;
case 2: flg = &Graphics::flags3; break;
default: tlog1 << "Not supported boat subtype: " << themp->boat->subID << std::endl;
}
}
else
{
flg = &Graphics::flags4;
} }
} }
else else //boat
{ {
flg = &Graphics::flags4; const CGBoat *boat = static_cast<const CGBoat*>(obj);
dir = boat->direction;
iv = &graphics->boatAnims[boat->subID]->ourImages;
} }
//print hero / boat and flag
if(!themp->isStanding) //hero is moving if(themp && !themp->isStanding) //hero is moving
{ {
size_t gg; size_t gg;
for(gg=0; gg<iv.size(); ++gg) for(gg=0; gg<iv->size(); ++gg)
{ {
if(iv[gg].groupNumber==getHeroFrameNum(themp->moveDir, !themp->isStanding)) if((*iv)[gg].groupNumber==getHeroFrameNum(dir, true))
{ {
tb = iv[gg+heroAnim%imgVal].bitmap; tb = (*iv)[gg+heroAnim%IMGVAL].bitmap;
break; break;
} }
} }
CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr); CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr);
//printing flag //printing flag
pp.y+=imgVal*2-32; pp.y+=IMGVAL*2-32;
sr.y-=16; sr.y-=16;
SDL_BlitSurface((graphics->*flg)[themp->getOwner()]->ourImages[gg+heroAnim%imgVal+35].bitmap, &pp, extSurf, &sr); SDL_BlitSurface((graphics->*flg)[color]->ourImages[gg+heroAnim%IMGVAL+35].bitmap, &pp, extSurf, &sr);
} }
else //hero stands still else //hero / boat stands still
{ {
size_t gg; size_t gg;
for(gg=0; gg < iv.size(); ++gg) for(gg=0; gg < iv->size(); ++gg)
{ {
if(iv[gg].groupNumber==getHeroFrameNum(themp->moveDir, !themp->isStanding)) if((*iv)[gg].groupNumber==getHeroFrameNum(dir, false))
{ {
tb = iv[gg].bitmap; tb = (*iv)[gg].bitmap;
break; break;
} }
} }
CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr); CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr);
//printing flag //printing flag
if(themp->pos.x==top_tile.x+bx && themp->pos.y==top_tile.y+by) if(flg
&& obj->pos.x == top_tile.x + bx
&& obj->pos.y == top_tile.y + by)
{ {
SDL_Rect bufr = sr; SDL_Rect bufr = sr;
bufr.x-=2*32; bufr.x-=2*32;
@ -809,19 +823,18 @@ void CMapHandler::terrainRect(int3 top_tile, unsigned char anim, std::vector< st
bufr.h = 64; bufr.h = 64;
bufr.w = 96; bufr.w = 96;
if(bufr.x-extRect->x>-64) if(bufr.x-extRect->x>-64)
SDL_BlitSurface((graphics->*flg)[themp->getOwner()]->ourImages[ getHeroFrameNum(themp->moveDir, !themp->isStanding) *8+(heroAnim/4)%imgVal].bitmap, NULL, extSurf, &bufr); SDL_BlitSurface((graphics->*flg)[color]->ourImages[getHeroFrameNum(dir, false) *8+(heroAnim/4)%IMGVAL].bitmap, NULL, extSurf, &bufr);
} }
} }
} }
else //blit object else //blit normal object
{ {
const CGObjectInstance *obj = objects[h].first;
const std::vector<Cimage> &ourImages = obj->defInfo->handler->ourImages; const std::vector<Cimage> &ourImages = obj->defInfo->handler->ourImages;
SDL_Surface *bitmap = ourImages[(anim+obj->animPhaseShift)%ourImages.size()].bitmap; SDL_Surface *bitmap = ourImages[(anim+obj->animPhaseShift)%ourImages.size()].bitmap;
//setting appropriate flag color //setting appropriate flag color
if(obj->tempOwner<8 || obj->tempOwner==255) if(color < 8 || color==255)
CSDL_Ext::setPlayerColor(bitmap, obj->tempOwner); CSDL_Ext::setPlayerColor(bitmap, color);
CSDL_Ext::blit8bppAlphaTo24bpp(bitmap,&pp,extSurf,&sr); CSDL_Ext::blit8bppAlphaTo24bpp(bitmap,&pp,extSurf,&sr);
} }

View File

@ -662,7 +662,7 @@ void CGameHandler::newTurn()
{ {
NewTurn::Hero hth; NewTurn::Hero hth;
hth.id = h->id; hth.id = h->id;
hth.move = h->maxMovePoints(true); //TODO: check if hero is really on the land hth.move = h->maxMovePoints(gs->map->getTile(h->getPosition(false)).tertype != TerrainTile::water);
if(h->visitedTown && vstd::contains(h->visitedTown->builtBuildings,0)) //if hero starts turn in town with mage guild if(h->visitedTown && vstd::contains(h->visitedTown->builtBuildings,0)) //if hero starts turn in town with mage guild
hth.mana = h->manaLimit(); //restore all mana hth.mana = h->manaLimit(); //restore all mana
@ -2872,3 +2872,49 @@ void CGameHandler::objectVisited( const CGObjectInstance * obj, const CGHeroInst
{ {
obj->onHeroVisit(h); obj->onHeroVisit(h);
} }
bool CGameHandler::buildBoat( ui32 objid )
{
const IShipyard *obj = IShipyard::castFrom(getObj(objid));
if(obj->state())
{
complain("Cannot build boat in this shipyard!");
return false;
}
else if(obj->o->ID == TOWNI_TYPE
&& !vstd::contains((static_cast<const CGTownInstance*>(obj))->builtBuildings,6))
{
complain("Cannot build boat in the town - no shipyard!");
return false;
}
//TODO use "real" cost via obj->getBoatCost
if(getResource(obj->o->tempOwner, 6) < 1000 || getResource(obj->o->tempOwner, 0) < 10)
{
complain("Not enough resources to build a boat!");
return false;
}
int3 tile = obj->bestLocation();
if(!gs->map->isInTheMap(tile))
{
complain("Cannot find appropriate tile for a boat!");
return false;
}
//take boat cost
SetResources sr;
sr.player = obj->o->tempOwner;
sr.res = gs->getPlayer(obj->o->tempOwner)->resources;
sr.res[0] -= 10;
sr.res[6] -= 1000;
sendAndApply(&sr);
//create boat
NewObject no;
no.ID = 8;
no.subID = 1;
no.pos = tile + int3(1,0,0);
sendAndApply(&no);
}

View File

@ -144,6 +144,7 @@ public:
bool makeCustomAction(BattleAction &ba); bool makeCustomAction(BattleAction &ba);
bool queryReply( ui32 qid, ui32 answer ); bool queryReply( ui32 qid, ui32 answer );
bool hireHero( ui32 tid, ui8 hid ); bool hireHero( ui32 tid, ui8 hid );
bool buildBoat( ui32 objid );
bool setFormation( si32 hid, ui8 formation ); bool setFormation( si32 hid, ui8 formation );
bool tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 ); bool tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 );
bool buyArtifact( ui32 hid, si32 aid ); bool buyArtifact( ui32 hid, si32 aid );

View File

@ -122,6 +122,12 @@ bool HireHero::applyGh( CGameHandler *gh )
return gh->hireHero(tid,hid); return gh->hireHero(tid,hid);
} }
bool BuildBoat::applyGh( CGameHandler *gh )
{
ERROR_IF_NOT_OWNS(objid);
return gh->buildBoat(objid);
}
bool QueryReply::applyGh( CGameHandler *gh ) bool QueryReply::applyGh( CGameHandler *gh )
{ {
//TODO - check if player matches the query //TODO - check if player matches the query