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:
parent
7853a19b54
commit
9fd4b5bb62
@ -732,6 +732,13 @@ void CCallback::sendMessage(const std::string &mess)
|
||||
*cl->serv << ±
|
||||
}
|
||||
|
||||
void CCallback::buildBoat( const IShipyard *obj )
|
||||
{
|
||||
BuildBoat bb;
|
||||
bb.objid = obj->o->id;
|
||||
*cl->serv << &bb;
|
||||
}
|
||||
|
||||
InfoAboutHero::InfoAboutHero()
|
||||
{
|
||||
details = NULL;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 )
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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__
|
||||
|
@ -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 )
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
@ -3413,3 +3426,121 @@ 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);
|
||||
}
|
||||
}
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
@ -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;
|
||||
|
@ -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(){};
|
||||
|
@ -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;
|
||||
|
@ -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>();
|
||||
|
20
lib/map.cpp
20
lib/map.cpp
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,24 +735,29 @@ 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;
|
||||
const int IMGVAL = 8; //frames per group of movement animation
|
||||
ui8 dir;
|
||||
std::vector<Cimage> * iv = NULL;
|
||||
std::vector<CDefEssential *> Graphics::*flg = NULL;
|
||||
SDL_Surface * tb; //surface to blitted
|
||||
|
||||
if(themp) //hero
|
||||
{
|
||||
dir = themp->moveDir;
|
||||
|
||||
//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;
|
||||
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;
|
||||
if(themp->boat)
|
||||
{
|
||||
switch (themp->boat->subID)
|
||||
@ -767,41 +772,50 @@ void CMapHandler::terrainRect(int3 top_tile, unsigned char anim, std::vector< st
|
||||
{
|
||||
flg = &Graphics::flags4;
|
||||
}
|
||||
}
|
||||
else //boat
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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 );
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user