1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-02-03 13:01:33 +02:00

Second part of sailing support:

* boat graphics and appropriate flags are used
* disembarking possible
* new objects supported:
 - Flotsam
 - Shipwreck Survivor
 - Sea Chest
This commit is contained in:
Michał W. Urbańczyk 2009-07-19 03:10:24 +00:00
parent 2ca7cc5b5c
commit 9272f501cd
9 changed files with 203 additions and 34 deletions

View File

@ -282,7 +282,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
int3 hp = details.start;
if (details.result != TryMoveHero::SUCCESS) //hero failed to move
{
if(details.result == TryMoveHero::BLOCKING_VISIT)
if(details.result != TryMoveHero::FAILED)
{
adventureInt->paths.erase(ho);
adventureInt->terrain.currentPath = NULL;
@ -290,6 +290,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
ho->isStanding = true;
stillMoveHero.setn(STOP_MOVE);
LOCPLINT->totalRedraw();
return;
}
@ -1573,6 +1574,12 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CPath path )
for(int i=path.nodes.size()-1; i>0 && stillMoveHero.data == CONTINUE_MOVE; i--)
{
//stop sending move requests if hero exhausted all his move points
if(!h->movement)
{
stillMoveHero.data = STOP_MOVE;
break;
}
// Start a new sound for the hero movement or let the existing one carry on.
#if 0
// TODO

View File

@ -368,19 +368,20 @@ void Graphics::loadHeroFlags(std::pair<std::vector<CDefEssential *> Graphics::*,
rotations += std::make_pair(6,10), std::make_pair(7,11), std::make_pair(8,12);
for(int q=0; q<8; ++q)
{
for(size_t o=0; o<(this->*pr.first)[q]->ourImages.size(); ++o)
std::vector<Cimage> &curImgs = (this->*pr.first)[q]->ourImages;
for(size_t o=0; o<curImgs.size(); ++o)
{
for(size_t p=0;p<rotations.size();p++)
{
if((this->*pr.first)[q]->ourImages[o].groupNumber==rotations[p].first)
if(curImgs[o].groupNumber==rotations[p].first)
{
for(int e=0; e<8; ++e)
{
Cimage nci;
nci.bitmap = CSDL_Ext::rotate01((this->*pr.first)[q]->ourImages[o+e].bitmap);
nci.bitmap = CSDL_Ext::rotate01(curImgs[o+e].bitmap);
nci.groupNumber = rotations[p].second;
nci.imName = std::string();
(this->*pr.first)[q]->ourImages.push_back(nci);
curImgs.push_back(nci);
}
o+=8;
}
@ -388,50 +389,50 @@ void Graphics::loadHeroFlags(std::pair<std::vector<CDefEssential *> Graphics::*,
}
if (mode)
{
for(size_t o=0; o<flags4[q]->ourImages.size(); ++o)
for(size_t o=0; o<curImgs.size(); ++o)
{
if(flags4[q]->ourImages[o].groupNumber==1)
if(curImgs[o].groupNumber==1)
{
for(int e=0; e<8; ++e)
{
Cimage nci;
nci.bitmap = CSDL_Ext::rotate01(flags4[q]->ourImages[o+e].bitmap);
nci.bitmap = CSDL_Ext::rotate01(curImgs[o+e].bitmap);
nci.groupNumber = 13;
nci.imName = std::string();
flags4[q]->ourImages.push_back(nci);
curImgs.push_back(nci);
}
o+=8;
}
if(flags4[q]->ourImages[o].groupNumber==2)
if(curImgs[o].groupNumber==2)
{
for(int e=0; e<8; ++e)
{
Cimage nci;
nci.bitmap = CSDL_Ext::rotate01(flags4[q]->ourImages[o+e].bitmap);
nci.bitmap = CSDL_Ext::rotate01(curImgs[o+e].bitmap);
nci.groupNumber = 14;
nci.imName = std::string();
flags4[q]->ourImages.push_back(nci);
curImgs.push_back(nci);
}
o+=8;
}
if(flags4[q]->ourImages[o].groupNumber==3)
if(curImgs[o].groupNumber==3)
{
for(int e=0; e<8; ++e)
{
Cimage nci;
nci.bitmap = CSDL_Ext::rotate01(flags4[q]->ourImages[o+e].bitmap);
nci.bitmap = CSDL_Ext::rotate01(curImgs[o+e].bitmap);
nci.groupNumber = 15;
nci.imName = std::string();
flags4[q]->ourImages.push_back(nci);
curImgs.push_back(nci);
}
o+=8;
}
}
}
for(size_t ff=0; ff<(this->*pr.first)[q]->ourImages.size(); ++ff)
for(size_t ff=0; ff<curImgs.size(); ++ff)
{
SDL_SetColorKey((this->*pr.first)[q]->ourImages[ff].bitmap, SDL_SRCCOLORKEY,
SDL_MapRGB((this->*pr.first)[q]->ourImages[ff].bitmap->format, 0, 255, 255)
SDL_SetColorKey(curImgs[ff].bitmap, SDL_SRCCOLORKEY,
SDL_MapRGB(curImgs[ff].bitmap->format, 0, 255, 255)
);
}
}
@ -456,9 +457,9 @@ void Graphics::loadHeroFlags()
("AF05.DEF"),("AF06.DEF"),("AF07.DEF");
boost::thread_group grupa;
grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[3]),true));
grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[2]),false));
grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[1]),false));
grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[0]),false));
grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[2]),true));
grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[1]),true));
grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[0]),true));
grupa.join_all();
tlog0 << "Loading and transforming heroes' flags: "<<th.getDif()<<std::endl;
}

