many changes
This commit is contained in:
parent
437f515e7c
commit
cf18b0c36f
|
@ -33,11 +33,21 @@ namespace Otc
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TILE_PIXELS = 32,
|
TILE_PIXELS = 32,
|
||||||
SEA_LEVEL = 7,
|
MAX_ELEVATION = 24,
|
||||||
|
|
||||||
|
SEA_FLOOR = 7,
|
||||||
MAX_Z = 15,
|
MAX_Z = 15,
|
||||||
|
UNDERGROUND_FLOOR = SEA_FLOOR+1,
|
||||||
VISIBLE_X_TILES = 15,
|
VISIBLE_X_TILES = 15,
|
||||||
VISIBLE_Y_TILES = 11,
|
VISIBLE_Y_TILES = 11,
|
||||||
MAX_ELEVATION = 24,
|
AWARE_UNDEGROUND_FLOOR_RANGE = 2,
|
||||||
|
AWARE_X_TILES = VISIBLE_X_TILES + 3,
|
||||||
|
AWARE_Y_TILES = VISIBLE_Y_TILES + 3,
|
||||||
|
AWARE_X_LEFT_TILES = AWARE_X_TILES/2 - 1,
|
||||||
|
AWARE_X_RIGHT_TILES = AWARE_X_TILES/2,
|
||||||
|
AWARE_Y_TOP_TILES = AWARE_Y_TILES/2 - 1,
|
||||||
|
AWARE_Y_BOTTOM_TILES = AWARE_Y_TILES/2,
|
||||||
|
|
||||||
EFFECT_TICKS_PER_FRAME = 75,
|
EFFECT_TICKS_PER_FRAME = 75,
|
||||||
ITEM_TICKS_PER_FRAME = 500,
|
ITEM_TICKS_PER_FRAME = 500,
|
||||||
ANIMATED_TEXT_DURATION = 1000,
|
ANIMATED_TEXT_DURATION = 1000,
|
||||||
|
@ -46,19 +56,19 @@ namespace Otc
|
||||||
MAX_STATIC_TEXT_WIDTH = 200,
|
MAX_STATIC_TEXT_WIDTH = 200,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MapDrawFlags {
|
enum DrawFlags {
|
||||||
MapDrawNonMoveableItems = 1,
|
DrawGround = 1,
|
||||||
MapDrawMoveableItems = 2,
|
DrawWalls = 2,
|
||||||
MapDrawCreatures = 4,
|
DrawCommonItems = 4,
|
||||||
MapDrawCreaturesInformation = 8,
|
DrawCreatures = 8,
|
||||||
MapDrawStaticTexts = 16,
|
DrawEffects = 16,
|
||||||
MapDrawAnimatedTexts = 32,
|
DrawMissiles = 32,
|
||||||
MapDrawEffects = 64,
|
DrawCreaturesInformation = 64,
|
||||||
MapDrawMissiles = 128,
|
DrawStaticTexts = 128,
|
||||||
MapDrawEverything = MapDrawNonMoveableItems | MapDrawMoveableItems |
|
DrawAnimatedTexts = 256,
|
||||||
MapDrawCreatures | MapDrawCreaturesInformation |
|
DrawEverything = DrawGround | DrawWalls | DrawCommonItems |
|
||||||
MapDrawStaticTexts | MapDrawAnimatedTexts |
|
DrawCreatures | DrawEffects | DrawMissiles |
|
||||||
MapDrawEffects | MapDrawMissiles
|
DrawCreaturesInformation | DrawStaticTexts | DrawAnimatedTexts
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DatOpts {
|
enum DatOpts {
|
||||||
|
|
|
@ -202,7 +202,7 @@ void Game::processInventoryChange(int slot, const ItemPtr& item)
|
||||||
void Game::processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos)
|
void Game::processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos)
|
||||||
{
|
{
|
||||||
// animate walk
|
// animate walk
|
||||||
if(oldPos.isInRange(newPos, 1, 1, 0))
|
if(oldPos.isInRange(newPos, 1, 1))
|
||||||
creature->walk(oldPos, newPos);
|
creature->walk(oldPos, newPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +246,7 @@ void Game::walk(Otc::Direction direction)
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
// only do prewalk to walkable tiles
|
// only do prewalk to walkable tiles
|
||||||
TilePtr toTile = g_map.getTile(m_localPlayer->getPosition() + Position::getPositionFromDirection(direction));
|
TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction));
|
||||||
if(toTile && toTile->isWalkable())
|
if(toTile && toTile->isWalkable())
|
||||||
m_localPlayer->preWalk(direction);
|
m_localPlayer->preWalk(direction);
|
||||||
else
|
else
|
||||||
|
|
|
@ -73,7 +73,7 @@ void Item::setPosition(const Position& position)
|
||||||
Thing::setPosition(position);
|
Thing::setPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Item::setData(int data)
|
void Item::setData(uint8 data)
|
||||||
{
|
{
|
||||||
if(isStackable() && getNumPatternsX() == 4 && getNumPatternsY() == 2) {
|
if(isStackable() && getNumPatternsX() == 4 && getNumPatternsY() == 2) {
|
||||||
if(data < 5) {
|
if(data < 5) {
|
||||||
|
|
|
@ -36,14 +36,14 @@ public:
|
||||||
void draw(const Point& dest, float scaleFactor);
|
void draw(const Point& dest, float scaleFactor);
|
||||||
|
|
||||||
void setPosition(const Position &position);
|
void setPosition(const Position &position);
|
||||||
void setData(int data);
|
void setData(uint8 data);
|
||||||
|
|
||||||
int getData() { return m_data; }
|
uint8 getData() { return m_data; }
|
||||||
|
|
||||||
ItemPtr asItem() { return std::static_pointer_cast<Item>(shared_from_this()); }
|
ItemPtr asItem() { return std::static_pointer_cast<Item>(shared_from_this()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_data;
|
uint8 m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -70,7 +70,7 @@ void LocalPlayer::walk(const Position& oldPos, const Position& newPos)
|
||||||
void LocalPlayer::preWalk(Otc::Direction direction)
|
void LocalPlayer::preWalk(Otc::Direction direction)
|
||||||
{
|
{
|
||||||
// start walking to direction
|
// start walking to direction
|
||||||
Position newPos = m_position + Position::getPositionFromDirection(direction);
|
Position newPos = m_position.translatedToDirection(direction);
|
||||||
m_preWalking = true;
|
m_preWalking = true;
|
||||||
m_lastPrewalkDone = false;
|
m_lastPrewalkDone = false;
|
||||||
m_lastPrewalkDestionation = newPos;
|
m_lastPrewalkDestionation = newPos;
|
||||||
|
|
|
@ -67,7 +67,13 @@ void Map::load()
|
||||||
uint16 id;
|
uint16 id;
|
||||||
in.read((char*)&id, sizeof(id));
|
in.read((char*)&id, sizeof(id));
|
||||||
while(id != 0xFFFF) {
|
while(id != 0xFFFF) {
|
||||||
addThing(Item::create(id), pos);
|
ItemPtr item = Item::create(id);
|
||||||
|
if(item->isStackable() || item->isFluidContainer() || item->isFluid()) {
|
||||||
|
uint8 data;
|
||||||
|
in.read((char*)&data, sizeof(data));
|
||||||
|
item->setData(data);
|
||||||
|
}
|
||||||
|
addThing(item, pos, 255);
|
||||||
in.read((char*)&id, sizeof(id));
|
in.read((char*)&id, sizeof(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +86,7 @@ void Map::save()
|
||||||
for(auto& pair : m_tiles) {
|
for(auto& pair : m_tiles) {
|
||||||
Position pos = pair.first;
|
Position pos = pair.first;
|
||||||
TilePtr tile = pair.second;
|
TilePtr tile = pair.second;
|
||||||
if(!tile)
|
if(!tile || tile->isEmpty())
|
||||||
continue;
|
continue;
|
||||||
out.write((char*)&pos, sizeof(pos));
|
out.write((char*)&pos, sizeof(pos));
|
||||||
uint16 id;
|
uint16 id;
|
||||||
|
@ -88,6 +94,10 @@ void Map::save()
|
||||||
if(ItemPtr item = thing->asItem()) {
|
if(ItemPtr item = thing->asItem()) {
|
||||||
id = item->getId();
|
id = item->getId();
|
||||||
out.write((char*)&id, sizeof(id));
|
out.write((char*)&id, sizeof(id));
|
||||||
|
if(item->isStackable() || item->isFluidContainer() || item->isFluid()) {
|
||||||
|
uint8 data = item->getData();
|
||||||
|
out.write((char*)&data, sizeof(data));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
id = 0xFFFF;
|
id = 0xFFFF;
|
||||||
|
@ -121,7 +131,7 @@ void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos)
|
||||||
tile->addThing(thing, stackPos);
|
tile->addThing(thing, stackPos);
|
||||||
|
|
||||||
// creature teleported
|
// creature teleported
|
||||||
if(oldPos.isValid() && !oldPos.isInRange(pos,1,1,0))
|
if(oldPos.isValid() && !oldPos.isInRange(pos,1,1))
|
||||||
g_game.processCreatureTeleport(creature);
|
g_game.processCreatureTeleport(creature);
|
||||||
} else if(MissilePtr missile = thing->asMissile()) {
|
} else if(MissilePtr missile = thing->asMissile()) {
|
||||||
m_floorMissiles[pos.z].push_back(missile);
|
m_floorMissiles[pos.z].push_back(missile);
|
||||||
|
@ -235,6 +245,36 @@ void Map::removeCreatureById(uint32 id)
|
||||||
m_knownCreatures.erase(id);
|
m_knownCreatures.erase(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Map::setCentralPosition(const Position& centralPosition)
|
||||||
|
{
|
||||||
|
bool teleported = !m_centralPosition.isInRange(centralPosition, 1,1);
|
||||||
|
m_centralPosition = centralPosition;
|
||||||
|
|
||||||
|
// remove all creatures when teleporting, the server will resend them again
|
||||||
|
if(teleported) {
|
||||||
|
for(const auto& pair : m_knownCreatures) {
|
||||||
|
const CreaturePtr& creature = pair.second;
|
||||||
|
const TilePtr& tile = creature->getCurrentTile();
|
||||||
|
if(tile) {
|
||||||
|
tile->removeThing(creature);
|
||||||
|
creature->setPosition(Position());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove creatures from tiles that we are not aware anymore
|
||||||
|
} else {
|
||||||
|
for(const auto& pair : m_knownCreatures) {
|
||||||
|
const CreaturePtr& creature = pair.second;
|
||||||
|
if(!isAwareOfPosition(creature->getPosition())) {
|
||||||
|
const TilePtr& tile = creature->getCurrentTile();
|
||||||
|
if(tile) {
|
||||||
|
tile->removeThing(creature);
|
||||||
|
creature->setPosition(Position());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<CreaturePtr> Map::getSpectators(const Position& centerPos, bool multiFloor)
|
std::vector<CreaturePtr> Map::getSpectators(const Position& centerPos, bool multiFloor)
|
||||||
{
|
{
|
||||||
return getSpectatorsInRange(centerPos, multiFloor, (Otc::VISIBLE_X_TILES - 1)/2, (Otc::VISIBLE_Y_TILES - 1)/2);
|
return getSpectatorsInRange(centerPos, multiFloor, (Otc::VISIBLE_X_TILES - 1)/2, (Otc::VISIBLE_Y_TILES - 1)/2);
|
||||||
|
@ -259,7 +299,7 @@ std::vector<CreaturePtr> Map::getSpectatorsInRangeEx(const Position& centerPos,
|
||||||
for(int iz=-minZRange; iz<=maxZRange; ++iz) {
|
for(int iz=-minZRange; iz<=maxZRange; ++iz) {
|
||||||
for(int iy=-minYRange; iy<=maxYRange; ++iy) {
|
for(int iy=-minYRange; iy<=maxYRange; ++iy) {
|
||||||
for(int ix=-minXRange; ix<=maxXRange; ++ix) {
|
for(int ix=-minXRange; ix<=maxXRange; ++ix) {
|
||||||
TilePtr tile = getTile(centerPos + Position(ix,iy,iz));
|
TilePtr tile = getTile(centerPos.translated(ix,iy,iz));
|
||||||
if(!tile)
|
if(!tile)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -282,13 +322,14 @@ bool Map::isCovered(const Position& pos, int firstFloor)
|
||||||
{
|
{
|
||||||
// check for tiles on top of the postion
|
// check for tiles on top of the postion
|
||||||
Position tilePos = pos;
|
Position tilePos = pos;
|
||||||
tilePos.coveredUp();
|
while(tilePos.coveredUp() && tilePos.z >= firstFloor) {
|
||||||
while(tilePos.z >= firstFloor) {
|
|
||||||
TilePtr tile = getTile(tilePos);
|
TilePtr tile = getTile(tilePos);
|
||||||
// the below tile is covered when the above tile has a full ground
|
// the below tile is covered when the above tile has a full ground
|
||||||
if(tile && tile->isFullGround())
|
if(tile && tile->isFullGround())
|
||||||
return true;
|
return true;
|
||||||
tilePos.coveredUp();
|
|
||||||
|
if(tilePos.z == 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -296,8 +337,7 @@ bool Map::isCovered(const Position& pos, int firstFloor)
|
||||||
bool Map::isCompletelyCovered(const Position& pos, int firstFloor)
|
bool Map::isCompletelyCovered(const Position& pos, int firstFloor)
|
||||||
{
|
{
|
||||||
Position tilePos = pos;
|
Position tilePos = pos;
|
||||||
tilePos.coveredUp();
|
while(tilePos.coveredUp() && tilePos.z >= firstFloor) {
|
||||||
while(tilePos.z >= firstFloor) {
|
|
||||||
bool covered = true;
|
bool covered = true;
|
||||||
// check in 2x2 range tiles that has no transparent pixels
|
// check in 2x2 range tiles that has no transparent pixels
|
||||||
for(int x=0;x<2;++x) {
|
for(int x=0;x<2;++x) {
|
||||||
|
@ -311,7 +351,40 @@ bool Map::isCompletelyCovered(const Position& pos, int firstFloor)
|
||||||
}
|
}
|
||||||
if(covered)
|
if(covered)
|
||||||
return true;
|
return true;
|
||||||
tilePos.coveredUp();
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Map::isAwareOfPosition(const Position& pos)
|
||||||
|
{
|
||||||
|
if(pos.z < getFirstAwareFloor() || pos.z > getLastAwareFloor())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Position groundedPos = pos;
|
||||||
|
while(groundedPos.z != m_centralPosition.z) {
|
||||||
|
if(groundedPos.z > m_centralPosition.z)
|
||||||
|
groundedPos.coveredUp();
|
||||||
|
else
|
||||||
|
groundedPos.coveredDown();
|
||||||
|
}
|
||||||
|
return m_centralPosition.isInRange(groundedPos, Otc::AWARE_X_LEFT_TILES,
|
||||||
|
Otc::AWARE_X_RIGHT_TILES,
|
||||||
|
Otc::AWARE_Y_TOP_TILES,
|
||||||
|
Otc::AWARE_Y_BOTTOM_TILES);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Map::getFirstAwareFloor()
|
||||||
|
{
|
||||||
|
if(m_centralPosition.z > Otc::SEA_FLOOR)
|
||||||
|
return m_centralPosition.z-2;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Map::getLastAwareFloor()
|
||||||
|
{
|
||||||
|
if(m_centralPosition.z > Otc::SEA_FLOOR)
|
||||||
|
return std::min(m_centralPosition.z+2, (int)Otc::MAX_Z);
|
||||||
|
else
|
||||||
|
return Otc::SEA_FLOOR;
|
||||||
|
}
|
||||||
|
|
|
@ -58,14 +58,17 @@ public:
|
||||||
std::vector<CreaturePtr> getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange);
|
std::vector<CreaturePtr> getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange);
|
||||||
|
|
||||||
void setLight(const Light& light) { m_light = light; }
|
void setLight(const Light& light) { m_light = light; }
|
||||||
void setCentralPosition(const Position& centralPosition) { m_centralPosition = centralPosition; }
|
void setCentralPosition(const Position& centralPosition);
|
||||||
|
|
||||||
bool isLookPossible(const Position& pos);
|
bool isLookPossible(const Position& pos);
|
||||||
bool isCovered(const Position& pos, int firstFloor = 0);
|
bool isCovered(const Position& pos, int firstFloor = 0);
|
||||||
bool isCompletelyCovered(const Position& pos, int firstFloor = 0);
|
bool isCompletelyCovered(const Position& pos, int firstFloor = 0);
|
||||||
|
bool isAwareOfPosition(const Position& pos);
|
||||||
|
|
||||||
Light getLight() { return m_light; }
|
Light getLight() { return m_light; }
|
||||||
Position getCentralPosition() { return m_centralPosition; }
|
Position getCentralPosition() { return m_centralPosition; }
|
||||||
|
int getFirstAwareFloor();
|
||||||
|
int getLastAwareFloor();
|
||||||
|
|
||||||
|
|
||||||
std::vector<AnimatedTextPtr> getAnimatedTexts() { return m_animatedTexts; }
|
std::vector<AnimatedTextPtr> getAnimatedTexts() { return m_animatedTexts; }
|
||||||
|
|
|
@ -45,6 +45,7 @@ MapView::MapView()
|
||||||
m_shaderProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
|
m_shaderProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
|
||||||
m_shaderProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/map.frag");
|
m_shaderProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/map.frag");
|
||||||
assert(m_shaderProgram->link());
|
assert(m_shaderProgram->link());
|
||||||
|
//m_animated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::draw(const Rect& rect)
|
void MapView::draw(const Rect& rect)
|
||||||
|
@ -55,10 +56,26 @@ void MapView::draw(const Rect& rect)
|
||||||
float scaleFactor = m_tileSize/(float)Otc::TILE_PIXELS;
|
float scaleFactor = m_tileSize/(float)Otc::TILE_PIXELS;
|
||||||
Position cameraPosition = getCameraPosition();
|
Position cameraPosition = getCameraPosition();
|
||||||
|
|
||||||
if(updated || m_animated) {
|
int tileDrawFlags = 0;
|
||||||
|
if(isNearView())
|
||||||
|
tileDrawFlags = Otc::DrawGround | Otc::DrawWalls | Otc::DrawCommonItems | Otc::DrawCreatures | Otc::DrawEffects;
|
||||||
|
else if(isMidView())
|
||||||
|
tileDrawFlags = Otc::DrawGround | Otc::DrawWalls | Otc::DrawCommonItems;
|
||||||
|
else if(isFarView())
|
||||||
|
tileDrawFlags = Otc::DrawGround | Otc::DrawWalls;
|
||||||
|
else // huge far view
|
||||||
|
tileDrawFlags = Otc::DrawGround;
|
||||||
|
|
||||||
|
bool animate = m_animated;
|
||||||
|
|
||||||
|
// avoid animation of mid/far views
|
||||||
|
if(!isNearView())
|
||||||
|
animate = false;
|
||||||
|
|
||||||
|
if(updated || animate) {
|
||||||
m_framebuffer->bind();
|
m_framebuffer->bind();
|
||||||
for(const TilePtr& tile : m_cachedVisibleTiles) {
|
for(const TilePtr& tile : m_cachedVisibleTiles) {
|
||||||
tile->draw(transformPositionTo2D(tile->getPosition()), scaleFactor);
|
tile->draw(transformPositionTo2D(tile->getPosition()), scaleFactor, tileDrawFlags);
|
||||||
//TODO: restore missiles
|
//TODO: restore missiles
|
||||||
}
|
}
|
||||||
m_framebuffer->generateMipmaps();
|
m_framebuffer->generateMipmaps();
|
||||||
|
@ -128,6 +145,12 @@ void MapView::draw(const Rect& rect)
|
||||||
animatedText->draw(p, rect);
|
animatedText->draw(p, rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// draw a arrow for position the center in non near views
|
||||||
|
if(!isNearView()) {
|
||||||
|
g_painter.setColor(Fw::red);
|
||||||
|
g_painter.drawFilledRect(Rect(rect.center(), 4, 4));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MapView::updateVisibleTilesCache()
|
bool MapView::updateVisibleTilesCache()
|
||||||
|
@ -159,10 +182,10 @@ bool MapView::updateVisibleTilesCache()
|
||||||
// loop through / diagonal tiles
|
// loop through / diagonal tiles
|
||||||
for(int ix = std::min(diagonal, m_drawDimension.width() - 1), iy = std::max(diagonal - m_drawDimension.width() + 1, 0); ix >= 0 && iy < m_drawDimension.height(); --ix, ++iy) {
|
for(int ix = std::min(diagonal, m_drawDimension.width() - 1), iy = std::max(diagonal - m_drawDimension.width() + 1, 0); ix >= 0 && iy < m_drawDimension.height(); --ix, ++iy) {
|
||||||
// position on current floor
|
// position on current floor
|
||||||
Position tilePos(cameraPosition.x + (ix - m_virtualCenterOffset.x), cameraPosition.y + (iy - m_virtualCenterOffset.y), cameraPosition.z);
|
Position tilePos = cameraPosition.translated(ix - m_virtualCenterOffset.x, iy - m_virtualCenterOffset.y);
|
||||||
// adjust tilePos to the wanted floor
|
// adjust tilePos to the wanted floor
|
||||||
tilePos.coveredUp(cameraPosition.z - iz);
|
tilePos.coveredUp(cameraPosition.z - iz);
|
||||||
if(TilePtr tile = g_map.getTile(tilePos)) {
|
if(const TilePtr& tile = g_map.getTile(tilePos)) {
|
||||||
// skip tiles that have nothing
|
// skip tiles that have nothing
|
||||||
if(tile->getThingCount() == 0)
|
if(tile->getThingCount() == 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -257,28 +280,30 @@ int MapView::getFirstVisibleFloor()
|
||||||
if(m_lockedFirstVisibleFloor != -1)
|
if(m_lockedFirstVisibleFloor != -1)
|
||||||
return m_lockedFirstVisibleFloor;
|
return m_lockedFirstVisibleFloor;
|
||||||
|
|
||||||
// if nothing is limiting the view, the first visible floor is 0
|
|
||||||
int firstFloor = 0;
|
|
||||||
Position cameraPosition = getCameraPosition();
|
Position cameraPosition = getCameraPosition();
|
||||||
|
|
||||||
|
// avoid rendering multile floors on far views
|
||||||
|
if(!isNearView())
|
||||||
|
return cameraPosition.z;
|
||||||
|
|
||||||
|
// if nothing is limiting the view, the first visible floor is 0
|
||||||
|
int firstFloor = 0;
|
||||||
|
|
||||||
// limits to underground floors while under sea level
|
// limits to underground floors while under sea level
|
||||||
if(cameraPosition.z > Otc::SEA_LEVEL)
|
if(cameraPosition.z > Otc::SEA_FLOOR)
|
||||||
firstFloor = Otc::SEA_LEVEL+1;
|
firstFloor = Otc::SEA_FLOOR+1;
|
||||||
|
|
||||||
// loop in 3x3 tiles around the camera
|
// loop in 3x3 tiles around the camera
|
||||||
for(int ix = -1; ix <= 1 && firstFloor < cameraPosition.z; ++ix) {
|
for(int ix = -1; ix <= 1 && firstFloor < cameraPosition.z; ++ix) {
|
||||||
for(int iy = -1; iy <= 1 && firstFloor < cameraPosition.z; ++iy) {
|
for(int iy = -1; iy <= 1 && firstFloor < cameraPosition.z; ++iy) {
|
||||||
Position pos(cameraPosition.x + ix, cameraPosition.y + iy, cameraPosition.z);
|
Position pos = cameraPosition.translated(ix, iy);
|
||||||
|
|
||||||
// process tiles that we can look through, e.g. windows, doors
|
// process tiles that we can look through, e.g. windows, doors
|
||||||
if((ix == 0 && iy == 0) || g_map.isLookPossible(pos)) {
|
if((ix == 0 && iy == 0) || g_map.isLookPossible(pos)) {
|
||||||
Position upperPos = pos;
|
Position upperPos = pos;
|
||||||
Position coveredPos = pos;
|
Position coveredPos = pos;
|
||||||
|
|
||||||
coveredPos.coveredUp();
|
while(coveredPos.coveredUp() && upperPos.up() && upperPos.z >= firstFloor) {
|
||||||
upperPos.up();
|
|
||||||
|
|
||||||
while(upperPos.z >= firstFloor) {
|
|
||||||
// check tiles physically above
|
// check tiles physically above
|
||||||
TilePtr tile = g_map.getTile(upperPos);
|
TilePtr tile = g_map.getTile(upperPos);
|
||||||
if(tile && tile->limitsFloorsView()) {
|
if(tile && tile->limitsFloorsView()) {
|
||||||
|
@ -293,8 +318,8 @@ int MapView::getFirstVisibleFloor()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
coveredPos.coveredUp();
|
if(upperPos.z == 0)
|
||||||
upperPos.up();
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,11 +332,15 @@ int MapView::getLastVisibleFloor()
|
||||||
{
|
{
|
||||||
Position cameraPosition = getCameraPosition();
|
Position cameraPosition = getCameraPosition();
|
||||||
|
|
||||||
|
// avoid rendering multile floors on far views
|
||||||
|
if(!isNearView())
|
||||||
|
return cameraPosition.z;
|
||||||
|
|
||||||
// view only underground floors when below sea level
|
// view only underground floors when below sea level
|
||||||
if(cameraPosition.z > Otc::SEA_LEVEL)
|
if(cameraPosition.z > Otc::SEA_FLOOR)
|
||||||
return Otc::MAX_Z;
|
return Otc::MAX_Z;
|
||||||
else
|
else
|
||||||
return Otc::SEA_LEVEL;
|
return Otc::SEA_FLOOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
Position MapView::getCameraPosition()
|
Position MapView::getCameraPosition()
|
||||||
|
|
|
@ -30,12 +30,14 @@
|
||||||
class MapView : public LuaObject
|
class MapView : public LuaObject
|
||||||
{
|
{
|
||||||
enum {
|
enum {
|
||||||
DEFAULT_FRAMBUFFER_SIZE = 2048
|
DEFAULT_FRAMBUFFER_SIZE = 2048,
|
||||||
|
NEAR_VIEW_AREA = 4096,
|
||||||
|
MID_VIEW_AREA = 16384,
|
||||||
|
FAR_VIEW_AREA = 32768
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MapView();
|
MapView();
|
||||||
|
|
||||||
void draw(const Rect& rect);
|
void draw(const Rect& rect);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -69,6 +71,10 @@ public:
|
||||||
Size getVisibleSize() { return m_visibleDimension * m_tileSize; }
|
Size getVisibleSize() { return m_visibleDimension * m_tileSize; }
|
||||||
CreaturePtr getFollowingCreature() { return m_followingCreature; }
|
CreaturePtr getFollowingCreature() { return m_followingCreature; }
|
||||||
|
|
||||||
|
bool isNearView() { return m_drawDimension.area() <= NEAR_VIEW_AREA; }
|
||||||
|
bool isMidView() { return m_drawDimension.area() > NEAR_VIEW_AREA && m_drawDimension.area() <= MID_VIEW_AREA; }
|
||||||
|
bool isFarView() { return m_drawDimension.area() > MID_VIEW_AREA && m_drawDimension.area() <= FAR_VIEW_AREA; }
|
||||||
|
bool isHugeFarView() { return m_drawDimension.area() > FAR_VIEW_AREA; }
|
||||||
bool isAnimated() { return m_animated; }
|
bool isAnimated() { return m_animated; }
|
||||||
|
|
||||||
Point transformPositionTo2D(const Position& position);
|
Point transformPositionTo2D(const Position& position);
|
||||||
|
|
|
@ -35,7 +35,7 @@ Missile::Missile() : Thing()
|
||||||
void Missile::draw(const Point& p, const Rect&)
|
void Missile::draw(const Point& p, const Rect&)
|
||||||
{
|
{
|
||||||
float time = (g_clock.ticks() - m_startTicks) / m_duration;
|
float time = (g_clock.ticks() - m_startTicks) / m_duration;
|
||||||
//internalDraw(p + Point(m_positionDelta.x * time, m_positionDelta.y * time), 0);
|
//internalDraw(p + Point(m_deltax * time, m_deltay * time), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Missile::setPath(const Position& fromPosition, const Position& toPosition)
|
void Missile::setPath(const Position& fromPosition, const Position& toPosition)
|
||||||
|
@ -80,11 +80,12 @@ void Missile::setPath(const Position& fromPosition, const Position& toPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_position = fromPosition;
|
m_position = fromPosition;
|
||||||
m_positionDelta = toPosition - fromPosition;
|
m_deltax = toPosition.x - fromPosition.x;
|
||||||
|
m_deltay = toPosition.y - fromPosition.y;
|
||||||
m_startTicks = g_clock.ticks();
|
m_startTicks = g_clock.ticks();
|
||||||
m_duration = 150 * std::sqrt(Point(m_positionDelta.x, m_positionDelta.y).length());
|
m_duration = 150 * std::sqrt(Point(m_deltax, m_deltay).length());
|
||||||
m_positionDelta.x *= Otc::TILE_PIXELS;
|
m_deltax *= Otc::TILE_PIXELS;
|
||||||
m_positionDelta.y *= Otc::TILE_PIXELS;
|
m_deltay *= Otc::TILE_PIXELS;
|
||||||
|
|
||||||
// schedule removal
|
// schedule removal
|
||||||
auto self = asMissile();
|
auto self = asMissile();
|
||||||
|
|
|
@ -47,7 +47,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ticks_t m_startTicks;
|
ticks_t m_startTicks;
|
||||||
Position m_positionDelta;
|
int m_deltax;
|
||||||
|
int m_deltay;
|
||||||
float m_duration;
|
float m_duration;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ protected:
|
||||||
|
|
||||||
uint32 m_id;
|
uint32 m_id;
|
||||||
Position m_position;
|
Position m_position;
|
||||||
int m_xPattern, m_yPattern, m_zPattern, m_animation;
|
uint8 m_xPattern, m_yPattern, m_zPattern, m_animation;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ThingType *m_type;
|
ThingType *m_type;
|
||||||
|
|
|
@ -36,22 +36,27 @@ Tile::Tile(const Position& position)
|
||||||
m_position = position;
|
m_position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tile::draw(const Point& dest, float scaleFactor)
|
void Tile::draw(const Point& dest, float scaleFactor, int drawFlags)
|
||||||
{
|
{
|
||||||
m_drawElevation = 0;
|
m_drawElevation = 0;
|
||||||
|
|
||||||
// first bottom items
|
// first bottom items
|
||||||
|
if(drawFlags & Otc::DrawGround || drawFlags & Otc::DrawWalls) {
|
||||||
for(const ThingPtr& thing : m_things) {
|
for(const ThingPtr& thing : m_things) {
|
||||||
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom())
|
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if((drawFlags & Otc::DrawGround && thing->isGround()) || (drawFlags & Otc::DrawWalls))
|
||||||
thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor);
|
thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor);
|
||||||
|
|
||||||
m_drawElevation += thing->getElevation();
|
m_drawElevation += thing->getElevation();
|
||||||
if(m_drawElevation > Otc::MAX_ELEVATION)
|
if(m_drawElevation > Otc::MAX_ELEVATION)
|
||||||
m_drawElevation = Otc::MAX_ELEVATION;
|
m_drawElevation = Otc::MAX_ELEVATION;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// now common items in reverse order
|
// now common items in reverse order
|
||||||
|
if(drawFlags & Otc::DrawCommonItems) {
|
||||||
for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
|
for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
|
||||||
const ThingPtr& thing = *it;
|
const ThingPtr& thing = *it;
|
||||||
if(thing->asCreature() || thing->isOnTop() || thing->isOnBottom() || thing->isGroundBorder() || thing->isGround())
|
if(thing->asCreature() || thing->isOnTop() || thing->isOnBottom() || thing->isGroundBorder() || thing->isGround())
|
||||||
|
@ -62,11 +67,13 @@ void Tile::draw(const Point& dest, float scaleFactor)
|
||||||
if(m_drawElevation > Otc::MAX_ELEVATION)
|
if(m_drawElevation > Otc::MAX_ELEVATION)
|
||||||
m_drawElevation = Otc::MAX_ELEVATION;
|
m_drawElevation = Otc::MAX_ELEVATION;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// we can render creatures in 3x3 range
|
// we can render creatures in 3x3 range
|
||||||
|
if(drawFlags & Otc::DrawCreatures) {
|
||||||
for(int xi = -1; xi <= 1; ++xi) {
|
for(int xi = -1; xi <= 1; ++xi) {
|
||||||
for(int yi = -1; yi <= 1; ++yi) {
|
for(int yi = -1; yi <= 1; ++yi) {
|
||||||
const TilePtr& tile = g_map.getTile(m_position + Position(xi, yi, 0));
|
const TilePtr& tile = g_map.getTile(m_position.translated(xi, yi, 0));
|
||||||
if(!tile)
|
if(!tile)
|
||||||
continue;
|
continue;
|
||||||
for(const CreaturePtr& creature : tile->getCreatures()) {
|
for(const CreaturePtr& creature : tile->getCreatures()) {
|
||||||
|
@ -84,17 +91,22 @@ void Tile::draw(const Point& dest, float scaleFactor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// effects
|
// effects
|
||||||
|
if(drawFlags & Otc::DrawEffects) {
|
||||||
for(const EffectPtr& effect : m_effects)
|
for(const EffectPtr& effect : m_effects)
|
||||||
effect->draw(dest, scaleFactor);
|
effect->draw(dest, scaleFactor);
|
||||||
|
}
|
||||||
|
|
||||||
// top items
|
// top items
|
||||||
|
if(drawFlags & Otc::DrawWalls) {
|
||||||
for(const ThingPtr& thing : m_things) {
|
for(const ThingPtr& thing : m_things) {
|
||||||
if(thing->isOnTop())
|
if(thing->isOnTop())
|
||||||
thing->draw(dest - m_drawElevation, scaleFactor);
|
thing->draw(dest - m_drawElevation, scaleFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Tile::clean()
|
void Tile::clean()
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,7 +31,7 @@ class Tile : public LuaObject
|
||||||
public:
|
public:
|
||||||
Tile(const Position& position);
|
Tile(const Position& position);
|
||||||
|
|
||||||
void draw(const Point& dest, float scaleFactor);
|
void draw(const Point& dest, float scaleFactor, int drawFlags);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateVisibleItemsCache();
|
void updateVisibleItemsCache();
|
||||||
|
|
|
@ -317,7 +317,7 @@ void ProtocolGame::parseMapDescription(InputMessage& msg)
|
||||||
{
|
{
|
||||||
Position pos = parsePosition(msg);
|
Position pos = parsePosition(msg);
|
||||||
g_map.setCentralPosition(pos);
|
g_map.setCentralPosition(pos);
|
||||||
setMapDescription(msg, pos.x - 8, pos.y - 6, pos.z, 18, 14);
|
setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseMoveNorth(InputMessage& msg)
|
void ProtocolGame::parseMoveNorth(InputMessage& msg)
|
||||||
|
@ -325,7 +325,7 @@ void ProtocolGame::parseMoveNorth(InputMessage& msg)
|
||||||
Position pos = g_map.getCentralPosition();
|
Position pos = g_map.getCentralPosition();
|
||||||
pos.y--;
|
pos.y--;
|
||||||
|
|
||||||
setMapDescription(msg, pos.x - 8, pos.y - 6, pos.z, 18, 1);
|
setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, Otc::AWARE_X_TILES, 1);
|
||||||
g_map.setCentralPosition(pos);
|
g_map.setCentralPosition(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +334,7 @@ void ProtocolGame::parseMoveEast(InputMessage& msg)
|
||||||
Position pos = g_map.getCentralPosition();
|
Position pos = g_map.getCentralPosition();
|
||||||
pos.x++;
|
pos.x++;
|
||||||
|
|
||||||
setMapDescription(msg, pos.x + 9, pos.y - 6, pos.z, 1, 14);
|
setMapDescription(msg, pos.x + Otc::AWARE_X_RIGHT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, 1, Otc::AWARE_Y_TILES);
|
||||||
g_map.setCentralPosition(pos);
|
g_map.setCentralPosition(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +343,7 @@ void ProtocolGame::parseMoveSouth(InputMessage& msg)
|
||||||
Position pos = g_map.getCentralPosition();
|
Position pos = g_map.getCentralPosition();
|
||||||
pos.y++;
|
pos.y++;
|
||||||
|
|
||||||
setMapDescription(msg, pos.x - 8, pos.y + 7, pos.z, 18, 1);
|
setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y + Otc::AWARE_Y_BOTTOM_TILES, pos.z, Otc::AWARE_X_TILES, 1);
|
||||||
g_map.setCentralPosition(pos);
|
g_map.setCentralPosition(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ void ProtocolGame::parseMoveWest(InputMessage& msg)
|
||||||
Position pos = g_map.getCentralPosition();
|
Position pos = g_map.getCentralPosition();
|
||||||
pos.x--;
|
pos.x--;
|
||||||
|
|
||||||
setMapDescription(msg, pos.x - 8, pos.y - 6, pos.z, 1, 14);
|
setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, 1, Otc::AWARE_Y_TILES);
|
||||||
g_map.setCentralPosition(pos);
|
g_map.setCentralPosition(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -819,11 +819,11 @@ void ProtocolGame::parseFloorChangeUp(InputMessage& msg)
|
||||||
pos.z--;
|
pos.z--;
|
||||||
|
|
||||||
int skip = 0;
|
int skip = 0;
|
||||||
if(pos.z == 7)
|
if(pos.z == Otc::SEA_FLOOR)
|
||||||
for(int i = 5; i >= 0; i--)
|
for(int i = Otc::SEA_FLOOR - Otc::AWARE_UNDEGROUND_FLOOR_RANGE; i >= 0; i--)
|
||||||
setFloorDescription(msg, pos.x - 8, pos.y - 6, i, 18, 14, 8 - i, &skip);
|
setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, i, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, 8 - i, &skip);
|
||||||
else if(pos.z > 7)
|
else if(pos.z > Otc::SEA_FLOOR)
|
||||||
setFloorDescription(msg, pos.x - 8, pos.y - 6, pos.z - 2, 18, 14, 3, &skip);
|
setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, 3, &skip);
|
||||||
|
|
||||||
pos.x++;
|
pos.x++;
|
||||||
pos.y++;
|
pos.y++;
|
||||||
|
@ -836,13 +836,13 @@ void ProtocolGame::parseFloorChangeDown(InputMessage& msg)
|
||||||
pos.z++;
|
pos.z++;
|
||||||
|
|
||||||
int skip = 0;
|
int skip = 0;
|
||||||
if(pos.z == 8) {
|
if(pos.z == Otc::UNDERGROUND_FLOOR) {
|
||||||
int j, i;
|
int j, i;
|
||||||
for(i = pos.z, j = -1; i < pos.z + 3; ++i, --j)
|
for(i = pos.z, j = -1; i <= pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE; ++i, --j)
|
||||||
setFloorDescription(msg, pos.x - 8, pos.y - 6, i, 18, 14, j, &skip);
|
setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, i, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, j, &skip);
|
||||||
}
|
}
|
||||||
else if(pos.z > 8 && pos.z < 14)
|
else if(pos.z > Otc::UNDERGROUND_FLOOR && pos.z < Otc::MAX_Z-1)
|
||||||
setFloorDescription(msg, pos.x - 8, pos.y - 6, pos.z + 2, 18, 14, -3, &skip);
|
setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, -3, &skip);
|
||||||
|
|
||||||
pos.x--;
|
pos.x--;
|
||||||
pos.y--;
|
pos.y--;
|
||||||
|
@ -931,13 +931,13 @@ void ProtocolGame::setMapDescription(InputMessage& msg, int32 x, int32 y, int32
|
||||||
{
|
{
|
||||||
int startz, endz, zstep, skip = 0;
|
int startz, endz, zstep, skip = 0;
|
||||||
|
|
||||||
if(z > 7) {
|
if(z > Otc::SEA_FLOOR) {
|
||||||
startz = z - 2;
|
startz = z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
|
||||||
endz = (15 < z+2) ? 15 : z+2;
|
endz = std::min(z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::MAX_Z);
|
||||||
zstep = 1;
|
zstep = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
startz = 7;
|
startz = Otc::SEA_FLOOR;
|
||||||
endz = 0;
|
endz = 0;
|
||||||
zstep = -1;
|
zstep = -1;
|
||||||
}
|
}
|
||||||
|
@ -952,13 +952,17 @@ void ProtocolGame::setFloorDescription(InputMessage& msg, int32 x, int32 y, int3
|
||||||
|
|
||||||
for(int nx = 0; nx < width; nx++) {
|
for(int nx = 0; nx < width; nx++) {
|
||||||
for(int ny = 0; ny < height; ny++) {
|
for(int ny = 0; ny < height; ny++) {
|
||||||
|
Position tilePos(x + nx + offset, y + ny + offset, z);
|
||||||
|
|
||||||
|
// clean pre stored tiles
|
||||||
|
g_map.cleanTile(tilePos);
|
||||||
|
|
||||||
if(skip == 0) {
|
if(skip == 0) {
|
||||||
int tileOpt = msg.getU16(true);
|
int tileOpt = msg.getU16(true);
|
||||||
if(tileOpt >= 0xFF00)
|
if(tileOpt >= 0xFF00)
|
||||||
skip = (msg.getU16() & 0xFF);
|
skip = (msg.getU16() & 0xFF);
|
||||||
else {
|
else {
|
||||||
Position pos(x + nx + offset, y + ny + offset, z);
|
setTileDescription(msg, tilePos);
|
||||||
setTileDescription(msg, pos);
|
|
||||||
skip = (msg.getU16() & 0xFF);
|
skip = (msg.getU16() & 0xFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,51 +30,99 @@
|
||||||
class Position
|
class Position
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Position() : x(-1), y(-1), z(-1) { }
|
Position() : x(65535), y(65535), z(255) { }
|
||||||
Position(int x, int y, int z) : x(x), y(y), z(z) { }
|
Position(uint16 x, uint16 y, uint8 z) : x(x), y(y), z(z) { }
|
||||||
|
|
||||||
static Position getPositionFromDirection(Otc::Direction direction) {
|
Position translatedToDirection(Otc::Direction direction) {
|
||||||
|
Position pos = *this;
|
||||||
switch(direction) {
|
switch(direction) {
|
||||||
case Otc::North:
|
case Otc::North:
|
||||||
return Position( 0, -1, 0);
|
pos.y--;
|
||||||
|
break;
|
||||||
case Otc::East:
|
case Otc::East:
|
||||||
return Position( 1, 0, 0);
|
pos.x++;
|
||||||
|
break;
|
||||||
case Otc::South:
|
case Otc::South:
|
||||||
return Position( 0, 1, 0);
|
pos.y++;
|
||||||
|
break;
|
||||||
case Otc::West:
|
case Otc::West:
|
||||||
return Position(-1, 0, 0);
|
pos.x--;
|
||||||
|
break;
|
||||||
case Otc::NorthEast:
|
case Otc::NorthEast:
|
||||||
return Position( 1, -1, 0);
|
pos.x++;
|
||||||
|
pos.y--;
|
||||||
|
break;
|
||||||
case Otc::SouthEast:
|
case Otc::SouthEast:
|
||||||
return Position( 1, 1, 0);
|
pos.x++;
|
||||||
|
pos.y++;
|
||||||
|
break;
|
||||||
case Otc::SouthWest:
|
case Otc::SouthWest:
|
||||||
return Position(-1, 1, 0);
|
pos.x--;
|
||||||
|
pos.y++;
|
||||||
|
break;
|
||||||
case Otc::NorthWest:
|
case Otc::NorthWest:
|
||||||
return Position(-1, -1, 0);
|
pos.x--;
|
||||||
default:
|
pos.y--;
|
||||||
return Position();
|
break;
|
||||||
}
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
Position translatedToReverseDirection(Otc::Direction direction) {
|
||||||
|
Position pos = *this;
|
||||||
|
switch(direction) {
|
||||||
|
case Otc::North:
|
||||||
|
pos.y++;
|
||||||
|
break;
|
||||||
|
case Otc::East:
|
||||||
|
pos.x--;
|
||||||
|
break;
|
||||||
|
case Otc::South:
|
||||||
|
pos.y--;
|
||||||
|
break;
|
||||||
|
case Otc::West:
|
||||||
|
pos.x++;
|
||||||
|
break;
|
||||||
|
case Otc::NorthEast:
|
||||||
|
pos.x--;
|
||||||
|
pos.y++;
|
||||||
|
break;
|
||||||
|
case Otc::SouthEast:
|
||||||
|
pos.x--;
|
||||||
|
pos.y--;
|
||||||
|
break;
|
||||||
|
case Otc::SouthWest:
|
||||||
|
pos.x++;
|
||||||
|
pos.y--;
|
||||||
|
break;
|
||||||
|
case Otc::NorthWest:
|
||||||
|
pos.x++;
|
||||||
|
pos.y++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
Otc::Direction getDirectionFromPosition(const Position& position) const {
|
Otc::Direction getDirectionFromPosition(const Position& position) const {
|
||||||
Position positionDelta = position - *this;
|
int dx = position.x - x;
|
||||||
|
int dy = position.y - y;
|
||||||
|
|
||||||
if(positionDelta.x == 0 && positionDelta.y == 0)
|
if(dx == 0 && dy == 0)
|
||||||
return Otc::InvalidDirection;
|
return Otc::InvalidDirection;
|
||||||
else if(positionDelta.x == 0) {
|
else if(dx == 0) {
|
||||||
if(positionDelta.y < 0)
|
if(dy < 0)
|
||||||
return Otc::North;
|
return Otc::North;
|
||||||
else if(positionDelta.y > 0)
|
else if(dy > 0)
|
||||||
return Otc::South;
|
return Otc::South;
|
||||||
}
|
}
|
||||||
else if(positionDelta.y == 0) {
|
else if(dy == 0) {
|
||||||
if(positionDelta.x < 0)
|
if(dx < 0)
|
||||||
return Otc::West;
|
return Otc::West;
|
||||||
else if(positionDelta.x > 0)
|
else if(dx > 0)
|
||||||
return Otc::East;
|
return Otc::East;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
float angle = std::atan2(positionDelta.y * -1, positionDelta.x) * RAD_TO_DEC;
|
float angle = std::atan2(dy * -1, dx) * RAD_TO_DEC;
|
||||||
if(angle < 0)
|
if(angle < 0)
|
||||||
angle += 360;
|
angle += 360;
|
||||||
|
|
||||||
|
@ -98,7 +146,10 @@ public:
|
||||||
return Otc::InvalidDirection;
|
return Otc::InvalidDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isValid() const { return x >= 0 && y >= 0 && z >= 0 && x <= 65535 && y <= 65535 && z <= 15; }
|
bool isValid() const { return !(x == 65535 && y == 65535 && z == 255); }
|
||||||
|
|
||||||
|
void translate(int dx, int dy, short dz = 0) { x += dx; y += dy; z += dz; }
|
||||||
|
Position translated(int dx, int dy, short dz = 0) const { Position pos = *this; pos.x += dx; pos.y += dy; pos.z += dz; return pos; }
|
||||||
|
|
||||||
Position operator+(const Position& other) const { return Position(x + other.x, y + other.y, z + other.z); }
|
Position operator+(const Position& other) const { return Position(x + other.x, y + other.y, z + other.z); }
|
||||||
Position& operator+=(const Position& other) { x+=other.x; y+=other.y; z +=other.z; return *this; }
|
Position& operator+=(const Position& other) { x+=other.x; y+=other.y; z +=other.z; return *this; }
|
||||||
|
@ -109,19 +160,50 @@ public:
|
||||||
bool operator==(const Position& other) const { return other.x == x && other.y == y && other.z == z; }
|
bool operator==(const Position& other) const { return other.x == x && other.y == y && other.z == z; }
|
||||||
bool operator!=(const Position& other) const { return other.x!=x || other.y!=y || other.z!=z; }
|
bool operator!=(const Position& other) const { return other.x!=x || other.y!=y || other.z!=z; }
|
||||||
|
|
||||||
bool isInRange(const Position& pos, int xdif, int ydif, int zdif = 1) const {
|
bool isInRange(const Position& pos, int xRange, int yRange) const { return std::abs(x-pos.x) <= xRange && std::abs(y-pos.y) <= yRange; }
|
||||||
return std::abs(x-pos.x) <= xdif && std::abs(y-pos.y) <= ydif && std::abs(pos.z-z) <= zdif;
|
bool isInRange(const Position& pos, int minXRange, int maxXRange, int minYRange, int maxYRange) const {
|
||||||
|
return (pos.x >= x-minXRange && pos.x <= x+maxXRange && pos.y >= y-minYRange && pos.y <= y+maxYRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
void up(int n = 1) { z-=n; }
|
bool up(int n = 1) {
|
||||||
void down(int n = 1) { z+=n; }
|
int nz = z-n;
|
||||||
|
if(nz >= 0 && nz <= Otc::MAX_Z) {
|
||||||
|
z = nz;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void coveredUp(int n = 1) { x+=n; y+=n; z-=n; }
|
bool down(int n = 1) {
|
||||||
void coveredDown(int n = 1) { x-=n; y-=n; z+=n; }
|
int nz = z+n;
|
||||||
|
if(nz >= 0 && nz <= Otc::MAX_Z) {
|
||||||
|
z = nz;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int x;
|
bool coveredUp(int n = 1) {
|
||||||
int y;
|
int nx = x+n, ny = y+n, nz = z-n;
|
||||||
int z;
|
if(nx >= 0 && nx <= 65535 && ny >= 0 && ny <= 65535 && nz >= 0 && nz <= Otc::MAX_Z) {
|
||||||
|
x = nx; y = ny; z = nz;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool coveredDown(int n = 1) {
|
||||||
|
int nx = x-n, ny = y-n, nz = z+n;
|
||||||
|
if(nx >= 0 && nx <= 65535 && ny >= 0 && ny <= 65535 && nz >= 0 && nz <= Otc::MAX_Z) {
|
||||||
|
x = nx; y = ny; z = nz;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 x;
|
||||||
|
uint16 y;
|
||||||
|
uint8 z;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PositionHasher : std::unary_function<Position, std::size_t> {
|
struct PositionHasher : std::unary_function<Position, std::size_t> {
|
||||||
|
@ -132,13 +214,17 @@ struct PositionHasher : std::unary_function<Position, std::size_t> {
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& out, const Position& pos)
|
inline std::ostream& operator<<(std::ostream& out, const Position& pos)
|
||||||
{
|
{
|
||||||
out << pos.x << " " << pos.y << " " << pos.z;
|
out << (int)pos.x << " " << (int)pos.y << " " << (int)pos.z;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::istream& operator>>(std::istream& in, Position& pos)
|
inline std::istream& operator>>(std::istream& in, Position& pos)
|
||||||
{
|
{
|
||||||
in >> pos.x >> pos.y >> pos.z;
|
int x, y, z;
|
||||||
|
in >> x >> y >> z;
|
||||||
|
pos.x = x;
|
||||||
|
pos.y = y;
|
||||||
|
pos.z = z;
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue