many changes

This commit is contained in:
Eduardo Bart 2012-01-30 16:18:10 -02:00
parent 437f515e7c
commit cf18b0c36f
16 changed files with 376 additions and 151 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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; }

View File

@ -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()

View File

@ -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);

View File

@ -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();

View File

@ -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;
}; };

View File

@ -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;

View File

@ -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,16 +91,21 @@ 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()

View File

@ -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();

View File

@ -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);
} }
} }

View File

@ -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;
} }