View File

@ -140,16 +140,25 @@ void RemoveObject::applyCl( CClient *cl )
void TryMoveHero::applyFirstCl( CClient *cl )
{
if(result == TELEPORTATION || result == EMBARK)
CGI->mh->removeObject(GS(cl)->getHero(id));
CGHeroInstance *h = GS(cl)->getHero(id);
if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK)
CGI->mh->removeObject(h);
if(result == DISEMBARK)
CGI->mh->printObject(h->boat);
}
void TryMoveHero::applyCl( CClient *cl )
{
const CGHeroInstance *h = cl->getHero(id);
if(result == TELEPORTATION || result == EMBARK)
if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK)
CGI->mh->printObject(h);
if(result == EMBARK)
CGI->mh->hideObject(h->boat);
int player = h->tempOwner;
if(vstd::contains(cl->playerint,player))

View File

@ -2200,6 +2200,60 @@ void CGPickable::initObj()
val1 = val2 * 100;
type = ran()%6; //given resource
break;
case 29: //floatsam
switch(type = ran()%4)
{
case 0:
val1 = val2 = 0;
break;
case 1:
val1 = 5;
val2 = 0;
break;
case 2:
val1 = 5;
val2 = 200;
break;
case 3:
val1 = 10;
val2 = 500;
break;
}
break;
case 82: //sea chest
{
int hlp = ran()%100;
if(hlp < 20)
{
val1 = 0;
type = 0;
}
else if(hlp < 90)
{
val1 = 1500;
type = 2;
}
else
{
val1 = 1000;
val2 = VLC->arth->treasures[ran()%VLC->arth->treasures.size()]->id;
type = 1;
}
}
break;
case 86: //Shipwreck Survivor
{
int hlp = ran()%100;
if(hlp < 55)
val1 = VLC->arth->treasures[ran()%VLC->arth->treasures.size()]->id;
else if(hlp < 75)
val1 = VLC->arth->minors[ran()%VLC->arth->minors.size()]->id;
else if(hlp < 95)
val1 = VLC->arth->majors[ran()%VLC->arth->majors.size()]->id;
else
val1 = VLC->arth->relics[ran()%VLC->arth->relics.size()]->id;
}
break;
case 101: //treasure chest
{
int hlp = ran()%100;
@ -2247,6 +2301,57 @@ void CGPickable::onHeroVisit( const CGHeroInstance * h ) const
cb->showInfoDialog(&iw);
break;
}
case 29: //flotsam
{
cb->giveResource(h->tempOwner,0,val1); //wood
cb->giveResource(h->tempOwner,6,val2);//gold
InfoWindow iw;
iw.soundID = soundBase::GENIE;
iw.player = h->tempOwner;
if(val1)
iw.components.push_back(Component(2,0,val1,0));
if(val2)
iw.components.push_back(Component(2,6,val2,0));
iw.text.addTxt(MetaString::ADVOB_TXT, 51+type);
cb->showInfoDialog(&iw);
break;
}
case 82: //Sea Chest
{
InfoWindow iw;
iw.soundID = soundBase::chest;
iw.player = h->tempOwner;
iw.text.addTxt(MetaString::ADVOB_TXT, 116 + type);
if(val1) //there is gold
{
iw.components.push_back(Component(2,6,val1,0));
cb->giveResource(h->tempOwner,6,val1);
}
if(type == 1) //art
{
//TODO: what if no space in backpack?
iw.components.push_back(Component(4, val2, 1, 0));
iw.text.addReplacement(MetaString::ART_NAMES, val2);
cb->giveHeroArtifact(val2,h->id,-2);
}
cb->showInfoDialog(&iw);
break;
}
case 86: //Shipwreck Survivor
{
//TODO: what if no space in backpack?
InfoWindow iw;
iw.soundID = soundBase::experience;
iw.player = h->tempOwner;
iw.components.push_back(Component(4,val1,1,0));
iw.text.addTxt(MetaString::ADVOB_TXT, 125);
iw.text.addReplacement(MetaString::ART_NAMES, val1);
cb->giveHeroArtifact(val1,h->id,-2);
cb->showInfoDialog(&iw);
break;
}
case 101: //treasure chest
{
if (subID) //not OH3 treasure chest

View File

@ -581,7 +581,7 @@ public:
}
};
class DLL_EXPORT CGPickable : public CGObjectInstance //campfire, treasure chest
class DLL_EXPORT CGPickable : public CGObjectInstance //campfire, treasure chest, Flotsam, Shipwreck Survivor, Sea Chest
{
public:
ui32 type, val1, val2;

View File

@ -288,6 +288,9 @@ void TryMoveHero::applyGs( CGameState *gs )
CGHeroInstance *h = gs->getHero(id);
h->movement = movePoints;
if(result == SUCCESS || result == BLOCKING_VISIT || result == EMBARK || result == DISEMBARK)
h->moveDir = getDir(start,end);
if(result == EMBARK) //hero enters boat at dest tile
{
const TerrainTile &tt = gs->map->getTile(CGHeroInstance::convertPosition(end, false));
@ -298,19 +301,26 @@ void TryMoveHero::applyGs( CGameState *gs )
h->boat = boat;
boat->hero = h;
}
else if(result == DISEMBARK) //hero leaves boat to dest tile
{
h->boat->direction = h->moveDir;
h->boat->pos = start;
h->boat->hero = NULL;
gs->map->addBlockVisTiles(h->boat);
h->boat = NULL;
}
if(start!=end && (result == SUCCESS || result == TELEPORTATION || result == EMBARK))
if(start!=end && (result == SUCCESS || result == TELEPORTATION || result == EMBARK || result == DISEMBARK))
{
gs->map->removeBlockVisTiles(h);
h->pos = end;
if(h->boat)
h->boat->pos = end;
gs->map->addBlockVisTiles(h);
}
BOOST_FOREACH(int3 t, fowRevealed)
gs->getPlayer(h->getOwner())->fogOfWarMap[t.x][t.y][t.z] = 1;
if(result == SUCCESS || result == BLOCKING_VISIT || result == EMBARK)
h->moveDir = getDir(start,end);
}
DLL_EXPORT void SetGarrisons::applyGs( CGameState *gs )

