many changes
This commit is contained in:
parent
437f515e7c
commit
cf18b0c36f
|
@ -33,11 +33,21 @@ namespace Otc
|
|||
|
||||
enum {
|
||||
TILE_PIXELS = 32,
|
||||
SEA_LEVEL = 7,
|
||||
MAX_ELEVATION = 24,
|
||||
|
||||
SEA_FLOOR = 7,
|
||||
MAX_Z = 15,
|
||||
UNDERGROUND_FLOOR = SEA_FLOOR+1,
|
||||
VISIBLE_X_TILES = 15,
|
||||
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,
|
||||
ITEM_TICKS_PER_FRAME = 500,
|
||||
ANIMATED_TEXT_DURATION = 1000,
|
||||
|
@ -46,19 +56,19 @@ namespace Otc
|
|||
MAX_STATIC_TEXT_WIDTH = 200,
|
||||
};
|
||||
|
||||
enum MapDrawFlags {
|
||||
MapDrawNonMoveableItems = 1,
|
||||
MapDrawMoveableItems = 2,
|
||||
MapDrawCreatures = 4,
|
||||
MapDrawCreaturesInformation = 8,
|
||||
MapDrawStaticTexts = 16,
|
||||
MapDrawAnimatedTexts = 32,
|
||||
MapDrawEffects = 64,
|
||||
MapDrawMissiles = 128,
|
||||
MapDrawEverything = MapDrawNonMoveableItems | MapDrawMoveableItems |
|
||||
MapDrawCreatures | MapDrawCreaturesInformation |
|
||||
MapDrawStaticTexts | MapDrawAnimatedTexts |
|
||||
MapDrawEffects | MapDrawMissiles
|
||||
enum DrawFlags {
|
||||
DrawGround = 1,
|
||||
DrawWalls = 2,
|
||||
DrawCommonItems = 4,
|
||||
DrawCreatures = 8,
|
||||
DrawEffects = 16,
|
||||
DrawMissiles = 32,
|
||||
DrawCreaturesInformation = 64,
|
||||
DrawStaticTexts = 128,
|
||||
DrawAnimatedTexts = 256,
|
||||
DrawEverything = DrawGround | DrawWalls | DrawCommonItems |
|
||||
DrawCreatures | DrawEffects | DrawMissiles |
|
||||
DrawCreaturesInformation | DrawStaticTexts | DrawAnimatedTexts
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
// animate walk
|
||||
if(oldPos.isInRange(newPos, 1, 1, 0))
|
||||
if(oldPos.isInRange(newPos, 1, 1))
|
||||
creature->walk(oldPos, newPos);
|
||||
}
|
||||
|
||||
|
@ -246,7 +246,7 @@ void Game::walk(Otc::Direction direction)
|
|||
}*/
|
||||
|
||||
// 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())
|
||||
m_localPlayer->preWalk(direction);
|
||||
else
|
||||
|
|
|
@ -73,7 +73,7 @@ void Item::setPosition(const Position& position)
|
|||
Thing::setPosition(position);
|
||||
}
|
||||
|
||||
void Item::setData(int data)
|
||||
void Item::setData(uint8 data)
|
||||
{
|
||||
if(isStackable() && getNumPatternsX() == 4 && getNumPatternsY() == 2) {
|
||||
if(data < 5) {
|
||||
|
|
|
@ -36,14 +36,14 @@ public:
|
|||
void draw(const Point& dest, float scaleFactor);
|
||||
|
||||
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()); }
|
||||
|
||||
private:
|
||||
int m_data;
|
||||
uint8 m_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -70,7 +70,7 @@ void LocalPlayer::walk(const Position& oldPos, const Position& newPos)
|
|||
void LocalPlayer::preWalk(Otc::Direction direction)
|
||||
{
|
||||
// start walking to direction
|
||||
Position newPos = m_position + Position::getPositionFromDirection(direction);
|
||||
Position newPos = m_position.translatedToDirection(direction);
|
||||
m_preWalking = true;
|
||||
m_lastPrewalkDone = false;
|
||||
m_lastPrewalkDestionation = newPos;
|
||||
|
|
|
@ -67,7 +67,13 @@ void Map::load()
|
|||
uint16 id;
|
||||
in.read((char*)&id, sizeof(id));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +86,7 @@ void Map::save()
|
|||
for(auto& pair : m_tiles) {
|
||||
Position pos = pair.first;
|
||||
TilePtr tile = pair.second;
|
||||
if(!tile)
|
||||
if(!tile || tile->isEmpty())
|
||||
continue;
|
||||
out.write((char*)&pos, sizeof(pos));
|
||||
uint16 id;
|
||||
|
@ -88,6 +94,10 @@ void Map::save()
|
|||
if(ItemPtr item = thing->asItem()) {
|
||||
id = item->getId();
|
||||
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;
|
||||
|
@ -121,7 +131,7 @@ void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos)
|
|||
tile->addThing(thing, stackPos);
|
||||
|
||||
// creature teleported
|
||||
if(oldPos.isValid() && !oldPos.isInRange(pos,1,1,0))
|
||||
if(oldPos.isValid() && !oldPos.isInRange(pos,1,1))
|
||||
g_game.processCreatureTeleport(creature);
|
||||
} else if(MissilePtr missile = thing->asMissile()) {
|
||||
m_floorMissiles[pos.z].push_back(missile);
|
||||
|
@ -235,6 +245,36 @@ void Map::removeCreatureById(uint32 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)
|
||||
{
|
||||
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 iy=-minYRange; iy<=maxYRange; ++iy) {
|
||||
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)
|
||||
continue;
|
||||
|
||||
|
@ -282,13 +322,14 @@ bool Map::isCovered(const Position& pos, int firstFloor)
|
|||
{
|
||||
// check for tiles on top of the postion
|
||||
Position tilePos = pos;
|
||||
tilePos.coveredUp();
|
||||
while(tilePos.z >= firstFloor) {
|
||||
while(tilePos.coveredUp() && tilePos.z >= firstFloor) {
|
||||
TilePtr tile = getTile(tilePos);
|
||||
// the below tile is covered when the above tile has a full ground
|
||||
if(tile && tile->isFullGround())
|
||||
return true;
|
||||
tilePos.coveredUp();
|
||||
|
||||
if(tilePos.z == 0)
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -296,8 +337,7 @@ bool Map::isCovered(const Position& pos, int firstFloor)
|
|||
bool Map::isCompletelyCovered(const Position& pos, int firstFloor)
|
||||
{
|
||||
Position tilePos = pos;
|
||||
tilePos.coveredUp();
|
||||
while(tilePos.z >= firstFloor) {
|
||||
while(tilePos.coveredUp() && tilePos.z >= firstFloor) {
|
||||
bool covered = true;
|
||||
// check in 2x2 range tiles that has no transparent pixels
|
||||
for(int x=0;x<2;++x) {
|
||||
|
@ -311,7 +351,40 @@ bool Map::isCompletelyCovered(const Position& pos, int firstFloor)
|
|||
}
|
||||
if(covered)
|
||||
return true;
|
||||
tilePos.coveredUp();
|
||||
}
|
||||
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);
|
||||
|
||||
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 isCovered(const Position& pos, int firstFloor = 0);
|
||||
bool isCompletelyCovered(const Position& pos, int firstFloor = 0);
|
||||
bool isAwareOfPosition(const Position& pos);
|
||||
|
||||
Light getLight() { return m_light; }
|
||||
Position getCentralPosition() { return m_centralPosition; }
|
||||
int getFirstAwareFloor();
|
||||
int getLastAwareFloor();
|
||||
|
||||
|
||||
std::vector<AnimatedTextPtr> getAnimatedTexts() { return m_animatedTexts; }
|
||||
|
|
|
@ -45,6 +45,7 @@ MapView::MapView()
|
|||
m_shaderProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
|
||||
m_shaderProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/map.frag");
|
||||
assert(m_shaderProgram->link());
|
||||
//m_animated = false;
|
||||
}
|
||||
|
||||
void MapView::draw(const Rect& rect)
|
||||
|
@ -55,10 +56,26 @@ void MapView::draw(const Rect& rect)
|
|||
float scaleFactor = m_tileSize/(float)Otc::TILE_PIXELS;
|
||||
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();
|
||||
for(const TilePtr& tile : m_cachedVisibleTiles) {
|
||||
tile->draw(transformPositionTo2D(tile->getPosition()), scaleFactor);
|
||||
tile->draw(transformPositionTo2D(tile->getPosition()), scaleFactor, tileDrawFlags);
|
||||
//TODO: restore missiles
|
||||
}
|
||||
m_framebuffer->generateMipmaps();
|
||||
|
@ -128,6 +145,12 @@ void MapView::draw(const Rect& 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()
|
||||
|
@ -159,10 +182,10 @@ bool MapView::updateVisibleTilesCache()
|
|||
// 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) {
|
||||
// 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
|
||||
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
|
||||
if(tile->getThingCount() == 0)
|
||||
continue;
|
||||
|
@ -257,28 +280,30 @@ int MapView::getFirstVisibleFloor()
|
|||
if(m_lockedFirstVisibleFloor != -1)
|
||||
return m_lockedFirstVisibleFloor;
|
||||
|
||||
// if nothing is limiting the view, the first visible floor is 0
|
||||
int firstFloor = 0;
|
||||
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
|
||||
if(cameraPosition.z > Otc::SEA_LEVEL)
|
||||
firstFloor = Otc::SEA_LEVEL+1;
|
||||
if(cameraPosition.z > Otc::SEA_FLOOR)
|
||||
firstFloor = Otc::SEA_FLOOR+1;
|
||||
|
||||
// loop in 3x3 tiles around the camera
|
||||
for(int ix = -1; ix <= 1 && firstFloor < cameraPosition.z; ++ix) {
|
||||
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
|
||||
if((ix == 0 && iy == 0) || g_map.isLookPossible(pos)) {
|
||||
Position upperPos = pos;
|
||||
Position coveredPos = pos;
|
||||
|
||||
coveredPos.coveredUp();
|
||||
upperPos.up();
|
||||
|
||||
while(upperPos.z >= firstFloor) {
|
||||
while(coveredPos.coveredUp() && upperPos.up() && upperPos.z >= firstFloor) {
|
||||
// check tiles physically above
|
||||
TilePtr tile = g_map.getTile(upperPos);
|
||||
if(tile && tile->limitsFloorsView()) {
|
||||
|
@ -293,8 +318,8 @@ int MapView::getFirstVisibleFloor()
|
|||
break;
|
||||
}
|
||||
|
||||
coveredPos.coveredUp();
|
||||
upperPos.up();
|
||||
if(upperPos.z == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -307,11 +332,15 @@ int MapView::getLastVisibleFloor()
|
|||
{
|
||||
Position cameraPosition = getCameraPosition();
|
||||
|
||||
// avoid rendering multile floors on far views
|
||||
if(!isNearView())
|
||||
return cameraPosition.z;
|
||||
|
||||
// view only underground floors when below sea level
|
||||
if(cameraPosition.z > Otc::SEA_LEVEL)
|
||||
if(cameraPosition.z > Otc::SEA_FLOOR)
|
||||
return Otc::MAX_Z;
|
||||
else
|
||||
return Otc::SEA_LEVEL;
|
||||
return Otc::SEA_FLOOR;
|
||||
}
|
||||
|
||||
Position MapView::getCameraPosition()
|
||||
|
|
|
@ -30,12 +30,14 @@
|
|||
class MapView : public LuaObject
|
||||
{
|
||||
enum {
|
||||
DEFAULT_FRAMBUFFER_SIZE = 2048
|
||||
DEFAULT_FRAMBUFFER_SIZE = 2048,
|
||||
NEAR_VIEW_AREA = 4096,
|
||||
MID_VIEW_AREA = 16384,
|
||||
FAR_VIEW_AREA = 32768
|
||||
};
|
||||
|
||||
public:
|
||||
MapView();
|
||||
|
||||
void draw(const Rect& rect);
|
||||
|
||||
private:
|
||||
|
@ -69,6 +71,10 @@ public:
|
|||
Size getVisibleSize() { return m_visibleDimension * m_tileSize; }
|
||||
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; }
|
||||
|
||||
Point transformPositionTo2D(const Position& position);
|
||||
|
|
|
@ -35,7 +35,7 @@ Missile::Missile() : Thing()
|
|||
void Missile::draw(const Point& p, const Rect&)
|
||||
{
|
||||
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)
|
||||
|
@ -80,11 +80,12 @@ void Missile::setPath(const Position& fromPosition, const Position& toPosition)
|
|||
}
|
||||
|
||||
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_duration = 150 * std::sqrt(Point(m_positionDelta.x, m_positionDelta.y).length());
|
||||
m_positionDelta.x *= Otc::TILE_PIXELS;
|
||||
m_positionDelta.y *= Otc::TILE_PIXELS;
|
||||
m_duration = 150 * std::sqrt(Point(m_deltax, m_deltay).length());
|
||||
m_deltax *= Otc::TILE_PIXELS;
|
||||
m_deltay *= Otc::TILE_PIXELS;
|
||||
|
||||
// schedule removal
|
||||
auto self = asMissile();
|
||||
|
|
|
@ -47,7 +47,8 @@ public:
|
|||
|
||||
private:
|
||||
ticks_t m_startTicks;
|
||||
Position m_positionDelta;
|
||||
int m_deltax;
|
||||
int m_deltay;
|
||||
float m_duration;
|
||||
};
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ protected:
|
|||
|
||||
uint32 m_id;
|
||||
Position m_position;
|
||||
int m_xPattern, m_yPattern, m_zPattern, m_animation;
|
||||
uint8 m_xPattern, m_yPattern, m_zPattern, m_animation;
|
||||
|
||||
private:
|
||||
ThingType *m_type;
|
||||
|
|
|
@ -36,63 +36,75 @@ Tile::Tile(const 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;
|
||||
|
||||
// first bottom items
|
||||
for(const ThingPtr& thing : m_things) {
|
||||
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom())
|
||||
break;
|
||||
thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor);
|
||||
if(drawFlags & Otc::DrawGround || drawFlags & Otc::DrawWalls) {
|
||||
for(const ThingPtr& thing : m_things) {
|
||||
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom())
|
||||
break;
|
||||
|
||||
m_drawElevation += thing->getElevation();
|
||||
if(m_drawElevation > Otc::MAX_ELEVATION)
|
||||
m_drawElevation = Otc::MAX_ELEVATION;
|
||||
if((drawFlags & Otc::DrawGround && thing->isGround()) || (drawFlags & Otc::DrawWalls))
|
||||
thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor);
|
||||
|
||||
m_drawElevation += thing->getElevation();
|
||||
if(m_drawElevation > Otc::MAX_ELEVATION)
|
||||
m_drawElevation = Otc::MAX_ELEVATION;
|
||||
}
|
||||
}
|
||||
|
||||
// now common items in reverse order
|
||||
for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
|
||||
const ThingPtr& thing = *it;
|
||||
if(thing->asCreature() || thing->isOnTop() || thing->isOnBottom() || thing->isGroundBorder() || thing->isGround())
|
||||
break;
|
||||
thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor);
|
||||
if(drawFlags & Otc::DrawCommonItems) {
|
||||
for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
|
||||
const ThingPtr& thing = *it;
|
||||
if(thing->asCreature() || thing->isOnTop() || thing->isOnBottom() || thing->isGroundBorder() || thing->isGround())
|
||||
break;
|
||||
thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor);
|
||||
|
||||
m_drawElevation += thing->getElevation();
|
||||
if(m_drawElevation > Otc::MAX_ELEVATION)
|
||||
m_drawElevation = Otc::MAX_ELEVATION;
|
||||
m_drawElevation += thing->getElevation();
|
||||
if(m_drawElevation > Otc::MAX_ELEVATION)
|
||||
m_drawElevation = Otc::MAX_ELEVATION;
|
||||
}
|
||||
}
|
||||
|
||||
// we can render creatures in 3x3 range
|
||||
for(int xi = -1; xi <= 1; ++xi) {
|
||||
for(int yi = -1; yi <= 1; ++yi) {
|
||||
const TilePtr& tile = g_map.getTile(m_position + Position(xi, yi, 0));
|
||||
if(!tile)
|
||||
continue;
|
||||
for(const CreaturePtr& creature : tile->getCreatures()) {
|
||||
int tileSize = Otc::TILE_PIXELS * scaleFactor;
|
||||
Rect creatureRect(dest.x + xi*tileSize + (creature->getWalkOffset().x - creature->getDisplacementX())*scaleFactor,
|
||||
dest.y + yi*tileSize + (creature->getWalkOffset().y - creature->getDisplacementY())*scaleFactor,
|
||||
tileSize, tileSize);
|
||||
Rect thisTileRect(dest.x, dest.y, tileSize, tileSize);
|
||||
if(drawFlags & Otc::DrawCreatures) {
|
||||
for(int xi = -1; xi <= 1; ++xi) {
|
||||
for(int yi = -1; yi <= 1; ++yi) {
|
||||
const TilePtr& tile = g_map.getTile(m_position.translated(xi, yi, 0));
|
||||
if(!tile)
|
||||
continue;
|
||||
for(const CreaturePtr& creature : tile->getCreatures()) {
|
||||
int tileSize = Otc::TILE_PIXELS * scaleFactor;
|
||||
Rect creatureRect(dest.x + xi*tileSize + (creature->getWalkOffset().x - creature->getDisplacementX())*scaleFactor,
|
||||
dest.y + yi*tileSize + (creature->getWalkOffset().y - creature->getDisplacementY())*scaleFactor,
|
||||
tileSize, tileSize);
|
||||
Rect thisTileRect(dest.x, dest.y, tileSize, tileSize);
|
||||
|
||||
// only render creatures where bottom right is inside our rect
|
||||
if(thisTileRect.contains(creatureRect.bottomRight())) {
|
||||
creature->draw(Point(dest.x + xi*tileSize - m_drawElevation*scaleFactor,
|
||||
dest.y + yi*tileSize - m_drawElevation*scaleFactor), scaleFactor);
|
||||
// only render creatures where bottom right is inside our rect
|
||||
if(thisTileRect.contains(creatureRect.bottomRight())) {
|
||||
creature->draw(Point(dest.x + xi*tileSize - m_drawElevation*scaleFactor,
|
||||
dest.y + yi*tileSize - m_drawElevation*scaleFactor), scaleFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// effects
|
||||
for(const EffectPtr& effect : m_effects)
|
||||
effect->draw(dest, scaleFactor);
|
||||
if(drawFlags & Otc::DrawEffects) {
|
||||
for(const EffectPtr& effect : m_effects)
|
||||
effect->draw(dest, scaleFactor);
|
||||
}
|
||||
|
||||
// top items
|
||||
for(const ThingPtr& thing : m_things) {
|
||||
if(thing->isOnTop())
|
||||
thing->draw(dest - m_drawElevation, scaleFactor);
|
||||
if(drawFlags & Otc::DrawWalls) {
|
||||
for(const ThingPtr& thing : m_things) {
|
||||
if(thing->isOnTop())
|
||||
thing->draw(dest - m_drawElevation, scaleFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ class Tile : public LuaObject
|
|||
public:
|
||||
Tile(const Position& position);
|
||||
|
||||
void draw(const Point& dest, float scaleFactor);
|
||||
void draw(const Point& dest, float scaleFactor, int drawFlags);
|
||||
|
||||
private:
|
||||
void updateVisibleItemsCache();
|
||||
|
|
|
@ -317,7 +317,7 @@ void ProtocolGame::parseMapDescription(InputMessage& msg)
|
|||
{
|
||||
Position pos = parsePosition(msg);
|
||||
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)
|
||||
|
@ -325,7 +325,7 @@ void ProtocolGame::parseMoveNorth(InputMessage& msg)
|
|||
Position pos = g_map.getCentralPosition();
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -334,7 +334,7 @@ void ProtocolGame::parseMoveEast(InputMessage& msg)
|
|||
Position pos = g_map.getCentralPosition();
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -343,7 +343,7 @@ void ProtocolGame::parseMoveSouth(InputMessage& msg)
|
|||
Position pos = g_map.getCentralPosition();
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -352,7 +352,7 @@ void ProtocolGame::parseMoveWest(InputMessage& msg)
|
|||
Position pos = g_map.getCentralPosition();
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -819,11 +819,11 @@ void ProtocolGame::parseFloorChangeUp(InputMessage& msg)
|
|||
pos.z--;
|
||||
|
||||
int skip = 0;
|
||||
if(pos.z == 7)
|
||||
for(int i = 5; i >= 0; i--)
|
||||
setFloorDescription(msg, pos.x - 8, pos.y - 6, i, 18, 14, 8 - i, &skip);
|
||||
else if(pos.z > 7)
|
||||
setFloorDescription(msg, pos.x - 8, pos.y - 6, pos.z - 2, 18, 14, 3, &skip);
|
||||
if(pos.z == Otc::SEA_FLOOR)
|
||||
for(int i = Otc::SEA_FLOOR - Otc::AWARE_UNDEGROUND_FLOOR_RANGE; i >= 0; i--)
|
||||
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 > Otc::SEA_FLOOR)
|
||||
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.y++;
|
||||
|
@ -836,13 +836,13 @@ void ProtocolGame::parseFloorChangeDown(InputMessage& msg)
|
|||
pos.z++;
|
||||
|
||||
int skip = 0;
|
||||
if(pos.z == 8) {
|
||||
if(pos.z == Otc::UNDERGROUND_FLOOR) {
|
||||
int j, i;
|
||||
for(i = pos.z, j = -1; i < pos.z + 3; ++i, --j)
|
||||
setFloorDescription(msg, pos.x - 8, pos.y - 6, i, 18, 14, j, &skip);
|
||||
for(i = pos.z, j = -1; i <= pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE; ++i, --j)
|
||||
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)
|
||||
setFloorDescription(msg, pos.x - 8, pos.y - 6, pos.z + 2, 18, 14, -3, &skip);
|
||||
else if(pos.z > Otc::UNDERGROUND_FLOOR && pos.z < Otc::MAX_Z-1)
|
||||
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.y--;
|
||||
|
@ -931,13 +931,13 @@ void ProtocolGame::setMapDescription(InputMessage& msg, int32 x, int32 y, int32
|
|||
{
|
||||
int startz, endz, zstep, skip = 0;
|
||||
|
||||
if(z > 7) {
|
||||
startz = z - 2;
|
||||
endz = (15 < z+2) ? 15 : z+2;
|
||||
if(z > Otc::SEA_FLOOR) {
|
||||
startz = z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
|
||||
endz = std::min(z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::MAX_Z);
|
||||
zstep = 1;
|
||||
}
|
||||
else {
|
||||
startz = 7;
|
||||
startz = Otc::SEA_FLOOR;
|
||||
endz = 0;
|
||||
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 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) {
|
||||
int tileOpt = msg.getU16(true);
|
||||
if(tileOpt >= 0xFF00)
|
||||
skip = (msg.getU16() & 0xFF);
|
||||
else {
|
||||
Position pos(x + nx + offset, y + ny + offset, z);
|
||||
setTileDescription(msg, pos);
|
||||
setTileDescription(msg, tilePos);
|
||||
skip = (msg.getU16() & 0xFF);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,51 +30,99 @@
|
|||
class Position
|
||||
{
|
||||
public:
|
||||
Position() : x(-1), y(-1), z(-1) { }
|
||||
Position(int x, int y, int z) : x(x), y(y), z(z) { }
|
||||
Position() : x(65535), y(65535), z(255) { }
|
||||
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) {
|
||||
case Otc::North:
|
||||
return Position( 0, -1, 0);
|
||||
pos.y--;
|
||||
break;
|
||||
case Otc::East:
|
||||
return Position( 1, 0, 0);
|
||||
pos.x++;
|
||||
break;
|
||||
case Otc::South:
|
||||
return Position( 0, 1, 0);
|
||||
pos.y++;
|
||||
break;
|
||||
case Otc::West:
|
||||
return Position(-1, 0, 0);
|
||||
pos.x--;
|
||||
break;
|
||||
case Otc::NorthEast:
|
||||
return Position( 1, -1, 0);
|
||||
pos.x++;
|
||||
pos.y--;
|
||||
break;
|
||||
case Otc::SouthEast:
|
||||
return Position( 1, 1, 0);
|
||||
pos.x++;
|
||||
pos.y++;
|
||||
break;
|
||||
case Otc::SouthWest:
|
||||
return Position(-1, 1, 0);
|
||||
pos.x--;
|
||||
pos.y++;
|
||||
break;
|
||||
case Otc::NorthWest:
|
||||
return Position(-1, -1, 0);
|
||||
default:
|
||||
return Position();
|
||||
pos.x--;
|
||||
pos.y--;
|
||||
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 {
|
||||
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;
|
||||
else if(positionDelta.x == 0) {
|
||||
if(positionDelta.y < 0)
|
||||
else if(dx == 0) {
|
||||
if(dy < 0)
|
||||
return Otc::North;
|
||||
else if(positionDelta.y > 0)
|
||||
else if(dy > 0)
|
||||
return Otc::South;
|
||||
}
|
||||
else if(positionDelta.y == 0) {
|
||||
if(positionDelta.x < 0)
|
||||
else if(dy == 0) {
|
||||
if(dx < 0)
|
||||
return Otc::West;
|
||||
else if(positionDelta.x > 0)
|
||||
else if(dx > 0)
|
||||
return Otc::East;
|
||||
}
|
||||
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)
|
||||
angle += 360;
|
||||
|
||||
|
@ -98,7 +146,10 @@ public:
|
|||
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) { 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 isInRange(const Position& pos, int xdif, int ydif, int zdif = 1) const {
|
||||
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 xRange, int yRange) const { return std::abs(x-pos.x) <= xRange && std::abs(y-pos.y) <= yRange; }
|
||||
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; }
|
||||
void down(int n = 1) { z+=n; }
|
||||
bool up(int n = 1) {
|
||||
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; }
|
||||
void coveredDown(int n = 1) { x-=n; y-=n; z+=n; }
|
||||
bool down(int n = 1) {
|
||||
int nz = z+n;
|
||||
if(nz >= 0 && nz <= Otc::MAX_Z) {
|
||||
z = nz;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
bool coveredUp(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;
|
||||
}
|
||||
|
||||
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> {
|
||||
|
@ -132,13 +214,17 @@ struct PositionHasher : std::unary_function<Position, std::size_t> {
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue