From 6d891ff9200d650efe7166762a0446e53c4639ec Mon Sep 17 00:00:00 2001 From: Paul Merrill Date: Thu, 5 Apr 2012 02:39:24 -0700 Subject: [PATCH] shoddy feature: lazy exits --- src/area-tmx.cpp | 56 +++++++++++++++++++++++++++++++++++++------------------- src/entity.cpp | 23 ++++++++++++++++++----- src/player.cpp | 48 +++++++++++++++++++++++++++++++++++++----------- src/tile.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- src/tile.h | 16 ++++++++++++++-- 5 files changed, 152 insertions(+), 41 deletions(-) diff --git a/src/area-tmx.cpp b/src/area-tmx.cpp index 17245d7..f99993f 100644 --- a/src/area-tmx.cpp +++ b/src/area-tmx.cpp @@ -581,8 +581,8 @@ bool AreaTMX::processObject(XMLNode node, int z) // Gather object properties now. Assign them to tiles later. std::vector onEnter, onLeave, onUse; - bool wwide, hwide; /* wide exit in dimensions: width, height */ - boost::optional exit; + bool wwide[5], hwide[5]; /* wide exit in dimensions: width, height */ + boost::scoped_ptr exit[5]; boost::optional layermod; unsigned flags = 0x0; @@ -622,11 +622,26 @@ bool AreaTMX::processObject(XMLNode node, int z) onUse.push_back(filename); } else if (name == "exit") { - Exit exit_; - ASSERT(parseExit(value, &exit_, &wwide, &hwide)); - exit.reset(exit_); + exit[EXIT_NORMAL].reset(new Exit); + ASSERT(parseExit(value, exit[EXIT_NORMAL].get(), &wwide[EXIT_NORMAL], &hwide[EXIT_NORMAL])); flags |= TILE_NOWALK_NPC; } + else if (name == "exit:up") { + exit[EXIT_UP].reset(new Exit); + ASSERT(parseExit(value, exit[EXIT_UP].get(), &wwide[EXIT_UP], &hwide[EXIT_UP])); + } + else if (name == "exit:down") { + exit[EXIT_DOWN].reset(new Exit); + ASSERT(parseExit(value, exit[EXIT_DOWN].get(), &wwide[EXIT_DOWN], &hwide[EXIT_DOWN])); + } + else if (name == "exit:left") { + exit[EXIT_LEFT].reset(new Exit); + ASSERT(parseExit(value, exit[EXIT_LEFT].get(), &wwide[EXIT_LEFT], &hwide[EXIT_LEFT])); + } + else if (name == "exit:right") { + exit[EXIT_RIGHT].reset(new Exit); + ASSERT(parseExit(value, exit[EXIT_RIGHT].get(), &wwide[EXIT_RIGHT], &hwide[EXIT_RIGHT])); + } else if (name == "layermod") { int mod; ASSERT(child.intAttr("value", &mod)); @@ -652,15 +667,16 @@ bool AreaTMX::processObject(XMLNode node, int z) h = 1; // We don't actually use the object gid. It is supposed to - // indicate which tile our object is rendered as, but, for + // indicate which tile our object is rendered as, but for // Tsunagari, tile objects are always transparent and reveal // the tile below. } else { // This is one of Tiled's "Objects". It has a width and height. ASSERT(node.intAttr("width", &w)); - ASSERT(node.intAttr("height", &h)); w /= tileDim.x; h /= - tileDim.y; + ASSERT(node.intAttr("height", &h)); + w /= tileDim.x; + h /= tileDim.y; } // We know which Tiles are being talked about now... yay @@ -669,14 +685,16 @@ bool AreaTMX::processObject(XMLNode node, int z) Tile& tile = map[z][Y][X]; tile.flags |= flags; - if (exit) { - tile.exit = exit; - int dx = X - x; - int dy = Y - y; - if (wwide) - tile.exit->tile.x += dx; - if (hwide) - tile.exit->tile.y += dy; + for (int i = 0; i < 5; i++) { + if (exit[i]) { + tile.exits[i] = new Exit(*exit[i].get()); + int dx = X - x; + int dy = Y - y; + if (wwide[i]) + tile.exits[i]->coord.x += dx; + if (hwide[i]) + tile.exits[i]->coord.y += dy; + } } if (layermod) tile.layermod = layermod; @@ -746,9 +764,9 @@ bool AreaTMX::parseExit(const std::string& dest, Exit* exit, } exit->area = area; - exit->tile.x = atoi(xstr.c_str()); - exit->tile.y = atoi(ystr.c_str()); - exit->tile.z = atof(zstr.c_str()); + exit->coord.x = atoi(xstr.c_str()); + exit->coord.y = atoi(ystr.c_str()); + exit->coord.z = atof(zstr.c_str()); *wwide = xstr.find('+') != std::string::npos; *hwide = ystr.find('+') != std::string::npos; diff --git a/src/entity.cpp b/src/entity.cpp index f9bcf64..e853dda 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -330,12 +330,23 @@ const std::string& Entity::directionStr(ivec2 facing) const bool Entity::canMove(icoord dest) { - if (!area->inBounds(dest)) + bool can = false, inBounds; + icoord delta = dest; + delta -= getTileCoords_i(); + can = can || (inBounds = area->inBounds(dest)); + can = can || (delta.z == 0 && getTile().exitAt(delta.x, delta.y)); + if (!can) // The tile is off the map. return false; destCoord = area->phys2virt_r(dest); - destTile = &area->getTile(dest); - return !destTile->hasFlag(TILE_NOWALK); + if (inBounds) { + destTile = &area->getTile(dest); + return !destTile->hasFlag(TILE_NOWALK); + } + else { + destTile = NULL; + return true; + } } void Entity::preMove() @@ -378,8 +389,10 @@ void Entity::postMove() setPhase(getFacing()); // Process triggers. - destTile->onEnterScripts(this); - tileEntryScript(); + if (destTile) { + destTile->onEnterScripts(this); + tileEntryScript(); + } // TODO: move teleportation here /* diff --git a/src/player.cpp b/src/player.cpp index 56d2f35..2ad0f90 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -92,15 +92,18 @@ void Player::moveByTile(ivec2 delta) icoord newCoord = getTileCoords_i(); newCoord += icoord(delta.x, delta.y, 0); + /* // The tile is off the map. Turn to face the direction, but don't move. if (!area->inBounds(newCoord)) { setPhase(directionStr(setFacing(delta))); redraw = true; return; } + */ destTile = &area->getTile(newCoord); + /* // Is anything player-specific preventing us from moving? if (destTile->hasFlag(TILE_NOWALK_PLAYER)) { // The tile we're trying to move onto is set as @@ -110,6 +113,7 @@ void Player::moveByTile(ivec2 delta) redraw = true; return; } + */ Entity::moveByTile(delta); } @@ -138,18 +142,40 @@ void Player::postMove() Entity::postMove(); // Exits - const boost::optional exit = destTile->exit; - if (exit) { - World* world = World::instance(); - AreaPtr newArea = world->getArea(exit->area); - if (newArea) { - world->focusArea(newArea, exit->tile); + if (destTile) { + const Exit* exit = destTile->exits[EXIT_NORMAL]; + if (exit) { + World* world = World::instance(); + AreaPtr newArea = world->getArea(exit->area); + if (newArea) { + world->focusArea(newArea, exit->coord); + } + else { + // Roll back movement if exit failed to open. + r = fromCoord; + Log::err("Exit", + exit->area + ": failed to load properly"); + } } - else { - // Roll back movement if exit failed to open. - r = fromCoord; - Log::err("Exit", - exit->area + ": failed to load properly"); + } + if (fromTile) { + icoord delta = area->virt2phys(destCoord); + delta -= area->virt2phys(fromCoord); + if (delta.z == 0) { + Exit* exit = area->getTile(area->virt2phys(fromCoord)).exitAt(delta.x, delta.y); + if (exit) { + World* world = World::instance(); + AreaPtr newArea = world->getArea(exit->area); + if (newArea) { + world->focusArea(newArea, exit->coord); + } + else { + // Roll back movement if exit failed to open. + r = fromCoord; + Log::err("Exit", + exit->area + ": failed to load properly"); + } + } } } diff --git a/src/tile.cpp b/src/tile.cpp index a22b553..84a58cf 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -53,7 +53,7 @@ Exit::Exit() } Exit::Exit(const std::string area, int x, int y, double z) - : area(area), tile(x, y, z) + : area(area), coord(x, y, z) { } @@ -65,6 +65,7 @@ Tile::Tile() Tile::Tile(Area* area, int x, int y, int z) : area(area), x(x), y(y), z(z), flags(0x0), type(NULL) { + memset(exits, 0, sizeof(exits)); } bool Tile::hasFlag(unsigned flag) const @@ -82,6 +83,40 @@ Tile& Tile::offset(int x, int y) return area->getTile(this->x + x, this->y + y, z); } +Exit* Tile::getNormalExit() +{ + return exits[EXIT_NORMAL]; +} + +void Tile::setNormalExit(Exit* exit) +{ + exits[EXIT_NORMAL] = exit; +} + +Exit* Tile::exitAt(int x, int y) +{ + switch (x) { + case -1: + return y == 0 ? exits[EXIT_LEFT] : NULL; + case 0: + switch (y) { + case -1: + return exits[EXIT_UP]; + case 0: + return exits[EXIT_NORMAL]; + case 1: + return exits[EXIT_DOWN]; + default: + return NULL; + } + break; + case 1: + return y == 0 ? exits[EXIT_RIGHT] : NULL; + default: + return NULL; + } +} + void Tile::onEnterScripts(Entity* triggeredBy) { runScripts(triggeredBy, onEnter); @@ -186,7 +221,15 @@ void exportTile() .def_readonly("y", &Tile::y) .def_readonly("z", &Tile::z) .def_readwrite("type", &Tile::type) - .def_readwrite("exit", &Tile::exit) + .add_property("exit", + make_function( + static_cast (&Tile::getNormalExit), + boost::python::return_value_policy< + boost::python::reference_existing_object + >() + ), + &Tile::setNormalExit + ) .add_property("walkable", &Tile::getWalkable, &Tile::setWalkable) .add_property("flags", &Tile::flagManip) @@ -208,8 +251,7 @@ void exportTile() const std::string, int, int, double >()) .def_readwrite("area", &Exit::area) - .def_readwrite("tile", &Exit::tile) + .def_readwrite("coord", &Exit::coord) ; - boost::python::optional_(); } diff --git a/src/tile.h b/src/tile.h index 20e8af0..1ed9f2a 100644 --- a/src/tile.h +++ b/src/tile.h @@ -31,6 +31,14 @@ class TileType; #define TILE_NOWALK_PLAYER 0x002 #define TILE_NOWALK_NPC 0x004 +enum ExitDirections { + EXIT_NORMAL, + EXIT_UP, + EXIT_DOWN, + EXIT_LEFT, + EXIT_RIGHT +}; + /** * Independant object that can manipulate a Tile's flags. */ @@ -62,7 +70,7 @@ struct Exit { Exit(const std::string area, int x, int y, double z); std::string area; - vicoord tile; + vicoord coord; }; //! Contains properties unique to this tile. @@ -83,7 +91,7 @@ public: unsigned flags; TileType* type; std::vector onEnter, onLeave, onUse; - boost::optional exit; + Exit* exits[5]; boost::optional layermod; //! Determines whether this tile or one of its parent types embodies a @@ -93,6 +101,10 @@ public: Tile& offset(int x, int y); + Exit* getNormalExit(); + void setNormalExit(Exit* exit); + Exit* exitAt(int x, int y); + void onEnterScripts(Entity* triggeredBy); void onLeaveScripts(Entity* triggeredBy); void onUseScripts(Entity* triggeredBy); -- 2.11.4.GIT