View File

@ -1498,7 +1498,10 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
break;
}
case 12: //campfire
case 101: //treasure chest
case 29: //Flotsam
case 82: //Sea Chest
case 86: //Shipwreck Survivor
case 101://treasure chest
{
nobj = new CGPickable();
break;

View File

@ -784,10 +784,29 @@ void CMapHandler::terrainRect(int3 top_tile, unsigned char anim, std::vector< st
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
std::vector<CDefEssential *> Graphics::*flg = NULL;
if(themp->boat)
{
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;
}
if(!themp->isStanding) //hero is moving
{
size_t gg;
@ -802,7 +821,7 @@ void CMapHandler::terrainRect(int3 top_tile, unsigned char anim, std::vector< st
CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr);
pp.y+=imgVal*2-32;
sr.y-=16;
SDL_BlitSurface(graphics->flags4[themp->getOwner()]->ourImages[gg+heroAnim%imgVal+35].bitmap, &pp, extSurf, &sr);
SDL_BlitSurface((graphics->*flg)[themp->getOwner()]->ourImages[gg+heroAnim%imgVal+35].bitmap, &pp, extSurf, &sr);
}
else //hero stands still
{
@ -825,7 +844,7 @@ 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->flags4[themp->getOwner()]->ourImages[ getHeroFrameNum(themp->moveDir, !themp->isStanding) *8+(heroAnim/4)%imgVal].bitmap, NULL, extSurf, &bufr);
SDL_BlitSurface((graphics->*flg)[themp->getOwner()]->ourImages[ getHeroFrameNum(themp->moveDir, !themp->isStanding) *8+(heroAnim/4)%imgVal].bitmap, NULL, extSurf, &bufr);
}
}
}

View File

@ -1167,7 +1167,10 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
if((t.tertype == TerrainTile::rock || (t.blocked && !t.visitable))
&& complain("Cannot move hero, destination tile is blocked!")
|| (!h->boat && !h->canWalkOnSea() && t.tertype == TerrainTile::water && (t.visitableObjects.size() != 1 || t.visitableObjects.front()->ID != 8))
&& complain("Cannot move hero, destination tile is on water!"))
&& complain("Cannot move hero, destination tile is on water!")
|| (h->boat && t.tertype != TerrainTile::water && t.blocked)
&& complain("Cannot disembark hero, tile is blocked!")
|| !h->movement && complain("Hero don't have any movement points left!"))
{
//send info about movement failure
sendAndApply(&tmh);
@ -1185,11 +1188,22 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
sendAndApply(&tmh);
return true;
}
//hero leaves the boat
else if(h->boat && t.tertype != TerrainTile::water && !t.blocked)
{
tmh.result = TryMoveHero::DISEMBARK;
tmh.movePoints = 0; //disembarking takes all move points
//TODO: check for bonus that removes that penalty
getTilesInRange(tmh.fowRevealed,h->getSightCenter()+(tmh.end-tmh.start),h->getSightRadious(),h->tempOwner,1);
sendAndApply(&tmh);
return true;
}
//checks for standard movement
if(!instant)
{
if( (distance(h->pos,dst)>=1.5) //tiles are not neighouring
if( (distance(h->pos,dst)>=1.5) //tiles are not neighbouring
|| (h->movement < cost && h->movement < 100) //lack of movement points
)
{
@ -1308,6 +1322,7 @@ int CGameHandler::getCurrentPlayer()
void CGameHandler::giveResource(int player, int which, int val)
{
if(!val) return; //don't waste time on empty call
SetResource sr;
sr.player = player;
sr.resid = which;