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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -47,7 +47,8 @@ public:
private:
ticks_t m_startTicks;
Position m_positionDelta;
int m_deltax;
int m_deltay;
float m_duration;
};

View File

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

View File

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

View File

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

View File

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

View File

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