mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
First part of Boat and sailing support.
[It's possible to enter the boat and move by sea, graphical glitches removal and disembarking will be done soon]
This commit is contained in:
parent
601117f440
commit
2ca7cc5b5c
@ -756,7 +756,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
||||
stillMoveHero.setn(STOP_MOVE);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
if(ev->key.keysym.sym < SDLK_F1)
|
||||
if(ev->key.keysym.sym < SDLK_F1 || ev->key.keysym.sym > SDLK_F15)
|
||||
stillMoveHero.setn(STOP_MOVE);
|
||||
break;
|
||||
}
|
||||
|
@ -326,7 +326,7 @@ void Graphics::loadHeroAnims()
|
||||
void Graphics::loadHeroAnim( const std::string &name, const std::vector<std::pair<int,int> > &rotations, std::vector<CDefEssential *> Graphics::*dst )
|
||||
{
|
||||
CDefEssential *anim = CDefHandler::giveDefEss(name);
|
||||
heroAnims.push_back(anim);
|
||||
(this->*dst).push_back(anim);
|
||||
int pom = 0; //how many groups has been rotated
|
||||
for(int o=7; pom<6; ++o)
|
||||
{
|
||||
|
@ -140,7 +140,7 @@ void RemoveObject::applyCl( CClient *cl )
|
||||
|
||||
void TryMoveHero::applyFirstCl( CClient *cl )
|
||||
{
|
||||
if(result == TELEPORTATION)
|
||||
if(result == TELEPORTATION || result == EMBARK)
|
||||
CGI->mh->removeObject(GS(cl)->getHero(id));
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ void TryMoveHero::applyCl( CClient *cl )
|
||||
{
|
||||
const CGHeroInstance *h = cl->getHero(id);
|
||||
|
||||
if(result == TELEPORTATION)
|
||||
if(result == TELEPORTATION || result == EMBARK)
|
||||
CGI->mh->printObject(h);
|
||||
int player = h->tempOwner;
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
9
|
||||
10 100 150 100 150 175 125 100 100 -1 -1
|
||||
10 100 150 100 150 175 125 100 100 -1 -1
|
||||
10 100 150 100 100 175 125 100 100 -1 -1
|
||||
10 100 150 100 150 175 125 100 100 -1 -1
|
||||
10 100 150 100 150 175 125 100 100 -1 -1
|
||||
10 100 150 100 150 175 125 100 100 -1 -1
|
||||
10 100 150 100 150 175 100 100 100 -1 -1
|
||||
10 100 150 100 150 100 125 100 100 -1 -1
|
||||
10 100 150 100 150 175 125 100 100 -1 -1
|
||||
10 100 150 100 150 175 125 100 100 100 -1
|
||||
10 100 150 100 150 175 125 100 100 100 -1
|
||||
10 100 150 100 100 175 125 100 100 100 -1
|
||||
10 100 150 100 150 175 125 100 100 100 -1
|
||||
10 100 150 100 150 175 125 100 100 100 -1
|
||||
10 100 150 100 150 175 125 100 100 100 -1
|
||||
10 100 150 100 150 175 100 100 100 100 -1
|
||||
10 100 150 100 150 100 125 100 100 100 -1
|
||||
10 100 150 100 150 175 125 100 100 100 -1
|
@ -373,7 +373,7 @@ si32 CGHeroInstance::manaLimit() const
|
||||
|
||||
bool CGHeroInstance::canWalkOnSea() const
|
||||
{
|
||||
//TODO: write it - it should check if hero is flying, or something similiar
|
||||
//TODO: write it - it should check if hero is flying, or something similar
|
||||
return false;
|
||||
}
|
||||
int CGHeroInstance::getPrimSkillLevel(int id) const
|
||||
@ -492,6 +492,7 @@ CGHeroInstance::CGHeroInstance()
|
||||
exp = 0xffffffff;
|
||||
visitedTown = NULL;
|
||||
type = NULL;
|
||||
boat = NULL;
|
||||
secSkills.push_back(std::make_pair(-1, -1));
|
||||
}
|
||||
|
||||
@ -3207,3 +3208,9 @@ void CGOnceVisitable::searchTomb(const CGHeroInstance *h, ui32 accept) const
|
||||
cb->setObjProperty(id,10,h->getOwner());
|
||||
}
|
||||
}
|
||||
|
||||
void CGBoat::initObj()
|
||||
{
|
||||
defInfo->visitDir = 0xff;
|
||||
hero = NULL;
|
||||
}
|
@ -42,6 +42,7 @@ class CGDefInfo;
|
||||
class CSpecObjInfo;
|
||||
struct TerrainTile;
|
||||
struct InfoWindow;
|
||||
class CGBoat;
|
||||
|
||||
class DLL_EXPORT CCastleEvent
|
||||
{
|
||||
@ -203,6 +204,7 @@ public:
|
||||
ui8 sex;
|
||||
ui8 inTownGarrison; // if hero is in town garrison
|
||||
CGTownInstance * visitedTown; //set if hero is visiting town or in the town garrison
|
||||
CGBoat *boat; //set to CGBoat when sailing
|
||||
std::vector<ui32> artifacts; //hero's artifacts from bag
|
||||
std::map<ui16,ui32> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
|
||||
std::set<ui32> spells; //known spells (spell IDs)
|
||||
@ -722,6 +724,24 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_EXPORT CGBoat : public CGObjectInstance
|
||||
{
|
||||
public:
|
||||
ui8 direction;
|
||||
const CGHeroInstance *hero; //hero on board
|
||||
|
||||
void initObj();
|
||||
|
||||
CGBoat()
|
||||
{
|
||||
direction = 4;
|
||||
}
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CGObjectInstance&>(*this) & direction;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_EXPORT CGOnceVisitable : public CPlayersVisited //wagon, corpse, lean to, warriors tomb
|
||||
{
|
||||
public:
|
||||
|
@ -1484,61 +1484,21 @@ void CGameState::loadTownDInfos()
|
||||
|
||||
void CGameState::getNeighbours(int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand)
|
||||
{
|
||||
/* notation:
|
||||
* 1 2 3
|
||||
* 4 5 6
|
||||
* 7 8 9
|
||||
*/
|
||||
int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),
|
||||
int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) };
|
||||
|
||||
vec.clear();
|
||||
int3 hlp;
|
||||
bool weAreOnLand = (map->getTile(tile).tertype != 8);
|
||||
if(tile.y < map->height-1) //8
|
||||
for (size_t i = 0; i < ARRAY_COUNT(dirs); i++)
|
||||
{
|
||||
int3 hlp = tile + dirs[i];
|
||||
if(!map->isInTheMap(hlp))
|
||||
continue;
|
||||
|
||||
if((indeterminate(onLand) || onLand == (map->getTile(hlp).tertype!=8) )
|
||||
&& map->getTile(hlp).tertype!=9)
|
||||
{
|
||||
hlp = int3(tile.x,tile.y+1,tile.z);
|
||||
if((weAreOnLand == (map->getTile(hlp).tertype!=8)) && map->getTile(hlp).tertype!=9)
|
||||
vec.push_back(hlp);
|
||||
}
|
||||
if(tile.y > 0) //2
|
||||
{
|
||||
hlp = int3(tile.x,tile.y-1,tile.z);
|
||||
if((weAreOnLand == (map->getTile(hlp).tertype!=8)) && map->getTile(hlp).tertype!=9)
|
||||
vec.push_back(hlp);
|
||||
}
|
||||
if(tile.x > 0) //4
|
||||
{
|
||||
hlp = int3(tile.x-1,tile.y,tile.z);
|
||||
if((weAreOnLand == (map->getTile(hlp).tertype!=8)) && map->getTile(hlp).tertype!=9)
|
||||
vec.push_back(hlp);
|
||||
}
|
||||
if(tile.x < map->width-1) //6
|
||||
{
|
||||
hlp = int3(tile.x+1,tile.y,tile.z);
|
||||
if((weAreOnLand == (map->getTile(hlp).tertype!=8)) && map->getTile(hlp).tertype!=9)
|
||||
vec.push_back(hlp);
|
||||
}
|
||||
if(tile.x > 0 && tile.y > 0) //1
|
||||
{
|
||||
hlp = int3(tile.x-1,tile.y-1,tile.z);
|
||||
if((weAreOnLand == (map->getTile(hlp).tertype!=8)) && map->getTile(hlp).tertype!=9)
|
||||
vec.push_back(hlp);
|
||||
}
|
||||
if(tile.x > 0 && tile.y < map->height-1) //7
|
||||
{
|
||||
hlp = int3(tile.x-1,tile.y+1,tile.z);
|
||||
if((weAreOnLand == (map->getTile(hlp).tertype!=8)) && map->getTile(hlp).tertype!=9)
|
||||
vec.push_back(hlp);
|
||||
}
|
||||
if(tile.x < map->width-1 && tile.y > 0) //3
|
||||
{
|
||||
hlp = int3(tile.x+1,tile.y-1,tile.z);
|
||||
if((weAreOnLand == (map->getTile(hlp).tertype!=8)) && map->getTile(hlp).tertype!=9)
|
||||
vec.push_back(hlp);
|
||||
}
|
||||
if(tile.x < map->width-1 && tile.y < map->height-1) //9
|
||||
{
|
||||
hlp = int3(tile.x+1,tile.y+1,tile.z);
|
||||
if((weAreOnLand == (map->getTile(hlp).tertype!=8)) && map->getTile(hlp).tertype!=9)
|
||||
vec.push_back(hlp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1557,7 +1517,7 @@ int CGameState::getMovementCost(const CGHeroInstance *h, int3 src, int3 dest, in
|
||||
{
|
||||
int old = ret;
|
||||
ret *= 1.414;
|
||||
//diagonal move costs too much but normal move is possible - allow diagonal move
|
||||
//diagonal move costs too much but normal move is possible - allow diagonal move for remaining move points
|
||||
if(ret > remainingMovePoints && remainingMovePoints > old)
|
||||
{
|
||||
return remainingMovePoints;
|
||||
@ -1569,7 +1529,7 @@ int CGameState::getMovementCost(const CGHeroInstance *h, int3 src, int3 dest, in
|
||||
if(checkLast && left > 0 && remainingMovePoints-ret < 250) //it might be the last tile - if no further move possible we take all move points
|
||||
{
|
||||
std::vector<int3> vec;
|
||||
getNeighbours(dest,vec,true);
|
||||
getNeighbours(dest, vec, s.tertype != TerrainTile::water);
|
||||
for(size_t i=0; i < vec.size(); i++)
|
||||
{
|
||||
int fcost = getMovementCost(h,dest,vec[i],left,false);
|
||||
@ -1676,10 +1636,6 @@ bool CGameState::getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath
|
||||
CPathNode &node = graph[i][j];
|
||||
|
||||
node.accesible = !tinfo->blocked;
|
||||
if(i==dest.x && j==dest.y && tinfo->visitable)
|
||||
{
|
||||
node.accesible = true; //for allowing visiting objects
|
||||
}
|
||||
node.dist = -1;
|
||||
node.theNodeBefore = NULL;
|
||||
node.visited = false;
|
||||
@ -1697,6 +1653,35 @@ bool CGameState::getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Special rules for the destination tile
|
||||
{
|
||||
const TerrainTile *t = &map->terrain[dest.x][dest.y][dest.z];
|
||||
CPathNode &d = graph[dest.x][dest.y];
|
||||
|
||||
//tile may be blocked by blockvis / normal vis obj but it still must be accessible
|
||||
if(t->visitable)
|
||||
{
|
||||
d.accesible = true; //for allowing visiting objects
|
||||
}
|
||||
|
||||
if(blockLandSea && t->tertype == TerrainTile::water) //hero can walk only on land and dst lays on the water
|
||||
{
|
||||
size_t i = 0;
|
||||
for(; i < t->visitableObjects.size(); i++)
|
||||
if(t->visitableObjects[i]->ID == 8) //it's a Boat
|
||||
break;
|
||||
|
||||
d.accesible = (i < t->visitableObjects.size()); //dest is accessible only if there is boat
|
||||
}
|
||||
else if(!blockLandSea && t->tertype != TerrainTile::water) //hero is moving by water
|
||||
{
|
||||
d.accesible = (t->siodmyTajemniczyBajt & 64) && !t->blocked; //tile is accessible if it's coastal and not blocked
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//graph initialized
|
||||
|
||||
//initial tile - set cost on 0 and add to the queue
|
||||
@ -1726,7 +1711,7 @@ bool CGameState::getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath
|
||||
}
|
||||
|
||||
//add accessible neighbouring nodes to the queue
|
||||
getNeighbours(cp.coord,neighbours,blockLandSea);
|
||||
getNeighbours(cp.coord, neighbours, boost::logic::indeterminate);
|
||||
for(unsigned int i=0; i < neighbours.size(); i++)
|
||||
{
|
||||
CPathNode & dp = graph[neighbours[i].x][neighbours[i].y];
|
||||
|
@ -394,7 +394,7 @@ struct TryMoveHero : public CPackForClient //501
|
||||
|
||||
enum EResult
|
||||
{
|
||||
FAILED, SUCCESS, TELEPORTATION, RESERVED___, BLOCKING_VISIT
|
||||
FAILED, SUCCESS, TELEPORTATION, RESERVED___, BLOCKING_VISIT, EMBARK, DISEMBARK
|
||||
};
|
||||
|
||||
ui32 id, movePoints;
|
||||
|
@ -287,7 +287,19 @@ void TryMoveHero::applyGs( CGameState *gs )
|
||||
{
|
||||
CGHeroInstance *h = gs->getHero(id);
|
||||
h->movement = movePoints;
|
||||
if(start!=end && (result == SUCCESS || result == TELEPORTATION))
|
||||
|
||||
if(result == EMBARK) //hero enters boat at dest tile
|
||||
{
|
||||
const TerrainTile &tt = gs->map->getTile(CGHeroInstance::convertPosition(end, false));
|
||||
assert(tt.visitableObjects.size() == 1 && tt.visitableObjects.front()->ID == 8); //the only vis obj at dest is Boat
|
||||
CGBoat *boat = static_cast<CGBoat*>(tt.visitableObjects.front());
|
||||
|
||||
gs->map->removeBlockVisTiles(boat); //hero blockvis mask will be used, we don't need to duplicate it with boat
|
||||
h->boat = boat;
|
||||
boat->hero = h;
|
||||
}
|
||||
|
||||
if(start!=end && (result == SUCCESS || result == TELEPORTATION || result == EMBARK))
|
||||
{
|
||||
gs->map->removeBlockVisTiles(h);
|
||||
h->pos = end;
|
||||
@ -297,7 +309,7 @@ void TryMoveHero::applyGs( CGameState *gs )
|
||||
BOOST_FOREACH(int3 t, fowRevealed)
|
||||
gs->getPlayer(h->getOwner())->fogOfWarMap[t.x][t.y][t.z] = 1;
|
||||
|
||||
if(result == SUCCESS || result == BLOCKING_VISIT)
|
||||
if(result == SUCCESS || result == BLOCKING_VISIT || result == EMBARK)
|
||||
h->moveDir = getDir(start,end);
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,7 @@ void registerTypes1(Serializer &s)
|
||||
s.template registerType<CGBonusingObject>();
|
||||
s.template registerType<CGMagicWell>();
|
||||
s.template registerType<CGObservatory>();
|
||||
s.template registerType<CGBoat>();
|
||||
s.template registerType<CGOnceVisitable>();
|
||||
s.template registerType<CGObjectInstance>();
|
||||
}
|
||||
|
@ -1860,6 +1860,11 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
|
||||
nobj = new CGOnceVisitable();
|
||||
break;
|
||||
}
|
||||
case 8: //Boat
|
||||
{
|
||||
nobj = new CGBoat();
|
||||
break;
|
||||
}
|
||||
case 214: //hero placeholder
|
||||
{
|
||||
i+=3; //TODO: handle it more properly
|
||||
|
@ -784,7 +784,9 @@ void CMapHandler::terrainRect(int3 top_tile, unsigned char anim, std::vector< st
|
||||
SDL_Surface * tb;
|
||||
if(themp->type==NULL)
|
||||
continue;
|
||||
std::vector<Cimage> & iv = graphics->heroAnims[themp->type->heroType]->ourImages;
|
||||
std::vector<Cimage> & iv = (themp->boat)
|
||||
? graphics->boatAnims[themp->boat->subID]->ourImages
|
||||
: graphics->heroAnims[themp->type->heroType]->ourImages;
|
||||
|
||||
if(!themp->isStanding) //hero is moving
|
||||
{
|
||||
|
@ -1161,16 +1161,31 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
|
||||
tmh.movePoints = h->movement;
|
||||
|
||||
//check if destination tile is available
|
||||
if( t.tertype == TerrainTile::rock
|
||||
|| (!h->canWalkOnSea() && t.tertype == TerrainTile::water)
|
||||
|| (t.blocked && !t.visitable) //tile is blocked andnot visitable
|
||||
)
|
||||
|
||||
//it's a rock or blocked and not visitable tile
|
||||
//OR hero is on land and dest is water and (there is not present only one object - boat)
|
||||
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!"))
|
||||
{
|
||||
tlog2 << "Cannot move hero, destination tile is blocked!\n";
|
||||
//send info about movement failure
|
||||
sendAndApply(&tmh);
|
||||
return false;
|
||||
}
|
||||
|
||||
//hero enters the boat
|
||||
if(!h->boat && t.visitableObjects.size() && t.visitableObjects.front()->ID == 8)
|
||||
{
|
||||
tmh.result = TryMoveHero::EMBARK;
|
||||
tmh.movePoints = 0; //embarking 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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user