From 4c15d1d1dcedb3627e501fb5ddba4ae74281968c Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sun, 6 Aug 2006 17:30:40 +0000 Subject: Implemented crude handling of being movements. --- src/accounthandler.cpp | 11 ++++-- src/being.cpp | 6 --- src/being.h | 9 ----- src/client.cpp | 18 ++++++++- src/defines.h | 8 ++-- src/gamehandler.cpp | 17 ++++----- src/map.cpp | 30 +++------------ src/map.h | 27 +++++++++----- src/object.cpp | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/object.h | 36 ++++++++++++++++++ src/state.cpp | 48 ++++++++++++++++++++++++ 11 files changed, 242 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/accounthandler.cpp b/src/accounthandler.cpp index 271186c0..c7a7dd15 100644 --- a/src/accounthandler.cpp +++ b/src/accounthandler.cpp @@ -323,6 +323,9 @@ void AccountHandler::processMessage(NetComputer *comp, MessageIn &message) LOG_INFO("Selected Character " << int(charNum) << ": " << selectedChar->getName(), 1); + + selectedChar->setDestination(selectedChar->getX(), selectedChar->getY()); + selectedChar->setSpeed(10); // TODO } break; @@ -422,9 +425,10 @@ void AccountHandler::processMessage(NetComputer *comp, MessageIn &message) if (computer.getCharacter().get() == NULL) { result.writeByte(ERRMSG_NO_CHARACTER_SELECTED); - LOG_INFO("No character selected. Can't enter the world.", 2); + LOG_INFO("No character selected. Can't enter the world.", 1); break; // no character selected } + LOG_INFO(computer.getCharacter()->getName() << " is trying to enter the world.", 1); std::string magic_token(32, ' '); for (int i = 0; i < 32; ++i) { magic_token[i] = @@ -451,7 +455,7 @@ void AccountHandler::processMessage(NetComputer *comp, MessageIn &message) if (computer.getCharacter().get() == NULL) { result.writeByte(ERRMSG_NO_CHARACTER_SELECTED); - LOG_INFO("No character selected. Can't enter the chat.", 2); + LOG_INFO("No character selected. Can't enter the chat.", 1); break; // no character selected } std::string magic_token(32, ' '); @@ -472,7 +476,8 @@ void AccountHandler::processMessage(NetComputer *comp, MessageIn &message) } // return result - computer.send(result.getPacket()); + if (result.getDataSize() > 0) + computer.send(result.getPacket()); } void diff --git a/src/being.cpp b/src/being.cpp index c95136af..ae339ad8 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -23,12 +23,6 @@ #include "being.h" - -PATH_NODE::PATH_NODE(unsigned short x, unsigned short y): - x(x), y(y) -{ -} - /** * Update the internal status. */ diff --git a/src/being.h b/src/being.h index 052d82de..6dec64d3 100644 --- a/src/being.h +++ b/src/being.h @@ -34,15 +34,6 @@ const unsigned int MAX_EQUIP_SLOTS = 5; /**< Maximum number of equipped slots */ -struct PATH_NODE { - /** - * Constructor. - */ - PATH_NODE(unsigned short x, unsigned short y); - - unsigned short x, y; -}; - /** * Raw statistics of a Player */ diff --git a/src/client.cpp b/src/client.cpp index f1d73541..752d65d0 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -269,8 +269,8 @@ int main(int argc, char *argv[]) std::cin >> y; msg.writeShort(PGMSG_WALK); - msg.writeLong(x); - msg.writeLong(y); + msg.writeShort(x); + msg.writeShort(y); msgDestination = 1; } break; @@ -720,6 +720,20 @@ void parsePacket(char *data, int recvLength) { } } break; + case GPMSG_BEINGS_MOVE: + { + int nb = (recvLength - 2) / (1*4 + 4*2); + std::cout << "Beings are moving:" << std::endl; + for(; nb > 0; --nb) { + int id = msg.readLong(); + int cx = msg.readShort(), cy = msg.readShort(); + int dx = msg.readShort(), dy = msg.readShort(); + std::cout << " ID " << id << " at (" + << cx << ", " << cy << ") toward (" + << dx << ", " << dy << ")." << std::endl; + } + } break; + case XXMSG_INVALID: std::cout << "The server does not understand our message." << std::endl; break; diff --git a/src/defines.h b/src/defines.h index 90896f81..0c0f95f9 100644 --- a/src/defines.h +++ b/src/defines.h @@ -95,10 +95,9 @@ const unsigned int MAX_CLIENTS = 1024, // Screen Related /** - * Determine the area in which a character - * can hear another one speak + * Determine the area in which a character is aware of other beings */ - AROUND_AREA_IN_TILES = 10; + AROUND_AREA = 320; /** @@ -150,7 +149,8 @@ enum { GPMSG_BEING_ENTER = 0x0200, // B type, L being id // player: S name, B hair style, B hair color, B gender GPMSG_BEING_LEAVE = 0x0201, // B type, L being id - PGMSG_WALK = 0x0260, // L*2 destination + PGMSG_WALK = 0x0260, // W*2 destination + GPMSG_BEINGS_MOVE = 0x0280, // { L being id, W*2 position, W*2 destination }* PGMSG_SAY = 0x02A0, // S text GPMSG_SAY = 0x02A1, // S being, S text PGMSG_USE_ITEM = 0x0300, // L item id diff --git a/src/gamehandler.cpp b/src/gamehandler.cpp index b3dfb324..6dfab787 100644 --- a/src/gamehandler.cpp +++ b/src/gamehandler.cpp @@ -27,6 +27,7 @@ #include #include "gameclient.h" +#include "map.h" #include "messagein.h" #include "messageout.h" #include "netcomputer.h" @@ -194,12 +195,10 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message) case PGMSG_WALK: { - long x = message.readLong(); - long y = message.readLong(); + unsigned x = message.readShort(); + unsigned y = message.readShort(); - // simplistic "teleport" walk - computer.getCharacter()->setX(x); - computer.getCharacter()->setY(y); + computer.getCharacter()->setDestination(x, y); // no response should be required } break; @@ -220,7 +219,7 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message) break; } - if (result.getPacket()->length > 0) + if (result.getDataSize() > 0) computer.send(result.getPacket()); } @@ -248,10 +247,8 @@ void GameHandler::sayAround(GameClient &computer, std::string const &text) std::pair listenerXY = listener->getXY(); - if (abs(listenerXY.first - speakerXY.first) <= - (int)AROUND_AREA_IN_TILES && - abs(listenerXY.second - speakerXY.second) <= - (int)AROUND_AREA_IN_TILES) + if (areAround(listenerXY.first, listenerXY.second, + speakerXY.first, speakerXY.second)) { (*i)->send(msg.getPacket()); } diff --git a/src/map.cpp b/src/map.cpp index 89c34ee6..8a768e07 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -123,30 +123,6 @@ Map::getMetaTile(int x, int y) return &metaTiles[x + y * width]; } -int -Map::getWidth() -{ - return width; -} - -int -Map::getHeight() -{ - return height; -} - -int -Map::getTileWidth() -{ - return tileWidth; -} - -int -Map::getTileHeight() -{ - return tileHeight; -} - std::list Map::findPath(int startX, int startY, int destX, int destY) { @@ -305,3 +281,9 @@ Map::findPath(int startX, int startY, int destX, int destY) return path; } + +bool areAround(unsigned x1, unsigned y1, unsigned x2, unsigned y2) +{ + return (abs(x1 - x2) <= (int)AROUND_AREA && + abs(y1 - y2) <= (int)AROUND_AREA); +} diff --git a/src/map.h b/src/map.h index 9cc07044..46144f56 100644 --- a/src/map.h +++ b/src/map.h @@ -30,7 +30,14 @@ #include "properties.h" -struct PATH_NODE; + +struct PATH_NODE { + PATH_NODE(unsigned short u, unsigned short v) + : x(u), y(v) + {} + + unsigned short x, y; +}; /** * A meta tile stores additional information about a location on a tile map. @@ -129,26 +136,26 @@ class Map : public Properties /** * Returns the width of this map. */ - int - getWidth(); + int getWidth() const + { return width; } /** * Returns the height of this map. */ - int - getHeight(); + int getHeight() const + { return height; } /** * Returns the tile width of this map. */ - int - getTileWidth(); + int getTileWidth() const + { return tileWidth; } /** * Returns the tile height used by this map. */ - int - getTileHeight(); + int getTileHeight() const + { return tileHeight; } /** * Find a path from one location to the next. @@ -167,4 +174,6 @@ class Map : public Properties int onClosedList, onOpenList; }; +bool areAround(unsigned x1, unsigned y1, unsigned x2, unsigned y2); + #endif diff --git a/src/object.cpp b/src/object.cpp index 5c03981a..f6863cd4 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -21,11 +21,110 @@ */ #include +#include #include "object.h" +#include "map.h" +#include "mapmanager.h" + void Object::setID(int id) { assert(mID < 0); mID = id; } + +void MovingObject::move() +{ + unsigned mSrcX = getX(), mSrcY = getY(); + if (mSrcX == mDstX && mSrcY == mDstY) { + mNewX = mDstX; + mNewY = mDstY; + return; + } + + Map *map = MapManager::instance().getMap(getMapId()); + int tileW = map->getTileWidth(), tileH = map->getTileHeight(); + int tileD = (int) std::sqrt((double)(tileW * tileW + tileH * tileH)); + int tileSX = mSrcX / tileW, fracSX = mSrcX % tileW - tileW / 2; + int tileSY = mSrcY / tileH, fracSY = mSrcY % tileH - tileH / 2; + int tileDX = mDstX / tileW, fracDX = mDstX % tileW - tileW / 2; + int tileDY = mDstY / tileH, fracDY = mDstY % tileH - tileH / 2; + + std::list path; + if (tileSX != tileDX || tileSY != tileDY) { + path = map->findPath(tileSX, tileSY, tileDX, tileDY); + if (path.empty()) { + mNewX = mDstX = mSrcX; + mNewY = mDstY = mSrcY; + return; + } + } + + int tileCX = tileSX, tileCY = tileSY, fracCX = fracSX, fracCY = fracSY; + int tileNX = tileDX, tileNY = tileDY, left = mSpeed; + int vecX = 0, vecY = 0, cost = 0; + + for (std::list::const_iterator it = path.begin(), + it_end = path.end(); it != it_end; ++it) { + + tileNX = it->x; + tileNY = it->y; + assert(tileNX != tileCX && tileNY != tileCY && + tileNX != tileDX && tileNY != tileDY); + + if (fracCX != 0 || fracCY != 0) { + // not at the tile center, move toward the next tile center + vecX = -fracCX + tileW * (tileNX - tileCX); + vecY = -fracCY + tileH * (tileNY - tileCY); + cost = (int) std::sqrt((double)(vecX * vecX + vecY * vecY)); + } else { + // at a tile center and toward the next tile center + assert(abs(tileNX - tileCX) <= 1 && abs(tileNY - tileCY) <= 1); + if (tileNX != tileCX) { + vecX = tileW * (tileNX - tileCX); + if (tileNY != tileCY) { + vecY = tileH * (tileNY - tileCY); + cost = tileD; + } else { + vecY = 0; + cost = tileW; + } + } else { + assert(tileNY != tileCY); + vecX = 0; + vecY = tileH * (tileNY - tileCY); + cost = tileH; + } + } + + if (cost > left) break; + // enough movement left to reach the next tile center + tileCX = tileNX; + tileCY = tileNY; + fracCX = 0; + fracCY = 0; + vecX = 0; + vecY = 0; + left -= cost; + } + + if ((vecX == 0 && vecY == 0) && (fracCX != fracDX || fracCY != fracDY)) { + // walk toward the destination + vecX = fracDX - fracCX + tileW * (tileDX - tileCX); + vecY = fracDY - fracCY + tileH * (tileDY - tileCY); + cost = (int) std::sqrt((double)(vecX * vecX + vecY * vecY)); + } + + if (cost <= left) { + // enough movement left to perform the last step + mNewX = mDstX; + mNewY = mDstY; + return; + } + + // linear interpolation along the vector + assert(cost > 0); + mNewX = tileCX * tileW + tileW / 2 + fracCX + vecX * left / cost; + mNewY = tileCY * tileH + tileH / 2 + fracCY + vecY * left / cost; +} diff --git a/src/object.h b/src/object.h index 7c64719f..05b1f45d 100644 --- a/src/object.h +++ b/src/object.h @@ -165,6 +165,42 @@ class MovingObject: public Object MovingObject(int type, int id) : Object(type, id) {} + + /** + * Gets the destination coordinates of the object. + */ + std::pair getDestination() const + { return std::make_pair(mDstX, mDstY); } + + /** + * Sets the destination coordinates of the object. + */ + void setDestination(unsigned x, unsigned y) + { mDstX = x; mDstY = y; } + + /** + * Gets the next coordinates of the object. + */ + std::pair getNextPosition() const + { return std::make_pair(mNewX, mNewY); } + + /** + * Sets object speed. + */ + void setSpeed(unsigned s) + { mSpeed = s; } + + /** + * Moves the object toward its destination. + */ + void move(); + + private: + unsigned mDstX; /**< target x coordinate */ + unsigned mDstY; /**< target y coordinate */ + unsigned mNewX; /**< next x coordinate */ + unsigned mNewY; /**< next y coordinate */ + unsigned mSpeed; /**< speed */ }; /** diff --git a/src/state.cpp b/src/state.cpp index ae3ceda4..2cb46aa2 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -46,9 +46,57 @@ void State::update() // update game state (update AI, etc.) for (std::map::iterator m = maps.begin(), m_end = maps.end(); m != m_end; ++m) { + + typedef std::vector< utils::CountedPtr > Movings; + Movings movings; + for (Objects::iterator o = m->second.objects.begin(), o_end = m->second.objects.end(); o != o_end; ++o) { (*o)->update(); + int t = (*o)->getType(); + if (t == OBJECT_NPC || t == OBJECT_PLAYER || t == OBJECT_MONSTER) { + utils::CountedPtr ptr(*o); + ptr->move(); + movings.push_back(ptr); + } + } + + + Players &players = m->second.players; + for (Players::iterator p = players.begin(), + p_end = players.end(); p != p_end; ++p) { + std::pair ps = (*p)->getXY(); + std::pair pn = (*p)->getNextPosition(); + MessageOut msg; + msg.writeShort(GPMSG_BEINGS_MOVE); + + for (Movings::iterator o = movings.begin(), + o_end = movings.end(); o != o_end; ++o) { + std::pair os = (*o)->getXY(); + std::pair on = (*o)->getNextPosition(); + + bool were = areAround(ps.first, ps.second, os.first, os.second); + bool will = areAround(pn.first, pn.second, on.first, on.second); + bool has_moved = os.first != on.first || os.second != on.second; + if (!(will && has_moved) && !(were != will)) + continue; + + std::pair od = (*o)->getDestination(); + msg.writeLong((*o)->getID()); + msg.writeShort(on.first); + msg.writeShort(on.second); + msg.writeShort(od.first); + msg.writeShort(od.second); + } + + if (msg.getDataSize() > 2) + gameHandler->sendTo(*p, msg); + } + + for (Movings::iterator o = movings.begin(), + o_end = movings.end(); o != o_end; ++o) { + std::pair pos = (*o)->getNextPosition(); + (*o)->setXY(pos.first, pos.second); } } } -- cgit v1.2.3-70-g09d2