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;
}
void CCallback::buildBoat( const IShipyard *obj )
{
BuildBoat bb;
bb.objid = obj->o->id;
*cl->serv << &bb;
}
InfoAboutHero::InfoAboutHero()
{
details = NULL;

View File

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

View File

@ -31,6 +31,7 @@ class CGObjectInstance;
class CGDwelling;
class CCreatureSet;
class CArmedInstance;
class IShipyard;
struct BattleResult;
struct BattleAttack;
struct BattleStackAttacked;
@ -83,12 +84,14 @@ public:
virtual void receivedResource(int type, int val){};
virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID){};
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 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 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 tileRevealed(const std::set<int3> &pos){};
virtual void newObject(const CGObjectInstance * obj){}; //eg. ship built in shipyard
virtual void yourTurn(){};
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

View File

@ -393,6 +393,7 @@ public:
CCastleInterface::CCastleInterface(const CGTownInstance * Town, int listPos)
:hslotup(241,387,0,Town->garrisonHero,this),hslotdown(241,483,1,Town->visitingHero,this)
{
showing = false;
bars = CDefHandler::giveDefEss("TPTHBAR.DEF");
status = CDefHandler::giveDefEss("TPTHCHK.DEF");
LOCPLINT->castleInt = this;
@ -579,7 +580,11 @@ void CCastleInterface::buildingClicked(int building)
break;
}
//TODO: case 6: //shipyard
case 6: //shipyard
{
LOCPLINT->showShipyardDialog(town);
break;
}
case 7: case 8: case 9: //fort/citadel/castle
{
CFortScreen *fs = new CFortScreen(this);
@ -622,7 +627,9 @@ void CCastleInterface::buildingClicked(int building)
//TODO: case 17: //special 1
//TODO: case 18: //basic 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
case 22: //special 3
{
@ -886,6 +893,19 @@ void CCastleInterface::recreateBuildings()
else
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);
//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;
}
}
if(showing)
for(size_t i=0;i<buildings.size();i++)
buildings[i]->activate();
}
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)
{
waitWhileDialog();
boost::unique_lock<boost::recursive_mutex> un(*pim);
std::vector<std::pair<int,int> > cres;
for(int i = 0; i < dwelling->creatures.size(); i++)
{
@ -1744,6 +1745,30 @@ void CPlayerInterface::waitWhileDialog()
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 )
{
musicVolume = newVolume;

View File

@ -163,10 +163,12 @@ public:
void receivedResource(int type, int val);
void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID);
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 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 tileRevealed(const std::set<int3> &pos); //called when fog of war disappears from given tiles
void newObject(const CGObjectInstance * obj);
void yourTurn();
void availableCreaturesChanged(const CGTownInstance *town);
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 init(ICallback * CB);
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
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
};
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__

View File

@ -16,6 +16,7 @@
#include "../lib/VCMI_Lib.h"
#include "../CCallback.h"
#include "../hch/CTownHandler.h"
#include "../hch/CDefObjInfoHandler.h"
using namespace boost::assign;
using namespace CSDL_Ext;
#ifdef min
@ -360,6 +361,9 @@ void Graphics::loadHeroAnims()
loadHeroAnim("AB01_.DEF", rotations, &Graphics::boatAnims);
loadHeroAnim("AB02_.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 )

View File

@ -488,6 +488,28 @@ void OpenWindow::applyCl(CClient *cl)
const CGDwelling *dw = dynamic_cast<const CGDwelling*>(cl->getObj(id1));
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 <boost/bind.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/assign/std/vector.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/random/linear_congruential.hpp>
#include "CTownHandler.h"
@ -20,6 +21,7 @@
#include "../lib/NetPacks.h"
#include "../StartInfo.h"
#include "../lib/map.h"
using namespace boost::assign;
/*
* CObjectHandler.cpp, part of VCMI engine
@ -291,6 +293,10 @@ void CGObjectInstance::giveDummyBonus(int heroID, ui8 duration) const
cb->giveHeroBonus(&gbonus);
}
void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const
{
}
static int lowestSpeed(const CGHeroInstance * chi)
{
if(!chi->army.slots.size())
@ -1222,6 +1228,7 @@ bool CGTownInstance::hasCapitol() const
return (builtBuildings.find(13))!=builtBuildings.end();
}
CGTownInstance::CGTownInstance()
:IShipyard(this)
{
builded=-1;
destroyed=-1;
@ -1283,6 +1290,11 @@ int3 CGTownInstance::getSightCenter() const
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
{
if(visitors.find(h->id)==visitors.end())
@ -2498,6 +2510,7 @@ void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
{
case 11: //buoy
messageID = 21;
sound = soundBase::MORALE;
gbonus.bonus.type = HeroBonus::MORALE;
gbonus.bonus.val = +1;
gbonus.bdescr << std::pair<ui8,ui32>(6,94);
@ -3412,4 +3425,122 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
}
}
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
};
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
{
protected:
@ -139,6 +155,7 @@ public:
virtual const std::string & getHoverText() const;
//////////////////////////////////////////////////////////////////////////
void initObj();
void onHeroVisit(const CGHeroInstance * h) const;
void setProperty(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;
};
class DLL_EXPORT CGTownInstance : public CGDwelling
class DLL_EXPORT CGTownInstance : public CGDwelling, public IShipyard
{
public:
CTown * town;
@ -357,6 +374,7 @@ public:
int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
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
{

View File

@ -145,3 +145,10 @@ void IGameCallback::getAllowed(std::vector<CArtifact*> &out, int flags)
if(flags & CArtifact::ART_RELIC)
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 CArtifact;
class CArmedInstance;
struct TerrainTile;
class DLL_EXPORT IGameCallback
{
@ -55,6 +56,7 @@ public:
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 getAllowed(std::vector<CArtifact*> &out, int flags); //flags: bitfield uses EartClass
virtual TerrainTile * getTile(int3 pos);
//do sth
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;};
void applyCl(CClient *cl);
enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL};
enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL, SHIPYARD_WINDOW};
ui8 window;
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
{
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
{
QueryReply(){};

View File

@ -490,6 +490,32 @@ DLL_EXPORT void GiveHero::applyGs( CGameState *gs )
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 )
{
gs->day = day;

View File

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

View File

@ -1688,7 +1688,6 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
break;
}
case 42: //lighthouse
case 87: //shipyard
case 220://mine (?)
{
nobj = new CGObjectInstance();
@ -1881,6 +1880,12 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
nobj = new CGSirens();
break;
}
case 87: //Shipyard
{
nobj = new CGShipyard();
nobj->setOwner(readNormalNr(bufor,i)); i+=4;
break;
}
case 214: //hero placeholder
{
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)
return false;
@ -2034,6 +2039,17 @@ TerrainTile & Mapa::getTile( int3 tile )
{
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()
{
playerAmnt=humenPlayers=0;

View File

@ -335,8 +335,10 @@ struct DLL_EXPORT Mapa : public CMapHeader
Mapa();
~Mapa();
TerrainTile &getTile(int3 tile);
const TerrainTile &getTile(int3 tile) const;
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)
{
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)
{
const CGObjectInstance *obj = objects[h].first;
ui8 color = obj->tempOwner;
//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;
//printing object
SDL_Rect sr;
sr.x = srx;
sr.y = sry;
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.w = sr.w;
const CGHeroInstance * themp = (objects[h].first->ID != HEROI_TYPE
const CGHeroInstance * themp = (obj->ID != HEROI_TYPE
? 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;
SDL_Surface * tb;
if(themp->type==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
const int IMGVAL = 8; //frames per group of movement animation
ui8 dir;
std::vector<Cimage> * iv = 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;
case 1: flg = &Graphics::flags2; break;
case 2: flg = &Graphics::flags3; break;
default: tlog1 << "Not supported boat subtype: " << themp->boat->subID << std::endl;
switch (themp->boat->subID)
{
case 0: flg = &Graphics::flags1; break;
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;
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;
}
}
CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr);
//printing flag
pp.y+=imgVal*2-32;
pp.y+=IMGVAL*2-32;
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;
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;
}
}
CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr);
//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;
bufr.x-=2*32;
@ -809,19 +823,18 @@ void CMapHandler::terrainRect(int3 top_tile, unsigned char anim, std::vector< st
bufr.h = 64;
bufr.w = 96;
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;
SDL_Surface *bitmap = ourImages[(anim+obj->animPhaseShift)%ourImages.size()].bitmap;
//setting appropriate flag color
if(obj->tempOwner<8 || obj->tempOwner==255)
CSDL_Ext::setPlayerColor(bitmap, obj->tempOwner);
if(color < 8 || color==255)
CSDL_Ext::setPlayerColor(bitmap, color);
CSDL_Ext::blit8bppAlphaTo24bpp(bitmap,&pp,extSurf,&sr);
}

View File

@ -662,7 +662,7 @@ void CGameHandler::newTurn()
{
NewTurn::Hero hth;
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
hth.mana = h->manaLimit(); //restore all mana
@ -2872,3 +2872,49 @@ void CGameHandler::objectVisited( const CGObjectInstance * obj, const CGHeroInst
{
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 queryReply( ui32 qid, ui32 answer );
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 buyArtifact( ui32 hid, si32 aid );

View File

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