From c7e7b62aa94bf295ca1dc556762ad6070221e0cd Mon Sep 17 00:00:00 2001 From: Eugenio Favalli Date: Tue, 25 Jul 2006 18:04:38 +0000 Subject: Switched client to use enet and modified login sequence to work with the new protocol from tmwserv. --- src/net/beinghandler.cpp | 170 +++++++++++++++++++++++------------------------ 1 file changed, 84 insertions(+), 86 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index cd5653fc..68a46650 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -71,12 +71,12 @@ void BeingHandler::handleMessage(MessageIn *msg) case SMSG_BEING_VISIBLE: case SMSG_BEING_MOVE: // Information about a being in range - id = msg->readInt32(); - speed = msg->readInt16(); - msg->readInt16(); // unknown - msg->readInt16(); // unknown - msg->readInt16(); // option - job = msg->readInt16(); // class + id = msg->readLong(); + speed = msg->readShort(); + msg->readShort(); // unknown + msg->readShort(); // unknown + msg->readShort(); // option + job = msg->readShort(); // class dstBeing = beingManager->findBeing(id); @@ -104,33 +104,33 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; - dstBeing->setHairStyle(msg->readInt16()); - dstBeing->setWeapon(msg->readInt16()); - dstBeing->setVisibleEquipment(3, msg->readInt16()); // head bottom + dstBeing->setHairStyle(msg->readShort()); + dstBeing->setWeapon(msg->readShort()); + dstBeing->setVisibleEquipment(3, msg->readShort()); // head bottom if (msg->getId() == SMSG_BEING_MOVE) { - msg->readInt32(); // server tick + msg->readLong(); // server tick } - msg->readInt16(); // shield - dstBeing->setVisibleEquipment(4, msg->readInt16()); // head top - dstBeing->setVisibleEquipment(5, msg->readInt16()); // head mid - dstBeing->setHairColor(msg->readInt16()); - msg->readInt16(); // unknown - msg->readInt16(); // head dir - msg->readInt16(); // guild - msg->readInt16(); // unknown - msg->readInt16(); // unknown - msg->readInt16(); // manner - msg->readInt16(); // karma - msg->readInt8(); // unknown - dstBeing->setSex(1 - msg->readInt8()); // sex + msg->readShort(); // shield + dstBeing->setVisibleEquipment(4, msg->readShort()); // head top + dstBeing->setVisibleEquipment(5, msg->readShort()); // head mid + dstBeing->setHairColor(msg->readShort()); + msg->readShort(); // unknown + msg->readShort(); // head dir + msg->readShort(); // guild + msg->readShort(); // unknown + msg->readShort(); // unknown + msg->readShort(); // manner + msg->readShort(); // karma + msg->readByte(); // unknown + dstBeing->setSex(1 - msg->readByte()); // sex if (msg->getId() == SMSG_BEING_MOVE) { Uint16 srcX, srcY, dstX, dstY; - msg->readCoordinatePair(srcX, srcY, dstX, dstY); + //msg->readCoordinatePair(srcX, srcY, dstX, dstY); dstBeing->setAction(Being::STAND); dstBeing->mX = srcX; dstBeing->mY = srcY; @@ -138,23 +138,22 @@ void BeingHandler::handleMessage(MessageIn *msg) } else { - msg->readCoordinates(dstBeing->mX, dstBeing->mY, - dstBeing->mDirection); + //msg->readCoordinates(dstBeing->mX, dstBeing->mY, dstBeing->mDirection); } - msg->readInt8(); // unknown - msg->readInt8(); // unknown - msg->readInt8(); // unknown / sit + msg->readByte(); // unknown + msg->readByte(); // unknown + msg->readByte(); // unknown / sit break; case SMSG_BEING_REMOVE: // A being should be removed or has died - dstBeing = beingManager->findBeing(msg->readInt32()); + dstBeing = beingManager->findBeing(msg->readLong()); if (!dstBeing) break; - if (msg->readInt8() == 1) + if (msg->readByte() == 1) { // Death switch (dstBeing->getType()) @@ -182,15 +181,15 @@ void BeingHandler::handleMessage(MessageIn *msg) break; case SMSG_BEING_ACTION: - srcBeing = beingManager->findBeing(msg->readInt32()); - dstBeing = beingManager->findBeing(msg->readInt32()); - msg->readInt32(); // server tick - msg->readInt32(); // src speed - msg->readInt32(); // dst speed - param1 = msg->readInt16(); - msg->readInt16(); // param 2 - type = msg->readInt8(); - msg->readInt16(); // param 3 + srcBeing = beingManager->findBeing(msg->readLong()); + dstBeing = beingManager->findBeing(msg->readLong()); + msg->readLong(); // server tick + msg->readLong(); // src speed + msg->readLong(); // dst speed + param1 = msg->readShort(); + msg->readShort(); // param 2 + type = msg->readByte(); + msg->readShort(); // param 3 switch (type) { @@ -231,61 +230,61 @@ void BeingHandler::handleMessage(MessageIn *msg) break; case SMSG_BEING_LEVELUP: - if ((Uint32)msg->readInt32() == player_node->getId()) { + if ((Uint32)msg->readLong() == player_node->getId()) { logger->log("Level up"); sound.playSfx("sfx/levelup.ogg"); } else { logger->log("Someone else went level up"); } - msg->readInt32(); // type + msg->readLong(); // type break; case SMSG_BEING_EMOTION: - if (!(dstBeing = beingManager->findBeing(msg->readInt32()))) + if (!(dstBeing = beingManager->findBeing(msg->readLong()))) { break; } - dstBeing->mEmotion = msg->readInt8(); + dstBeing->mEmotion = msg->readByte(); dstBeing->mEmotionTime = EMOTION_TIME; break; case SMSG_BEING_CHANGE_LOOKS: { - if (!(dstBeing = beingManager->findBeing(msg->readInt32()))) + if (!(dstBeing = beingManager->findBeing(msg->readLong()))) { break; } - - int type = msg->readInt8(); + + int type = msg->readByte(); switch (type) { case 1: - dstBeing->setHairStyle(msg->readInt8()); + dstBeing->setHairStyle(msg->readByte()); break; case 2: - dstBeing->setWeapon(msg->readInt8()); + dstBeing->setWeapon(msg->readByte()); break; case 3: case 4: case 5: // Equip/unequip head 3. Bottom 4. Top 5. Middle - dstBeing->setVisibleEquipment(type, msg->readInt8()); + dstBeing->setVisibleEquipment(type, msg->readByte()); // First 3 slots of mVisibleEquipments are reserved for // later use, probably accessories. break; case 6: - dstBeing->setHairColor(msg->readInt8()); + dstBeing->setHairColor(msg->readByte()); break; default: - printf("c3: %i\n", msg->readInt8()); // unsupported + printf("c3: %i\n", msg->readByte()); // unsupported break; } } break; case SMSG_BEING_NAME_RESPONSE: - if ((dstBeing = beingManager->findBeing(msg->readInt32()))) + if ((dstBeing = beingManager->findBeing(msg->readLong()))) { dstBeing->setName(msg->readString(24)); } @@ -295,12 +294,12 @@ void BeingHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_UPDATE_2: case SMSG_PLAYER_MOVE: // An update about a player, potentially including movement. - id = msg->readInt32(); - speed = msg->readInt16(); - msg->readInt16(); // option 1 - msg->readInt16(); // option 2 - msg->readInt16(); // option - job = msg->readInt16(); + id = msg->readLong(); + speed = msg->readShort(); + msg->readShort(); // option 1 + msg->readShort(); // option 2 + msg->readShort(); // option + job = msg->readShort(); dstBeing = beingManager->findBeing(id); @@ -311,58 +310,57 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; - dstBeing->setHairStyle(msg->readInt16()); - dstBeing->setWeaponById(msg->readInt16()); // item id 1 - msg->readInt16(); // item id 2 - dstBeing->setVisibleEquipment(3, msg->readInt16()); // head bottom + dstBeing->setHairStyle(msg->readShort()); + dstBeing->setWeaponById(msg->readShort()); // item id 1 + msg->readShort(); // item id 2 + dstBeing->setVisibleEquipment(3, msg->readShort()); // head bottom if (msg->getId() == SMSG_PLAYER_MOVE) { - msg->readInt32(); // server tick + msg->readLong(); // server tick } - dstBeing->setVisibleEquipment(4, msg->readInt16()); // head top - dstBeing->setVisibleEquipment(5, msg->readInt16()); // head mid - dstBeing->setHairColor(msg->readInt16()); - msg->readInt16(); // unknown - msg->readInt16(); // head dir - msg->readInt32(); // guild - msg->readInt32(); // emblem - msg->readInt16(); // manner - msg->readInt8(); // karma - dstBeing->setSex(1 - msg->readInt8()); // sex + dstBeing->setVisibleEquipment(4, msg->readShort()); // head top + dstBeing->setVisibleEquipment(5, msg->readShort()); // head mid + dstBeing->setHairColor(msg->readShort()); + msg->readShort(); // unknown + msg->readShort(); // head dir + msg->readLong(); // guild + msg->readLong(); // emblem + msg->readShort(); // manner + msg->readByte(); // karma + dstBeing->setSex(1 - msg->readByte()); // sex if (msg->getId() == SMSG_PLAYER_MOVE) { Uint16 srcX, srcY, dstX, dstY; - msg->readCoordinatePair(srcX, srcY, dstX, dstY); + //msg->readCoordinatePair(srcX, srcY, dstX, dstY); dstBeing->mX = srcX; dstBeing->mY = srcY; dstBeing->setDestination(dstX, dstY); } else { - msg->readCoordinates(dstBeing->mX, dstBeing->mY, - dstBeing->mDirection); + //msg->readCoordinates(dstBeing->mX, dstBeing->mY, dstBeing->mDirection); } - msg->readInt8(); // unknown - msg->readInt8(); // unknown + msg->readByte(); // unknown + msg->readByte(); // unknown if (msg->getId() == SMSG_PLAYER_UPDATE_1) { - if (msg->readInt8() == 2) + if (msg->readByte() == 2) { dstBeing->setAction(Being::SIT); } } else if (msg->getId() == SMSG_PLAYER_MOVE) { - msg->readInt8(); // unknown + msg->readByte(); // unknown } - msg->readInt8(); // Lv - msg->readInt8(); // unknown + msg->readByte(); // Lv + msg->readByte(); // unknown dstBeing->mWalkTime = tick_time; dstBeing->mFrame = 0; @@ -370,9 +368,9 @@ void BeingHandler::handleMessage(MessageIn *msg) case 0x0119: // Change in players look - printf("0x0119 %i %i %i %x %i\n", msg->readInt32(), - msg->readInt16(), msg->readInt16(), msg->readInt16(), - msg->readInt8()); + printf("0x0119 %i %i %i %x %i\n", msg->readLong(), + msg->readShort(), msg->readShort(), msg->readShort(), + msg->readByte()); break; } } -- cgit v1.2.3-70-g09d2 From 33e19fb0822308a630ca6e1122b9b97882a120a7 Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Tue, 25 Jul 2006 19:21:22 +0000 Subject: Fixed Linux compiling issues and merged update system fix for Windows. --- ChangeLog | 6 ++++++ NEWS | 5 ++++- configure.ac | 6 +++--- src/gui/updatewindow.cpp | 11 +++++++---- src/net/beinghandler.cpp | 2 +- src/net/network.cpp | 8 ++++---- 6 files changed, 25 insertions(+), 13 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 67b6a585..662d0b5c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2006-07-25 Bjørn Lindeijer + + * src/gui/updatewindow.cpp: Fixed updating on Windows. + * src/net/beinghandler.cpp, src/net/network.cpp, configure.ac: Fixed + Linux compiling issues. + 2006-07-24 Bjørn Lindeijer * src/main.cpp: Fixed the loading of updates and made skipping the diff --git a/NEWS b/NEWS index b1d48891..ad78fc4f 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,7 @@ -0.0.20 (23 July 2006) +0.0.20.1 (25 July 2006) +- Fixed updating system on Windows + +0.0.20 (24 July 2006) - Added new hairstyle, and some fixes to the old ones - Added slider to set FPS limit - Added visible equipments diff --git a/configure.ac b/configure.ac index a4a3eef6..ce30607f 100755 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.59) -AC_INIT([The Mana World], [0.0.20], [elvenprogrammer@gmail.com], [tmw]) +AC_INIT([The Mana World], [0.1.0], [elvenprogrammer@gmail.com], [tmw]) AC_CONFIG_HEADERS([config.h:config.h.in]) AC_LANG_CPLUSPLUS @@ -43,8 +43,8 @@ AC_CHECK_LIB(SDL_mixer, Mix_OpenAudio, , AC_MSG_ERROR([ *** Unable to find SDL_mixer library (http://www.libsdl.org/projects/SDL_mixer/)])) -AC_CHECK_LIB(SDL_net, SDLNet_Init, , -AC_MSG_ERROR([ *** Unable to find SDL_net library])) +AC_CHECK_LIB([enet], [enet_initialize], , +AC_MSG_ERROR([ *** Unable to find enet library (enet.bespin.org)])) AC_CHECK_LIB(png, png_write_info, , AC_MSG_ERROR([ *** Unable to find png library])) diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index 8f43903f..3f5fe7bb 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -106,8 +106,7 @@ UpdaterWindow::~UpdaterWindow() free(mMemoryBuffer); } - // Remove downloaded files - remove((mBasePath + "/updates/news.txt").c_str()); + // Remove possibly leftover temporary download remove((mBasePath + "/updates/download.temp").c_str()); delete[] mCurlError; @@ -293,10 +292,14 @@ int UpdaterWindow::downloadThread(void *ptr) if (!uw->mStoreInMemory) { fclose(outfile); - // If the download was successful give the file the proper name - // else it will be deleted later + + // Give the file the proper name std::string newName(uw->mBasePath + "/updates/" + uw->mCurrentFile.c_str()); + + // Any existing file with this name is deleted first, otherwise the + // rename will fail on Windows. + remove(newName.c_str()); rename(outFilename.c_str(), newName.c_str()); } } diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 68a46650..7730e9be 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -368,7 +368,7 @@ void BeingHandler::handleMessage(MessageIn *msg) case 0x0119: // Change in players look - printf("0x0119 %i %i %i %x %i\n", msg->readLong(), + printf("0x0119 %li %i %i %x %i\n", msg->readLong(), msg->readShort(), msg->readShort(), msg->readShort(), msg->readByte()); break; diff --git a/src/net/network.cpp b/src/net/network.cpp index 8278e266..aa18e888 100644 --- a/src/net/network.cpp +++ b/src/net/network.cpp @@ -40,13 +40,13 @@ Network::~Network() { clearHandlers(); - if (mState != IDLE && mState != ERROR) + if (mState != IDLE && mState != NET_ERROR) disconnect(); } bool Network::connect(const std::string &address, short port) { - if (mState != IDLE && mState != ERROR) + if (mState != IDLE && mState != NET_ERROR) { logger->log("Tried to connect an already connected socket!"); return false; @@ -55,7 +55,7 @@ bool Network::connect(const std::string &address, short port) if (address.empty()) { logger->log("Empty address given to Network::connect()!"); - mState = ERROR; + mState = NET_ERROR; return false; } @@ -84,7 +84,7 @@ bool Network::connect(const std::string &address, short port) if (mServer == 0) { logger->log("Unable to initiate connection to the server."); - mState = ERROR; + mState = NET_ERROR; return false; } -- cgit v1.2.3-70-g09d2 From 2ae843719c2a7b2325309404a0e3cbb4aeb9c3df Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Tue, 1 Aug 2006 21:10:13 +0000 Subject: Fixed several compiler warnings and a linker error when compiling without OpenGL support. --- ChangeLog | 4 ++++ src/net/beinghandler.cpp | 18 +++++++++--------- src/net/maploginhandler.cpp | 6 +++--- src/net/protocol.h | 2 +- src/player.cpp | 4 ++-- src/resources/openglsdlimageloader.cpp | 4 ++++ 6 files changed, 23 insertions(+), 15 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 1a4b313c..d6049d68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ * configure.ac: Moved some basic checks above the checks on the libraries we depend on, in order to get rid of the confusing rpl_realloc error. + * src/net/beinghandler.cpp, src/net/maploginhandler.cpp, + src/net/protocol.h, src/resources/openglsdlimageloader.cpp, + src/player.cpp: Fixed several compiler warnings and a linker error + when compiling without OpenGL support. 2006-08-01 Eugenio Favalli diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 7730e9be..549797f9 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -129,12 +129,12 @@ void BeingHandler::handleMessage(MessageIn *msg) if (msg->getId() == SMSG_BEING_MOVE) { - Uint16 srcX, srcY, dstX, dstY; + //Uint16 srcX, srcY, dstX, dstY; //msg->readCoordinatePair(srcX, srcY, dstX, dstY); - dstBeing->setAction(Being::STAND); - dstBeing->mX = srcX; - dstBeing->mY = srcY; - dstBeing->setDestination(dstX, dstY); + //dstBeing->setAction(Being::STAND); + //dstBeing->mX = srcX; + //dstBeing->mY = srcY; + //dstBeing->setDestination(dstX, dstY); } else { @@ -333,11 +333,11 @@ void BeingHandler::handleMessage(MessageIn *msg) if (msg->getId() == SMSG_PLAYER_MOVE) { - Uint16 srcX, srcY, dstX, dstY; + //Uint16 srcX, srcY, dstX, dstY; //msg->readCoordinatePair(srcX, srcY, dstX, dstY); - dstBeing->mX = srcX; - dstBeing->mY = srcY; - dstBeing->setDestination(dstX, dstY); + //dstBeing->mX = srcX; + //dstBeing->mY = srcY; + //dstBeing->setDestination(dstX, dstY); } else { diff --git a/src/net/maploginhandler.cpp b/src/net/maploginhandler.cpp index 2a174c58..38ed2203 100644 --- a/src/net/maploginhandler.cpp +++ b/src/net/maploginhandler.cpp @@ -42,14 +42,14 @@ MapLoginHandler::MapLoginHandler() void MapLoginHandler::handleMessage(MessageIn *msg) { - unsigned char direction; + //unsigned char direction; switch (msg->getId()) { case SMSG_LOGIN_SUCCESS: msg->readLong(); // server tick - logger->log("Protocol: Player start position: (%d, %d), Direction: %d", - player_node->mX, player_node->mY, direction); + //logger->log("Protocol: Player start position: (%d, %d), Direction: %d", + // player_node->mX, player_node->mY, direction); state = GAME_STATE; break; diff --git a/src/net/protocol.h b/src/net/protocol.h index e1d403a2..6a13bbd9 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -191,7 +191,7 @@ enum { ERRMSG_NO_LOGIN, // the user is not yet logged ERRMSG_NO_CHARACTER_SELECTED, // the user needs a character ERRMSG_INSUFFICIENT_RIGHTS, // the user is not privileged - ERRMSG_INVALID_ARGUMENT, // part of the received message was invalid + ERRMSG_INVALID_ARGUMENT // part of the received message was invalid }; // Login specific return values diff --git a/src/player.cpp b/src/player.cpp index 9b7536cf..05825f6e 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -110,7 +110,7 @@ Player::setHairColor(Uint16 color) mSprites[HAIR_SPRITE] = new AnimatedSprite("graphics/sprites/hairstyle"+toString(mHairStyle)+".xml", color - 1); } Being::setHairColor(color); -}; +} void Player::setHairStyle(Uint16 style) @@ -121,7 +121,7 @@ Player::setHairStyle(Uint16 style) mSprites[HAIR_SPRITE] = new AnimatedSprite("graphics/sprites/hairstyle"+toString(style)+".xml", mHairColor - 1); } Being::setHairStyle(style); -}; +} void Player::setVisibleEquipment(Uint8 slot, Uint8 id) diff --git a/src/resources/openglsdlimageloader.cpp b/src/resources/openglsdlimageloader.cpp index f3ddbd84..c7ddec74 100644 --- a/src/resources/openglsdlimageloader.cpp +++ b/src/resources/openglsdlimageloader.cpp @@ -21,6 +21,8 @@ * $Id: sdlimageloader.cpp 2121 2006-01-31 02:55:26Z der_doener $ */ +#ifdef USE_OPENGL + #include "openglsdlimageloader.h" #include @@ -32,3 +34,5 @@ SDL_Surface* OpenGLSDLImageLoader::loadSDLSurface(const std::string& filename) ResourceManager *resman = ResourceManager::getInstance(); return resman->loadSDLSurface(filename); } + +#endif -- cgit v1.2.3-70-g09d2 From 2fe42d32c6d368a66586c605cc1b38ee8d85ed1d Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Sun, 20 Aug 2006 16:14:12 +0000 Subject: Changed MessageHandler::handleMessage to take a reference instead of a pointer. Removed unused Packet class. Added stub for handling GPMSG_BEING_ENTER. --- ChangeLog | 3 + src/Makefile.am | 2 - src/net/beinghandler.cpp | 237 +++++++++++++++++++++++------------------- src/net/beinghandler.h | 6 +- src/net/buysellhandler.cpp | 32 +++--- src/net/buysellhandler.h | 2 +- src/net/charserverhandler.cpp | 28 ++--- src/net/charserverhandler.h | 5 +- src/net/chathandler.cpp | 20 ++-- src/net/chathandler.h | 2 +- src/net/equipmenthandler.cpp | 46 ++++---- src/net/equipmenthandler.h | 2 +- src/net/inventoryhandler.cpp | 58 +++++------ src/net/inventoryhandler.h | 2 +- src/net/itemhandler.cpp | 16 +-- src/net/itemhandler.h | 2 +- src/net/loginhandler.cpp | 8 +- src/net/loginhandler.h | 2 +- src/net/maploginhandler.cpp | 6 +- src/net/maploginhandler.h | 2 +- src/net/messagehandler.h | 2 +- src/net/messagein.cpp | 2 - src/net/messageout.cpp | 2 - src/net/network.cpp | 2 +- src/net/npchandler.cpp | 18 ++-- src/net/npchandler.h | 2 +- src/net/packet.cpp | 40 ------- src/net/packet.h | 47 --------- src/net/playerhandler.cpp | 112 ++++++++++---------- src/net/playerhandler.h | 2 +- src/net/skillhandler.cpp | 34 +++--- src/net/skillhandler.h | 2 +- src/net/tradehandler.cpp | 26 ++--- src/net/tradehandler.h | 2 +- 34 files changed, 358 insertions(+), 416 deletions(-) delete mode 100644 src/net/packet.cpp delete mode 100644 src/net/packet.h (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 12e30213..8f589dcb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,6 +25,9 @@ selection of player character and implemented sending of game and chat server tokens. It gets you in the game (or what's left of it), but not on any map yet. + * src/net/*: Changed MessageHandler::handleMessage to take a reference + instead of a pointer. Removed unused Packet class. Added stub for + handling GPMSG_BEING_ENTER. 2006-08-19 Bjørn Lindeijer diff --git a/src/Makefile.am b/src/Makefile.am index 42671f64..8f40c506 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -146,8 +146,6 @@ tmw_SOURCES = graphic/imagerect.h \ net/network.h \ net/npchandler.cpp \ net/npchandler.h \ - net/packet.cpp \ - net/packet.h \ net/playerhandler.cpp \ net/playerhandler.h \ net/protocol.cpp \ diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 549797f9..ed0fc4b2 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -41,24 +41,25 @@ const int EMOTION_TIME = 150; /**< Duration of emotion icon */ BeingHandler::BeingHandler() { static const Uint16 _messages[] = { - SMSG_BEING_VISIBLE, - SMSG_BEING_MOVE, - SMSG_BEING_REMOVE, - SMSG_BEING_ACTION, - SMSG_BEING_LEVELUP, - SMSG_BEING_EMOTION, - SMSG_BEING_CHANGE_LOOKS, - SMSG_BEING_NAME_RESPONSE, - SMSG_PLAYER_UPDATE_1, - SMSG_PLAYER_UPDATE_2, - SMSG_PLAYER_MOVE, - 0x0119, + //SMSG_BEING_VISIBLE, + //SMSG_BEING_MOVE, + //SMSG_BEING_REMOVE, + //SMSG_BEING_ACTION, + //SMSG_BEING_LEVELUP, + //SMSG_BEING_EMOTION, + //SMSG_BEING_CHANGE_LOOKS, + //SMSG_BEING_NAME_RESPONSE, + //SMSG_PLAYER_UPDATE_1, + //SMSG_PLAYER_UPDATE_2, + //SMSG_PLAYER_MOVE, + //0x0119, + GPMSG_BEING_ENTER, 0 }; handledMessages = _messages; } -void BeingHandler::handleMessage(MessageIn *msg) +void BeingHandler::handleMessage(MessageIn &msg) { Uint32 id; Uint16 job, speed; @@ -66,17 +67,21 @@ void BeingHandler::handleMessage(MessageIn *msg) Sint8 type; Being *srcBeing, *dstBeing; - switch (msg->getId()) + switch (msg.getId()) { + case GPMSG_BEING_ENTER: + handleBeingEnterMessage(msg); + break; + case SMSG_BEING_VISIBLE: case SMSG_BEING_MOVE: // Information about a being in range - id = msg->readLong(); - speed = msg->readShort(); - msg->readShort(); // unknown - msg->readShort(); // unknown - msg->readShort(); // option - job = msg->readShort(); // class + id = msg.readLong(); + speed = msg.readShort(); + msg.readShort(); // unknown + msg.readShort(); // unknown + msg.readShort(); // option + job = msg.readShort(); // class dstBeing = beingManager->findBeing(id); @@ -91,7 +96,7 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing = beingManager->createBeing(id, job); } - else if (msg->getId() == 0x0078) + else if (msg.getId() == 0x0078) { dstBeing->clearPath(); dstBeing->mFrame = 0; @@ -104,33 +109,33 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; - dstBeing->setHairStyle(msg->readShort()); - dstBeing->setWeapon(msg->readShort()); - dstBeing->setVisibleEquipment(3, msg->readShort()); // head bottom + dstBeing->setHairStyle(msg.readShort()); + dstBeing->setWeapon(msg.readShort()); + dstBeing->setVisibleEquipment(3, msg.readShort()); // head bottom - if (msg->getId() == SMSG_BEING_MOVE) + if (msg.getId() == SMSG_BEING_MOVE) { - msg->readLong(); // server tick + msg.readLong(); // server tick } - msg->readShort(); // shield - dstBeing->setVisibleEquipment(4, msg->readShort()); // head top - dstBeing->setVisibleEquipment(5, msg->readShort()); // head mid - dstBeing->setHairColor(msg->readShort()); - msg->readShort(); // unknown - msg->readShort(); // head dir - msg->readShort(); // guild - msg->readShort(); // unknown - msg->readShort(); // unknown - msg->readShort(); // manner - msg->readShort(); // karma - msg->readByte(); // unknown - dstBeing->setSex(1 - msg->readByte()); // sex - - if (msg->getId() == SMSG_BEING_MOVE) + msg.readShort(); // shield + dstBeing->setVisibleEquipment(4, msg.readShort()); // head top + dstBeing->setVisibleEquipment(5, msg.readShort()); // head mid + dstBeing->setHairColor(msg.readShort()); + msg.readShort(); // unknown + msg.readShort(); // head dir + msg.readShort(); // guild + msg.readShort(); // unknown + msg.readShort(); // unknown + msg.readShort(); // manner + msg.readShort(); // karma + msg.readByte(); // unknown + dstBeing->setSex(1 - msg.readByte()); // sex + + if (msg.getId() == SMSG_BEING_MOVE) { //Uint16 srcX, srcY, dstX, dstY; - //msg->readCoordinatePair(srcX, srcY, dstX, dstY); + //msg.readCoordinatePair(srcX, srcY, dstX, dstY); //dstBeing->setAction(Being::STAND); //dstBeing->mX = srcX; //dstBeing->mY = srcY; @@ -138,22 +143,22 @@ void BeingHandler::handleMessage(MessageIn *msg) } else { - //msg->readCoordinates(dstBeing->mX, dstBeing->mY, dstBeing->mDirection); + //msg.readCoordinates(dstBeing->mX, dstBeing->mY, dstBeing->mDirection); } - msg->readByte(); // unknown - msg->readByte(); // unknown - msg->readByte(); // unknown / sit + msg.readByte(); // unknown + msg.readByte(); // unknown + msg.readByte(); // unknown / sit break; case SMSG_BEING_REMOVE: // A being should be removed or has died - dstBeing = beingManager->findBeing(msg->readLong()); + dstBeing = beingManager->findBeing(msg.readLong()); if (!dstBeing) break; - if (msg->readByte() == 1) + if (msg.readByte() == 1) { // Death switch (dstBeing->getType()) @@ -181,15 +186,15 @@ void BeingHandler::handleMessage(MessageIn *msg) break; case SMSG_BEING_ACTION: - srcBeing = beingManager->findBeing(msg->readLong()); - dstBeing = beingManager->findBeing(msg->readLong()); - msg->readLong(); // server tick - msg->readLong(); // src speed - msg->readLong(); // dst speed - param1 = msg->readShort(); - msg->readShort(); // param 2 - type = msg->readByte(); - msg->readShort(); // param 3 + srcBeing = beingManager->findBeing(msg.readLong()); + dstBeing = beingManager->findBeing(msg.readLong()); + msg.readLong(); // server tick + msg.readLong(); // src speed + msg.readLong(); // dst speed + param1 = msg.readShort(); + msg.readShort(); // param 2 + type = msg.readByte(); + msg.readShort(); // param 3 switch (type) { @@ -230,63 +235,63 @@ void BeingHandler::handleMessage(MessageIn *msg) break; case SMSG_BEING_LEVELUP: - if ((Uint32)msg->readLong() == player_node->getId()) { + if ((Uint32) msg.readLong() == player_node->getId()) { logger->log("Level up"); sound.playSfx("sfx/levelup.ogg"); } else { logger->log("Someone else went level up"); } - msg->readLong(); // type + msg.readLong(); // type break; case SMSG_BEING_EMOTION: - if (!(dstBeing = beingManager->findBeing(msg->readLong()))) + if (!(dstBeing = beingManager->findBeing(msg.readLong()))) { break; } - dstBeing->mEmotion = msg->readByte(); + dstBeing->mEmotion = msg.readByte(); dstBeing->mEmotionTime = EMOTION_TIME; break; case SMSG_BEING_CHANGE_LOOKS: { - if (!(dstBeing = beingManager->findBeing(msg->readLong()))) + if (!(dstBeing = beingManager->findBeing(msg.readLong()))) { break; } - int type = msg->readByte(); + int type = msg.readByte(); switch (type) { case 1: - dstBeing->setHairStyle(msg->readByte()); + dstBeing->setHairStyle(msg.readByte()); break; case 2: - dstBeing->setWeapon(msg->readByte()); + dstBeing->setWeapon(msg.readByte()); break; case 3: case 4: case 5: // Equip/unequip head 3. Bottom 4. Top 5. Middle - dstBeing->setVisibleEquipment(type, msg->readByte()); + dstBeing->setVisibleEquipment(type, msg.readByte()); // First 3 slots of mVisibleEquipments are reserved for // later use, probably accessories. break; case 6: - dstBeing->setHairColor(msg->readByte()); + dstBeing->setHairColor(msg.readByte()); break; default: - printf("c3: %i\n", msg->readByte()); // unsupported + printf("c3: %i\n", msg.readByte()); // unsupported break; } } break; case SMSG_BEING_NAME_RESPONSE: - if ((dstBeing = beingManager->findBeing(msg->readLong()))) + if ((dstBeing = beingManager->findBeing(msg.readLong()))) { - dstBeing->setName(msg->readString(24)); + dstBeing->setName(msg.readString(24)); } break; @@ -294,12 +299,12 @@ void BeingHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_UPDATE_2: case SMSG_PLAYER_MOVE: // An update about a player, potentially including movement. - id = msg->readLong(); - speed = msg->readShort(); - msg->readShort(); // option 1 - msg->readShort(); // option 2 - msg->readShort(); // option - job = msg->readShort(); + id = msg.readLong(); + speed = msg.readShort(); + msg.readShort(); // option 1 + msg.readShort(); // option 2 + msg.readShort(); // option + job = msg.readShort(); dstBeing = beingManager->findBeing(id); @@ -310,57 +315,57 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; - dstBeing->setHairStyle(msg->readShort()); - dstBeing->setWeaponById(msg->readShort()); // item id 1 - msg->readShort(); // item id 2 - dstBeing->setVisibleEquipment(3, msg->readShort()); // head bottom + dstBeing->setHairStyle(msg.readShort()); + dstBeing->setWeaponById(msg.readShort()); // item id 1 + msg.readShort(); // item id 2 + dstBeing->setVisibleEquipment(3, msg.readShort()); // head bottom - if (msg->getId() == SMSG_PLAYER_MOVE) + if (msg.getId() == SMSG_PLAYER_MOVE) { - msg->readLong(); // server tick + msg.readLong(); // server tick } - dstBeing->setVisibleEquipment(4, msg->readShort()); // head top - dstBeing->setVisibleEquipment(5, msg->readShort()); // head mid - dstBeing->setHairColor(msg->readShort()); - msg->readShort(); // unknown - msg->readShort(); // head dir - msg->readLong(); // guild - msg->readLong(); // emblem - msg->readShort(); // manner - msg->readByte(); // karma - dstBeing->setSex(1 - msg->readByte()); // sex - - if (msg->getId() == SMSG_PLAYER_MOVE) + dstBeing->setVisibleEquipment(4, msg.readShort()); // head top + dstBeing->setVisibleEquipment(5, msg.readShort()); // head mid + dstBeing->setHairColor(msg.readShort()); + msg.readShort(); // unknown + msg.readShort(); // head dir + msg.readLong(); // guild + msg.readLong(); // emblem + msg.readShort(); // manner + msg.readByte(); // karma + dstBeing->setSex(1 - msg.readByte()); // sex + + if (msg.getId() == SMSG_PLAYER_MOVE) { //Uint16 srcX, srcY, dstX, dstY; - //msg->readCoordinatePair(srcX, srcY, dstX, dstY); + //msg.readCoordinatePair(srcX, srcY, dstX, dstY); //dstBeing->mX = srcX; //dstBeing->mY = srcY; //dstBeing->setDestination(dstX, dstY); } else { - //msg->readCoordinates(dstBeing->mX, dstBeing->mY, dstBeing->mDirection); + //msg.readCoordinates(dstBeing->mX, dstBeing->mY, dstBeing->mDirection); } - msg->readByte(); // unknown - msg->readByte(); // unknown + msg.readByte(); // unknown + msg.readByte(); // unknown - if (msg->getId() == SMSG_PLAYER_UPDATE_1) + if (msg.getId() == SMSG_PLAYER_UPDATE_1) { - if (msg->readByte() == 2) + if (msg.readByte() == 2) { dstBeing->setAction(Being::SIT); } } - else if (msg->getId() == SMSG_PLAYER_MOVE) + else if (msg.getId() == SMSG_PLAYER_MOVE) { - msg->readByte(); // unknown + msg.readByte(); // unknown } - msg->readByte(); // Lv - msg->readByte(); // unknown + msg.readByte(); // Lv + msg.readByte(); // unknown dstBeing->mWalkTime = tick_time; dstBeing->mFrame = 0; @@ -368,9 +373,27 @@ void BeingHandler::handleMessage(MessageIn *msg) case 0x0119: // Change in players look - printf("0x0119 %li %i %i %x %i\n", msg->readLong(), - msg->readShort(), msg->readShort(), msg->readShort(), - msg->readByte()); + printf("0x0119 %li %i %i %x %i\n", msg.readLong(), + msg.readShort(), msg.readShort(), msg.readShort(), + msg.readByte()); break; } } + +void +BeingHandler::handleBeingEnterMessage(MessageIn &msg) +{ + // Not sure what do to exactly with this message yet. + /* + unsigned char type = msg.readByte(); + unsigned long id = msg.readLong(); + + if (type == OBJECT_PLAYER) + { + std::string name = msg.readString(); + unsigned char hairStyle = msg.readByte(); + unsigned char hairColor = msg.readByte(); + unsigned char gender = msg.readByte(); + } + */ +} diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h index 03012f39..2dd81e1a 100644 --- a/src/net/beinghandler.h +++ b/src/net/beinghandler.h @@ -31,7 +31,11 @@ class BeingHandler : public MessageHandler public: BeingHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); + + private: + void + handleBeingEnterMessage(MessageIn &msg); }; #endif diff --git a/src/net/buysellhandler.cpp b/src/net/buysellhandler.cpp index 3b5fc87d..173c59d2 100644 --- a/src/net/buysellhandler.cpp +++ b/src/net/buysellhandler.cpp @@ -54,10 +54,10 @@ BuySellHandler::BuySellHandler() handledMessages = _messages; } -void BuySellHandler::handleMessage(MessageIn *msg) +void BuySellHandler::handleMessage(MessageIn &msg) { int n_items; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_NPC_BUY_SELL_CHOICE: buyDialog->setVisible(false); @@ -65,38 +65,38 @@ void BuySellHandler::handleMessage(MessageIn *msg) sellDialog->setVisible(false); sellDialog->reset(); buySellDialog->setVisible(true); - current_npc = dynamic_cast(beingManager->findBeing(msg->readLong())); + current_npc = dynamic_cast(beingManager->findBeing(msg.readLong())); break; case SMSG_NPC_BUY: - msg->readShort(); // length - n_items = (msg->getLength() - 4) / 11; + msg.readShort(); // length + n_items = (msg.getLength() - 4) / 11; buyDialog->reset(); buyDialog->setMoney(player_node->mMoney); buyDialog->setVisible(true); for (int k = 0; k < n_items; k++) { - Sint32 value = msg->readLong(); - msg->readLong(); // DCvalue - msg->readByte(); // type - Sint16 itemId = msg->readShort(); + Sint32 value = msg.readLong(); + msg.readLong(); // DCvalue + msg.readByte(); // type + Sint16 itemId = msg.readShort(); buyDialog->addItem(itemId, value); } break; case SMSG_NPC_SELL: - msg->readShort(); // length - n_items = (msg->getLength() - 4) / 10; + msg.readShort(); // length + n_items = (msg.getLength() - 4) / 10; if (n_items > 0) { sellDialog->reset(); sellDialog->setVisible(true); for (int k = 0; k < n_items; k++) { - Sint16 index = msg->readShort(); - Sint32 value = msg->readLong(); - msg->readLong(); // OCvalue + Sint16 index = msg.readShort(); + Sint32 value = msg.readLong(); + msg.readLong(); // OCvalue Item *item = player_node->getInvItem(index); if (item && !(item->isEquipped())) { @@ -111,7 +111,7 @@ void BuySellHandler::handleMessage(MessageIn *msg) break; case SMSG_NPC_BUY_RESPONSE: - if (msg->readByte() == 0) { + if (msg.readByte() == 0) { chatWindow->chatLog("Thanks for buying", BY_SERVER); } else { chatWindow->chatLog("Unable to buy", BY_SERVER); @@ -119,7 +119,7 @@ void BuySellHandler::handleMessage(MessageIn *msg) break; case SMSG_NPC_SELL_RESPONSE: - if (msg->readByte() == 0) { + if (msg.readByte() == 0) { chatWindow->chatLog("Thanks for selling", BY_SERVER); } else { chatWindow->chatLog("Unable to sell", BY_SERVER); diff --git a/src/net/buysellhandler.h b/src/net/buysellhandler.h index 673aaac1..e242d373 100644 --- a/src/net/buysellhandler.h +++ b/src/net/buysellhandler.h @@ -31,7 +31,7 @@ class BuySellHandler : public MessageHandler public: BuySellHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp index 2bf2c4b4..5a2be683 100644 --- a/src/net/charserverhandler.cpp +++ b/src/net/charserverhandler.cpp @@ -48,20 +48,20 @@ CharServerHandler::CharServerHandler() } void -CharServerHandler::handleMessage(MessageIn *msg) +CharServerHandler::handleMessage(MessageIn &msg) { int slot; LocalPlayer *tempPlayer; - switch (msg->getId()) + switch (msg.getId()) { case APMSG_CHAR_CREATE_RESPONSE: - handleCharCreateResponse(*msg); + handleCharCreateResponse(msg); break; case APMSG_CHAR_DELETE_RESPONSE: { - int errMsg = msg->readByte(); + int errMsg = msg.readByte(); // Character deletion successful if (errMsg == ERRMSG_OK) { @@ -101,7 +101,7 @@ CharServerHandler::handleMessage(MessageIn *msg) break; case APMSG_CHAR_SELECT_RESPONSE: - handleCharSelectResponse(*msg); + handleCharSelectResponse(msg); break; } } @@ -193,18 +193,18 @@ CharServerHandler::handleCharSelectResponse(MessageIn &msg) } LocalPlayer* -CharServerHandler::readPlayerData(MessageIn *msg, int &slot) +CharServerHandler::readPlayerData(MessageIn &msg, int &slot) { LocalPlayer *tempPlayer = new LocalPlayer(mLoginData->account_ID, 0, NULL); - slot = msg->readByte(); // character slot - tempPlayer->mName = msg->readString(); - tempPlayer->mSex = msg->readByte(); - tempPlayer->setHairStyle(msg->readByte()); - tempPlayer->setHairColor(msg->readByte()); - tempPlayer->mLevel = msg->readByte(); - tempPlayer->mMoney = msg->readShort(); + slot = msg.readByte(); // character slot + tempPlayer->mName = msg.readString(); + tempPlayer->mSex = msg.readByte(); + tempPlayer->setHairStyle(msg.readByte()); + tempPlayer->setHairColor(msg.readByte()); + tempPlayer->mLevel = msg.readByte(); + tempPlayer->mMoney = msg.readShort(); for (int i = 0; i < 6; i++) { - tempPlayer->mAttr[i] = msg->readByte(); + tempPlayer->mAttr[i] = msg.readByte(); } return tempPlayer; } diff --git a/src/net/charserverhandler.h b/src/net/charserverhandler.h index b034b513..9ad11c6a 100644 --- a/src/net/charserverhandler.h +++ b/src/net/charserverhandler.h @@ -37,7 +37,7 @@ class CharServerHandler : public MessageHandler CharServerHandler(); void - handleMessage(MessageIn *msg); + handleMessage(MessageIn &msg); void setCharInfo(LockedArray *charInfo) @@ -58,7 +58,8 @@ class CharServerHandler : public MessageHandler LoginData *mLoginData; LockedArray *mCharInfo; - LocalPlayer* readPlayerData(MessageIn *msg, int &slot); + LocalPlayer* + readPlayerData(MessageIn &msg, int &slot); }; #endif diff --git a/src/net/chathandler.cpp b/src/net/chathandler.cpp index d6f822f8..795b2a27 100644 --- a/src/net/chathandler.cpp +++ b/src/net/chathandler.cpp @@ -52,25 +52,25 @@ ChatHandler::ChatHandler() handledMessages = _messages; } -void ChatHandler::handleMessage(MessageIn *msg) +void ChatHandler::handleMessage(MessageIn &msg) { Being *being; std::string chatMsg; Sint16 chatMsgLength; - switch (msg->getId()) + switch (msg.getId()) { // Received speech from being case SMSG_BEING_CHAT: - chatMsgLength = msg->readShort() - 8; - being = beingManager->findBeing(msg->readLong()); + chatMsgLength = msg.readShort() - 8; + being = beingManager->findBeing(msg.readLong()); if (!being || chatMsgLength <= 0) { break; } - chatMsg = msg->readString(chatMsgLength); + chatMsg = msg.readString(chatMsgLength); chatWindow->chatLog(chatMsg, BY_OTHER); chatMsg.erase(0, chatMsg.find(" : ", 0) + 3); being->setSpeech(chatMsg, SPEECH_TIME); @@ -78,16 +78,16 @@ void ChatHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_CHAT: case SMSG_GM_CHAT: - chatMsgLength = msg->readShort() - 4; + chatMsgLength = msg.readShort() - 4; if (chatMsgLength <= 0) { break; } - chatMsg = msg->readString(chatMsgLength); + chatMsg = msg.readString(chatMsgLength); - if (msg->getId() == SMSG_PLAYER_CHAT) + if (msg.getId() == SMSG_PLAYER_CHAT) { chatWindow->chatLog(chatMsg, BY_PLAYER); @@ -105,13 +105,13 @@ void ChatHandler::handleMessage(MessageIn *msg) break; case SMSG_WHO_ANSWER: - chatWindow->chatLog("Online users: " + toString(msg->readLong()), + chatWindow->chatLog("Online users: " + toString(msg.readLong()), BY_SERVER); break; case 0x010c: // Display MVP player - msg->readLong(); // id + msg.readLong(); // id chatWindow->chatLog("MVP player", BY_SERVER); break; } diff --git a/src/net/chathandler.h b/src/net/chathandler.h index eed19206..e9db3575 100644 --- a/src/net/chathandler.h +++ b/src/net/chathandler.h @@ -31,7 +31,7 @@ class ChatHandler : public MessageHandler public: ChatHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/equipmenthandler.cpp b/src/net/equipmenthandler.cpp index aa372961..1c0fd4ca 100644 --- a/src/net/equipmenthandler.cpp +++ b/src/net/equipmenthandler.cpp @@ -48,7 +48,7 @@ EquipmentHandler::EquipmentHandler() handledMessages = _messages; } -void EquipmentHandler::handleMessage(MessageIn *msg) +void EquipmentHandler::handleMessage(MessageIn &msg) { Sint32 itemCount; Sint16 index, equipPoint, itemId; @@ -57,22 +57,22 @@ void EquipmentHandler::handleMessage(MessageIn *msg) Being *being; Item *item; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_PLAYER_EQUIPMENT: - msg->readShort(); // length - itemCount = (msg->getLength() - 4) / 20; + msg.readShort(); // length + itemCount = (msg.getLength() - 4) / 20; for (int loop = 0; loop < itemCount; loop++) { - index = msg->readShort(); - itemId = msg->readShort(); - msg->readByte(); // type - msg->readByte(); // identify flag - msg->readShort(); // equip type - equipPoint = msg->readShort(); - msg->readByte(); // attribute - msg->readByte(); // refine + index = msg.readShort(); + itemId = msg.readShort(); + msg.readByte(); // type + msg.readByte(); // identify flag + msg.readShort(); // equip type + equipPoint = msg.readShort(); + msg.readByte(); // attribute + msg.readByte(); // refine player_node->addInvItem(index, itemId, 1, true); @@ -92,9 +92,9 @@ void EquipmentHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_EQUIP: - index = msg->readShort(); - equipPoint = msg->readShort(); - type = msg->readByte(); + index = msg.readShort(); + equipPoint = msg.readShort(); + type = msg.readByte(); logger->log("Equipping: %i %i %i", index, equipPoint, type); @@ -128,10 +128,10 @@ void EquipmentHandler::handleMessage(MessageIn *msg) case 0x01d7: // Equipment related - being = beingManager->findBeing(msg->readLong()); - msg->readByte(); // equip point - itemId = msg->readShort(); - msg->readShort(); // item id 2 + being = beingManager->findBeing(msg.readLong()); + msg.readByte(); // equip point + itemId = msg.readShort(); + msg.readShort(); // item id 2 if (!being) break; @@ -140,9 +140,9 @@ void EquipmentHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_UNEQUIP: - index = msg->readShort(); - equipPoint = msg->readShort(); - type = msg->readByte(); + index = msg.readShort(); + equipPoint = msg.readShort(); + type = msg.readByte(); if (!type) { chatWindow->chatLog("Unable to unequip.", BY_SERVER); @@ -192,7 +192,7 @@ void EquipmentHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_ARROW_EQUIP: - itemId = msg->readShort(); + itemId = msg.readShort(); if (itemId <= 1) break; diff --git a/src/net/equipmenthandler.h b/src/net/equipmenthandler.h index 656f7a73..c9c65d67 100644 --- a/src/net/equipmenthandler.h +++ b/src/net/equipmenthandler.h @@ -31,7 +31,7 @@ class EquipmentHandler : public MessageHandler public: EquipmentHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/inventoryhandler.cpp b/src/net/inventoryhandler.cpp index 51c71f8d..cb1883b0 100644 --- a/src/net/inventoryhandler.cpp +++ b/src/net/inventoryhandler.cpp @@ -46,27 +46,27 @@ InventoryHandler::InventoryHandler() handledMessages = _messages; } -void InventoryHandler::handleMessage(MessageIn *msg) +void InventoryHandler::handleMessage(MessageIn &msg) { Sint32 number; Sint16 index, amount, itemId, equipType; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_PLAYER_INVENTORY: // Only called on map load / warp. First reset all items // to not load them twice on map change. player_node->clearInventory(); - msg->readShort(); // length - number = (msg->getLength() - 4) / 18; + msg.readShort(); // length + number = (msg.getLength() - 4) / 18; for (int loop = 0; loop < number; loop++) { - index = msg->readShort(); - itemId = msg->readShort(); - msg->readByte(); // type - msg->readByte(); // identify flag - amount = msg->readShort(); + index = msg.readShort(); + itemId = msg.readShort(); + msg.readByte(); // type + msg.readByte(); // identify flag + amount = msg.readShort(); player_node->addInvItem(index, itemId, amount, false); @@ -79,16 +79,16 @@ void InventoryHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_INVENTORY_ADD: - index = msg->readShort(); - amount = msg->readShort(); - itemId = msg->readShort(); - msg->readByte(); // identify flag - msg->readByte(); // attribute - msg->readByte(); // refine - equipType = msg->readShort(); - msg->readByte(); // type - - if (msg->readByte()> 0) { + index = msg.readShort(); + amount = msg.readShort(); + itemId = msg.readShort(); + msg.readByte(); // identify flag + msg.readByte(); // attribute + msg.readByte(); // refine + equipType = msg.readShort(); + msg.readByte(); // type + + if (msg.readByte()> 0) { chatWindow->chatLog("Unable to pick up item", BY_SERVER); } else { player_node->addInvItem(index, itemId, amount, equipType != 0); @@ -96,26 +96,26 @@ void InventoryHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_INVENTORY_REMOVE: - index = msg->readShort(); - amount = msg->readShort(); + index = msg.readShort(); + amount = msg.readShort(); player_node->getInvItem(index)->increaseQuantity(-amount); break; case SMSG_PLAYER_INVENTORY_USE: - index = msg->readShort(); - msg->readShort(); // item id - msg->readLong(); // id - amount = msg->readShort(); - msg->readByte(); // type + index = msg.readShort(); + msg.readShort(); // item id + msg.readLong(); // id + amount = msg.readShort(); + msg.readByte(); // type player_node->getInvItem(index)->setQuantity(amount); break; case SMSG_ITEM_USE_RESPONSE: - index = msg->readShort(); - amount = msg->readShort(); + index = msg.readShort(); + amount = msg.readShort(); - if (msg->readByte() == 0) { + if (msg.readByte() == 0) { chatWindow->chatLog("Failed to use item", BY_SERVER); } else { player_node->getInvItem(index)->setQuantity(amount); diff --git a/src/net/inventoryhandler.h b/src/net/inventoryhandler.h index aedbc3a1..4190bf83 100644 --- a/src/net/inventoryhandler.h +++ b/src/net/inventoryhandler.h @@ -31,7 +31,7 @@ class InventoryHandler : public MessageHandler public: InventoryHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/itemhandler.cpp b/src/net/itemhandler.cpp index 23a9fa60..2961f71b 100644 --- a/src/net/itemhandler.cpp +++ b/src/net/itemhandler.cpp @@ -40,28 +40,28 @@ ItemHandler::ItemHandler() handledMessages = _messages; } -void ItemHandler::handleMessage(MessageIn *msg) +void ItemHandler::handleMessage(MessageIn &msg) { Uint32 id; Uint16 x, y; Sint16 itemId; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_ITEM_VISIBLE: case SMSG_ITEM_DROPPED: - id = msg->readLong(); - itemId = msg->readShort(); - msg->readByte(); // identify flag - x = msg->readShort(); - y = msg->readShort(); + id = msg.readLong(); + itemId = msg.readShort(); + msg.readByte(); // identify flag + x = msg.readShort(); + y = msg.readShort(); floorItemManager->create(id, itemId, x, y, engine->getCurrentMap()); break; case SMSG_ITEM_REMOVE: FloorItem *item; - item = floorItemManager->findById(msg->readLong()); + item = floorItemManager->findById(msg.readLong()); if (item) floorItemManager->destroy(item); break; diff --git a/src/net/itemhandler.h b/src/net/itemhandler.h index b2104722..5ffcb134 100644 --- a/src/net/itemhandler.h +++ b/src/net/itemhandler.h @@ -31,7 +31,7 @@ class ItemHandler : public MessageHandler public: ItemHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/loginhandler.cpp b/src/net/loginhandler.cpp index 4790d7d1..700fb75a 100644 --- a/src/net/loginhandler.cpp +++ b/src/net/loginhandler.cpp @@ -41,13 +41,13 @@ LoginHandler::LoginHandler() handledMessages = _messages; } -void LoginHandler::handleMessage(MessageIn *msg) +void LoginHandler::handleMessage(MessageIn &msg) { - switch (msg->getId()) + switch (msg.getId()) { case APMSG_LOGIN_RESPONSE: { - int errMsg = msg->readByte(); + int errMsg = msg.readByte(); // Successful login if (errMsg == ERRMSG_OK) { @@ -79,7 +79,7 @@ void LoginHandler::handleMessage(MessageIn *msg) break; case APMSG_REGISTER_RESPONSE: { - int errMsg = msg->readByte(); + int errMsg = msg.readByte(); // Successful registration if (errMsg == ERRMSG_OK) { diff --git a/src/net/loginhandler.h b/src/net/loginhandler.h index 1b15b736..508ec0f5 100644 --- a/src/net/loginhandler.h +++ b/src/net/loginhandler.h @@ -36,7 +36,7 @@ class LoginHandler : public MessageHandler public: LoginHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); void setLoginData(LoginData *loginData) { mLoginData = loginData; }; diff --git a/src/net/maploginhandler.cpp b/src/net/maploginhandler.cpp index 579e8542..323e07fb 100644 --- a/src/net/maploginhandler.cpp +++ b/src/net/maploginhandler.cpp @@ -40,14 +40,14 @@ MapLoginHandler::MapLoginHandler() handledMessages = _messages; } -void MapLoginHandler::handleMessage(MessageIn *msg) +void MapLoginHandler::handleMessage(MessageIn &msg) { //unsigned char direction; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_LOGIN_SUCCESS: - msg->readLong(); // server tick + msg.readLong(); // server tick //logger->log("Protocol: Player start position: (%d, %d), Direction: %d", // player_node->mX, player_node->mY, direction); state = STATE_GAME; diff --git a/src/net/maploginhandler.h b/src/net/maploginhandler.h index fe597549..3f779753 100644 --- a/src/net/maploginhandler.h +++ b/src/net/maploginhandler.h @@ -31,7 +31,7 @@ class MapLoginHandler : public MessageHandler public: MapLoginHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/messagehandler.h b/src/net/messagehandler.h index c09037f6..9f92636d 100644 --- a/src/net/messagehandler.h +++ b/src/net/messagehandler.h @@ -37,7 +37,7 @@ class MessageHandler MessageHandler(); virtual ~MessageHandler(); - virtual void handleMessage(MessageIn *msg) =0; + virtual void handleMessage(MessageIn &msg) = 0; void setNetwork(Network *network); diff --git a/src/net/messagein.cpp b/src/net/messagein.cpp index 7e85a813..23ea8181 100644 --- a/src/net/messagein.cpp +++ b/src/net/messagein.cpp @@ -27,8 +27,6 @@ #include -#include "packet.h" - MessageIn::MessageIn(const char *data, unsigned int length): mData(data), mLength(length), diff --git a/src/net/messageout.cpp b/src/net/messageout.cpp index 426a1c0d..4fca662a 100644 --- a/src/net/messageout.cpp +++ b/src/net/messageout.cpp @@ -27,8 +27,6 @@ #include -#include "packet.h" - MessageOut::MessageOut(): mData(0), mDataSize(0), diff --git a/src/net/network.cpp b/src/net/network.cpp index 2ce6fc2b..08b5fe92 100644 --- a/src/net/network.cpp +++ b/src/net/network.cpp @@ -160,7 +160,7 @@ Network::dispatchMessage(ENetPacket *packet) if (iter != mMessageHandlers.end()) { logger->log("Received packet %x (%i B)", msg.getId(), msg.getLength()); - iter->second->handleMessage(&msg); + iter->second->handleMessage(msg); } else { logger->log("Unhandled packet %x (%i B)", diff --git a/src/net/npchandler.cpp b/src/net/npchandler.cpp index 62355180..9c89e71f 100644 --- a/src/net/npchandler.cpp +++ b/src/net/npchandler.cpp @@ -47,21 +47,23 @@ NPCHandler::NPCHandler() handledMessages = _messages; } -void NPCHandler::handleMessage(MessageIn *msg) +void NPCHandler::handleMessage(MessageIn &msg) { - switch (msg->getId()) + switch (msg.getId()) { case SMSG_NPC_CHOICE: - msg->readShort(); // length - current_npc = dynamic_cast(beingManager->findBeing(msg->readLong())); - npcListDialog->parseItems(msg->readString(msg->getLength() - 8)); + msg.readShort(); // length + current_npc = dynamic_cast( + beingManager->findBeing(msg.readLong())); + npcListDialog->parseItems(msg.readString(msg.getLength() - 8)); npcListDialog->setVisible(true); break; case SMSG_NPC_MESSAGE: - msg->readShort(); // length - current_npc = dynamic_cast(beingManager->findBeing(msg->readLong())); - npcTextDialog->addText(msg->readString(msg->getLength() - 8)); + msg.readShort(); // length + current_npc = dynamic_cast( + beingManager->findBeing(msg.readLong())); + npcTextDialog->addText(msg.readString(msg.getLength() - 8)); npcListDialog->setVisible(false); npcTextDialog->setVisible(true); break; diff --git a/src/net/npchandler.h b/src/net/npchandler.h index 903ecd10..0cb40f64 100644 --- a/src/net/npchandler.h +++ b/src/net/npchandler.h @@ -31,7 +31,7 @@ class NPCHandler : public MessageHandler public: NPCHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/packet.cpp b/src/net/packet.cpp deleted file mode 100644 index e77ac117..00000000 --- a/src/net/packet.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * The Mana World - * Copyright 2004 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id$ - */ - -#include "packet.h" - -#include - -Packet::Packet(const char *data, int length): - mLength(length) -{ - // Create a copy of the data - mData = new char[mLength]; - memcpy(mData, data, mLength); -} - -Packet::~Packet() -{ - // Clean up the data - delete[] mData; -} diff --git a/src/net/packet.h b/src/net/packet.h deleted file mode 100644 index 84d16d5e..00000000 --- a/src/net/packet.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * The Mana World - * Copyright 2004 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id$ - */ - -#ifndef _TMW_PACKET_ -#define _TMW_PACKET_ - -/** - * A packet wraps a certain amount of bytes for sending and receiving. - */ -class Packet -{ - public: - /** - * Constructor. - */ - Packet(const char *data, int length); - - /** - * Destructor. - */ - ~Packet(); - - char *mData; /**< Packet data */ - unsigned int mLength; /**< Length of data in bytes */ -}; - -#endif diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp index d8ff81f4..f6065aaf 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/playerhandler.cpp @@ -46,7 +46,9 @@ OkDialog *deathNotice = NULL; namespace { struct WeightListener : public gcn::ActionListener { - void action(const std::string &eventId, gcn::Widget *widget) { weightNotice = NULL; } + void action(const std::string &eventId, gcn::Widget *widget) { + weightNotice = NULL; + } } weightListener; } @@ -80,9 +82,9 @@ PlayerHandler::PlayerHandler() handledMessages = _messages; } -void PlayerHandler::handleMessage(MessageIn *msg) +void PlayerHandler::handleMessage(MessageIn &msg) { - switch (msg->getId()) + switch (msg.getId()) { case SMSG_WALK_RESPONSE: // It is assumed by the client any request to walk actually @@ -93,9 +95,9 @@ void PlayerHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_WARP: { - std::string mapPath = msg->readString(16); - Uint16 x = msg->readShort(); - Uint16 y = msg->readShort(); + std::string mapPath = msg.readString(16); + Uint16 x = msg.readShort(); + Uint16 y = msg.readShort(); logger->log("Warping to %s (%d, %d)", mapPath.c_str(), x, y); @@ -114,13 +116,13 @@ void PlayerHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_STAT_UPDATE_1: { - Sint16 type = msg->readShort(); - Uint32 value = msg->readLong(); + Sint16 type = msg.readShort(); + Uint32 value = msg.readLong(); switch (type) { //case 0x0000: - // player_node->setWalkSpeed(msg->readLong()); + // player_node->setWalkSpeed(msg.readLong()); // break; case 0x0005: player_node->mHp = value; break; case 0x0006: player_node->mMaxHp = value; break; @@ -169,30 +171,30 @@ void PlayerHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_STAT_UPDATE_2: - switch (msg->readShort()) { + switch (msg.readShort()) { case 0x0001: - player_node->mXp = msg->readLong(); + player_node->mXp = msg.readLong(); break; case 0x0002: - player_node->mJobXp = msg->readLong(); + player_node->mJobXp = msg.readLong(); break; case 0x0014: - player_node->mMoney = msg->readLong(); + player_node->mMoney = msg.readLong(); break; case 0x0016: - player_node->mXpForNextLevel = msg->readLong(); + player_node->mXpForNextLevel = msg.readLong(); break; case 0x0017: - player_node->mJobXpForNextLevel = msg->readLong(); + player_node->mJobXpForNextLevel = msg.readLong(); break; } break; case SMSG_PLAYER_STAT_UPDATE_3: { - Sint32 type = msg->readLong(); - Sint32 base = msg->readLong(); - Sint32 bonus = msg->readLong(); + Sint32 type = msg.readLong(); + Sint32 base = msg.readLong(); + Sint32 bonus = msg.readLong(); Sint32 total = base + bonus; switch (type) { @@ -214,9 +216,9 @@ void PlayerHandler::handleMessage(MessageIn *msg) case SMSG_PLAYER_STAT_UPDATE_4: { - Sint16 type = msg->readShort(); - Sint8 fail = msg->readByte(); - Sint8 value = msg->readByte(); + Sint16 type = msg.readShort(); + Sint8 fail = msg.readByte(); + Sint8 value = msg.readByte(); if (fail != 1) break; @@ -240,60 +242,60 @@ void PlayerHandler::handleMessage(MessageIn *msg) // Updates stats and status points case SMSG_PLAYER_STAT_UPDATE_5: - player_node->mStatsPointsToAttribute = msg->readShort(); - player_node->mAttr[LocalPlayer::STR] = msg->readByte(); - player_node->mAttrUp[LocalPlayer::STR] = msg->readByte(); - player_node->mAttr[LocalPlayer::AGI] = msg->readByte(); - player_node->mAttrUp[LocalPlayer::AGI] = msg->readByte(); - player_node->mAttr[LocalPlayer::VIT] = msg->readByte(); - player_node->mAttrUp[LocalPlayer::VIT] = msg->readByte(); - player_node->mAttr[LocalPlayer::INT] = msg->readByte(); - player_node->mAttrUp[LocalPlayer::INT] = msg->readByte(); - player_node->mAttr[LocalPlayer::DEX] = msg->readByte(); - player_node->mAttrUp[LocalPlayer::DEX] = msg->readByte(); - player_node->mAttr[LocalPlayer::LUK] = msg->readByte(); - player_node->mAttrUp[LocalPlayer::LUK] = msg->readByte(); - player_node->ATK = msg->readShort(); // ATK - player_node->ATK_BONUS = msg->readShort(); // ATK bonus - player_node->MATK = msg->readShort(); // MATK max - player_node->MATK_BONUS = msg->readShort(); // MATK min - player_node->DEF = msg->readShort(); // DEF - player_node->DEF_BONUS = msg->readShort(); // DEF bonus - player_node->MDEF = msg->readShort(); // MDEF - player_node->MDEF_BONUS = msg->readShort(); // MDEF bonus - player_node->HIT = msg->readShort(); // HIT - player_node->FLEE = msg->readShort(); // FLEE - player_node->FLEE_BONUS = msg->readShort(); // FLEE bonus - msg->readShort(); // critical - msg->readShort(); // unknown + player_node->mStatsPointsToAttribute = msg.readShort(); + player_node->mAttr[LocalPlayer::STR] = msg.readByte(); + player_node->mAttrUp[LocalPlayer::STR] = msg.readByte(); + player_node->mAttr[LocalPlayer::AGI] = msg.readByte(); + player_node->mAttrUp[LocalPlayer::AGI] = msg.readByte(); + player_node->mAttr[LocalPlayer::VIT] = msg.readByte(); + player_node->mAttrUp[LocalPlayer::VIT] = msg.readByte(); + player_node->mAttr[LocalPlayer::INT] = msg.readByte(); + player_node->mAttrUp[LocalPlayer::INT] = msg.readByte(); + player_node->mAttr[LocalPlayer::DEX] = msg.readByte(); + player_node->mAttrUp[LocalPlayer::DEX] = msg.readByte(); + player_node->mAttr[LocalPlayer::LUK] = msg.readByte(); + player_node->mAttrUp[LocalPlayer::LUK] = msg.readByte(); + player_node->ATK = msg.readShort(); // ATK + player_node->ATK_BONUS = msg.readShort(); // ATK bonus + player_node->MATK = msg.readShort(); // MATK max + player_node->MATK_BONUS = msg.readShort(); // MATK min + player_node->DEF = msg.readShort(); // DEF + player_node->DEF_BONUS = msg.readShort(); // DEF bonus + player_node->MDEF = msg.readShort(); // MDEF + player_node->MDEF_BONUS = msg.readShort(); // MDEF bonus + player_node->HIT = msg.readShort(); // HIT + player_node->FLEE = msg.readShort(); // FLEE + player_node->FLEE_BONUS = msg.readShort(); // FLEE bonus + msg.readShort(); // critical + msg.readShort(); // unknown break; case SMSG_PLAYER_STAT_UPDATE_6: - switch (msg->readShort()) { + switch (msg.readShort()) { case 0x0020: - player_node->mAttrUp[LocalPlayer::STR] = msg->readByte(); + player_node->mAttrUp[LocalPlayer::STR] = msg.readByte(); break; case 0x0021: - player_node->mAttrUp[LocalPlayer::AGI] = msg->readByte(); + player_node->mAttrUp[LocalPlayer::AGI] = msg.readByte(); break; case 0x0022: - player_node->mAttrUp[LocalPlayer::VIT] = msg->readByte(); + player_node->mAttrUp[LocalPlayer::VIT] = msg.readByte(); break; case 0x0023: - player_node->mAttrUp[LocalPlayer::INT] = msg->readByte(); + player_node->mAttrUp[LocalPlayer::INT] = msg.readByte(); break; case 0x0024: - player_node->mAttrUp[LocalPlayer::DEX] = msg->readByte(); + player_node->mAttrUp[LocalPlayer::DEX] = msg.readByte(); break; case 0x0025: - player_node->mAttrUp[LocalPlayer::LUK] = msg->readByte(); + player_node->mAttrUp[LocalPlayer::LUK] = msg.readByte(); break; } break; case SMSG_PLAYER_ARROW_MESSAGE: { - Sint16 type = msg->readShort(); + Sint16 type = msg.readShort(); switch (type) { case 0: diff --git a/src/net/playerhandler.h b/src/net/playerhandler.h index b28a23f5..6d0baef7 100644 --- a/src/net/playerhandler.h +++ b/src/net/playerhandler.h @@ -31,7 +31,7 @@ class PlayerHandler : public MessageHandler public: PlayerHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/skillhandler.cpp b/src/net/skillhandler.cpp index 89009e47..d9bea775 100644 --- a/src/net/skillhandler.cpp +++ b/src/net/skillhandler.cpp @@ -39,27 +39,27 @@ SkillHandler::SkillHandler() handledMessages = _messages; } -void SkillHandler::handleMessage(MessageIn *msg) +void SkillHandler::handleMessage(MessageIn &msg) { int skillCount; - switch (msg->getId()) + switch (msg.getId()) { case SMSG_PLAYER_SKILLS: - msg->readShort(); // length - skillCount = (msg->getLength() - 4) / 37; + msg.readShort(); // length + skillCount = (msg.getLength() - 4) / 37; skillDialog->cleanList(); for (int k = 0; k < skillCount; k++) { - Sint16 skillId = msg->readShort(); - msg->readShort(); // target type - msg->readShort(); // unknown - Sint16 level = msg->readShort(); - Sint16 sp = msg->readShort(); - msg->readShort(); // range - std::string skillName = msg->readString(24); - Sint8 up = msg->readByte(); + Sint16 skillId = msg.readShort(); + msg.readShort(); // target type + msg.readShort(); // unknown + Sint16 level = msg.readShort(); + Sint16 sp = msg.readShort(); + msg.readShort(); // range + std::string skillName = msg.readString(24); + Sint8 up = msg.readByte(); if (level != 0 || up != 0) { @@ -77,11 +77,11 @@ void SkillHandler::handleMessage(MessageIn *msg) // Action failed (ex. sit because you have not reached the // right level) CHATSKILL action; - action.skill = msg->readShort(); - action.bskill = msg->readShort(); - action.unused = msg->readShort(); // unknown - action.success = msg->readByte(); - action.reason = msg->readByte(); + action.skill = msg.readShort(); + action.bskill = msg.readShort(); + action.unused = msg.readShort(); // unknown + action.success = msg.readByte(); + action.reason = msg.readByte(); if (action.success != SKILL_FAILED && action.bskill == BSKILL_EMOTE) { diff --git a/src/net/skillhandler.h b/src/net/skillhandler.h index 820a7b6a..8c0653d4 100644 --- a/src/net/skillhandler.h +++ b/src/net/skillhandler.h @@ -31,7 +31,7 @@ class SkillHandler : public MessageHandler public: SkillHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/tradehandler.cpp b/src/net/tradehandler.cpp index b0baa5ea..2ebc160f 100644 --- a/src/net/tradehandler.cpp +++ b/src/net/tradehandler.cpp @@ -63,9 +63,9 @@ TradeHandler::TradeHandler() handledMessages = _messages; } -void TradeHandler::handleMessage(MessageIn *msg) +void TradeHandler::handleMessage(MessageIn &msg) { - switch (msg->getId()) + switch (msg.getId()) { case SMSG_TRADE_REQUEST: // If a trade window or request window is already open, send a @@ -81,7 +81,7 @@ void TradeHandler::handleMessage(MessageIn *msg) } player_node->setTrading(true); - tradePartnerName = msg->readString(24); + tradePartnerName = msg.readString(24); ConfirmDialog *dlg; dlg = new ConfirmDialog("Request for trade", tradePartnerName + @@ -90,7 +90,7 @@ void TradeHandler::handleMessage(MessageIn *msg) break; case SMSG_TRADE_RESPONSE: - switch (msg->readByte()) + switch (msg.readByte()) { case 0: // Too far away chatWindow->chatLog("Trading isn't possible. " @@ -126,11 +126,11 @@ void TradeHandler::handleMessage(MessageIn *msg) case SMSG_TRADE_ITEM_ADD: { - Sint32 amount = msg->readLong(); - Sint16 type = msg->readShort(); - msg->readByte(); // identified flag - msg->readByte(); // attribute - msg->readByte(); // refine + Sint32 amount = msg.readLong(); + Sint16 type = msg.readShort(); + msg.readByte(); // identified flag + msg.readByte(); // attribute + msg.readByte(); // refine // TODO: handle also identified, etc if (type == 0) { @@ -144,10 +144,10 @@ void TradeHandler::handleMessage(MessageIn *msg) case SMSG_TRADE_ITEM_ADD_RESPONSE: // Trade: New Item add response (was 0x00ea, now 01b1) { - Item *item = player_node->getInvItem(msg->readShort()); - Sint16 quantity = msg->readShort(); + Item *item = player_node->getInvItem(msg.readShort()); + Sint16 quantity = msg.readShort(); - switch (msg->readByte()) + switch (msg.readByte()) { case 0: // Successfully added item @@ -175,7 +175,7 @@ void TradeHandler::handleMessage(MessageIn *msg) case SMSG_TRADE_OK: // 0 means ok from myself, 1 means ok from other; - tradeWindow->receivedOk(msg->readByte() == 0); + tradeWindow->receivedOk(msg.readByte() == 0); break; case SMSG_TRADE_CANCEL: diff --git a/src/net/tradehandler.h b/src/net/tradehandler.h index a1971004..0b73c871 100644 --- a/src/net/tradehandler.h +++ b/src/net/tradehandler.h @@ -33,7 +33,7 @@ class TradeHandler : public MessageHandler public: TradeHandler(); - void handleMessage(MessageIn *msg); + void handleMessage(MessageIn &msg); }; #endif -- cgit v1.2.3-70-g09d2 From 5cc5c903df7b535c6bf27987b89a405812d89735 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sat, 26 Aug 2006 13:28:35 +0000 Subject: Implemented "say around" chat. --- ChangeLog | 7 +++++++ src/gui/chat.cpp | 9 ++++----- src/net/beinghandler.cpp | 27 ++++++++++++++++----------- src/net/chathandler.cpp | 17 +++++++++++++++++ src/net/protocol.h | 2 +- 5 files changed, 45 insertions(+), 17 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 035f2688..3406dbdc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2006-08-26 Guillaume Melquiond + + * src/net/chathandler.cpp, src/gui/chat.cpp, src/net/protocol.h: Added + support for "say around" messages. + * src/net/beinghandler.cpp: Partly implemented being creation, so that + chat works. + 2006-08-21 Eugenio Favalli * The Mana World.dev, tmw.cbp: Updated project files. diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp index 592439fc..e8bb1cc6 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -37,6 +37,7 @@ #include "../localplayer.h" #include "../net/messageout.h" +#include "../net/network.h" #include "../net/protocol.h" ChatWindow::ChatWindow(Network *network): @@ -249,12 +250,10 @@ ChatWindow::chatSend(const std::string &nick, std::string msg) // Prepare ordinary message if (msg.substr(0, 1) != "/") { - msg = nick + " : " + msg; - MessageOut outMsg; - outMsg.writeShort(CMSG_CHAT_MESSAGE); - outMsg.writeShort(msg.length() + 4); - outMsg.writeString(msg, msg.length()); + outMsg.writeShort(PGMSG_SAY); + outMsg.writeString(msg); + network->send(Network::GAME, outMsg); } else if (msg.substr(0, IS_ANNOUNCE_LENGTH) == IS_ANNOUNCE) { diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index ed0fc4b2..10de5351 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -383,17 +383,22 @@ void BeingHandler::handleMessage(MessageIn &msg) void BeingHandler::handleBeingEnterMessage(MessageIn &msg) { - // Not sure what do to exactly with this message yet. - /* - unsigned char type = msg.readByte(); - unsigned long id = msg.readLong(); - - if (type == OBJECT_PLAYER) + msg.readByte(); // type + int id = msg.readLong(); + std::string name = msg.readString(); + Being *being; + if (player_node->getName() == name) + { + being = player_node; + being->setId(id); + } + else { - std::string name = msg.readString(); - unsigned char hairStyle = msg.readByte(); - unsigned char hairColor = msg.readByte(); - unsigned char gender = msg.readByte(); + // assume type is player for now, so job 0, TODO + being = beingManager->createBeing(id, 0); + being->setName(name); } - */ + being->setHairStyle(msg.readByte() + 1); + being->setHairColor(msg.readByte() + 1); + being->setSex(msg.readByte()); } diff --git a/src/net/chathandler.cpp b/src/net/chathandler.cpp index 795b2a27..02f99c41 100644 --- a/src/net/chathandler.cpp +++ b/src/net/chathandler.cpp @@ -42,11 +42,14 @@ extern Being *player_node; ChatHandler::ChatHandler() { static const Uint16 _messages[] = { + GPMSG_SAY, + /* SMSG_BEING_CHAT, SMSG_PLAYER_CHAT, SMSG_GM_CHAT, SMSG_WHO_ANSWER, 0x10c, // MVP + */ 0 }; handledMessages = _messages; @@ -60,6 +63,20 @@ void ChatHandler::handleMessage(MessageIn &msg) switch (msg.getId()) { + case GPMSG_SAY: + being = beingManager->findBeing(msg.readLong()); + chatMsg = msg.readString(); + if (being) + { + chatWindow->chatLog(being->getName() + " : " + chatMsg, being == player_node ? BY_PLAYER : BY_OTHER); + being->setSpeech(chatMsg, SPEECH_TIME); + } + else + { + chatWindow->chatLog("John Doe : " + chatMsg, BY_OTHER); + } + break; + // Received speech from being case SMSG_BEING_CHAT: chatMsgLength = msg.readShort() - 8; diff --git a/src/net/protocol.h b/src/net/protocol.h index 6927f3fd..33d72c96 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -157,7 +157,7 @@ enum { GPMSG_BEING_LEAVE = 0x0201, // B type, L being id PGMSG_WALK = 0x0260, // L*2 destination PGMSG_SAY = 0x02A0, // S text - GPMSG_SAY = 0x02A1, // S being, S text + GPMSG_SAY = 0x02A1, // L being id, S text PGMSG_USE_ITEM = 0x0300, // L item id GPMSG_USE_RESPONSE = 0x0301, // B error PGMSG_EQUIP = 0x0302, // L item id, B slot -- cgit v1.2.3-70-g09d2 From ef4486580fc7b8293555fcabc398ed0c2b90d78e Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Sat, 26 Aug 2006 16:01:24 +0000 Subject: Got rid of numerous additions and substractions to the hair style and color. Hair style 0 was added and defined as being bald (so bald is no longer a hardcoded style). --- ChangeLog | 9 +++++++++ src/being.cpp | 12 ++---------- src/being.h | 2 +- src/gui/char_select.cpp | 11 +++++------ src/gui/playerbox.cpp | 5 +++-- src/main.cpp | 2 +- src/net/beinghandler.cpp | 4 ++-- src/player.cpp | 8 ++++---- 8 files changed, 27 insertions(+), 26 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 3406dbdc..8b763f7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2006-08-26 Bjørn Lindeijer + + * src/gui/char_select.cpp, src/gui/playerbox.cpp, src/player.cpp, + src/main.cpp, src/being.cpp, src/net/beinghandler.cpp, src/being.h, + data/graphics/sprites/hairstyle0.xml, + data/graphics/sprites/Makefile.am: Got rid of numerous additions and + substractions to the hair style and color. Hair style 0 was added and + defined as being bald (so bald is no longer a hardcoded style). + 2006-08-26 Guillaume Melquiond * src/net/chathandler.cpp, src/gui/chat.cpp, src/net/protocol.h: Added diff --git a/src/being.cpp b/src/being.cpp index 7755d4e5..70e3eb8e 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -104,21 +104,13 @@ Being::setPath(const Path &path) void Being::setHairColor(Uint16 color) { - mHairColor = color; - if (mHairColor < 1 || mHairColor > NR_HAIR_COLORS + 1) - { - mHairColor = 1; - } + mHairColor = (color < NR_HAIR_COLORS) ? color : 0; } void Being::setHairStyle(Uint16 style) { - mHairStyle = style; - if (mHairStyle < 1 || mHairStyle > NR_HAIR_STYLES) - { - mHairStyle = 1; - } + mHairStyle = (style < NR_HAIR_STYLES) ? style : 0; } void diff --git a/src/being.h b/src/being.h index 055ea0d4..496f183d 100644 --- a/src/being.h +++ b/src/being.h @@ -33,7 +33,7 @@ #include "map.h" #include "animatedsprite.h" -#define NR_HAIR_STYLES 7 +#define NR_HAIR_STYLES 8 #define NR_HAIR_COLORS 10 class AnimatedSprite; diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp index 2fa6c68e..3db82287 100644 --- a/src/gui/char_select.cpp +++ b/src/gui/char_select.cpp @@ -183,8 +183,8 @@ void CharSelectDialog::updatePlayerInfo() mDelCharButton->setEnabled(true); mSelectButton->setEnabled(true); } - mPlayerBox->mHairStyle = pi->getHairStyle() - 1; - mPlayerBox->mHairColor = pi->getHairColor() - 1; + mPlayerBox->mHairStyle = pi->getHairStyle(); + mPlayerBox->mHairColor = pi->getHairColor(); mPlayerBox->mSex = pi->getSex(); mPlayerBox->mShowPlayer = true; } else { @@ -324,11 +324,10 @@ std::string CharCreateDialog::getName() void CharCreateDialog::attemptCharCreate() { // Send character infos - MessageOut outMsg; - outMsg.writeShort(PAMSG_CHAR_CREATE); + MessageOut outMsg(PAMSG_CHAR_CREATE); outMsg.writeString(getName()); - outMsg.writeByte(mPlayerBox->mHairStyle + 1); - outMsg.writeByte(mPlayerBox->mHairColor + 1); + outMsg.writeByte(mPlayerBox->mHairStyle); + outMsg.writeByte(mPlayerBox->mHairColor); // TODO: send selected sex outMsg.writeByte(0); // Player sex outMsg.writeShort(10); // STR diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp index d8faff99..ba97d54c 100644 --- a/src/gui/playerbox.cpp +++ b/src/gui/playerbox.cpp @@ -94,12 +94,13 @@ void PlayerBox::draw(gcn::Graphics *graphics) playerset[mSex]->get(0), 23, 12); // Draw his hair - if (mHairColor < NR_HAIR_COLORS && mHairStyle < NR_HAIR_STYLES) + if (mHairStyle > 0 && mHairColor < NR_HAIR_COLORS && + mHairStyle < NR_HAIR_STYLES) { int hf = 9 * mHairColor; if (hf >= 0 && hf < (int)hairset[mHairStyle]->size()) { dynamic_cast(graphics)->drawImage( - hairset[mHairStyle]->get(hf), 35, 7); + hairset[mHairStyle - 1]->get(hf), 35, 7); } } } diff --git a/src/main.cpp b/src/main.cpp index ef5557ec..4e65e4fc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -257,7 +257,7 @@ void init_engine() if (!playerset[1]) logger->error("Couldn't load female player spriteset!"); - for (int i = 0; i < NR_HAIR_STYLES; i++) + for (int i = 0; i < NR_HAIR_STYLES - 1; i++) { Spriteset *tmp = ResourceManager::getInstance()->getSpriteset( "graphics/sprites/hairstyle" + toString(i + 1) + ".png", diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 10de5351..c85e8893 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -398,7 +398,7 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) being = beingManager->createBeing(id, 0); being->setName(name); } - being->setHairStyle(msg.readByte() + 1); - being->setHairColor(msg.readByte() + 1); + being->setHairStyle(msg.readByte()); + being->setHairColor(msg.readByte()); being->setSex(msg.readByte()); } diff --git a/src/player.cpp b/src/player.cpp index b864dd0e..3f4abebb 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -114,12 +114,12 @@ Player::setSex(Uint8 sex) void Player::setHairColor(Uint16 color) { - if (color != mHairColor && mHairStyle > 0) + if (color != mHairColor) { delete mSprites[HAIR_SPRITE]; AnimatedSprite *newHairSprite = new AnimatedSprite( "graphics/sprites/hairstyle" + toString(mHairStyle) + ".xml", - color - 1); + color); newHairSprite->setDirection(getSpriteDirection()); mSprites[HAIR_SPRITE] = newHairSprite; @@ -133,12 +133,12 @@ Player::setHairColor(Uint16 color) void Player::setHairStyle(Uint16 style) { - if (style != mHairStyle && mHairColor > 0) + if (style != mHairStyle) { delete mSprites[HAIR_SPRITE]; AnimatedSprite *newHairSprite = new AnimatedSprite( "graphics/sprites/hairstyle" + toString(style) + ".xml", - mHairColor - 1); + mHairColor); newHairSprite->setDirection(getSpriteDirection()); mSprites[HAIR_SPRITE] = newHairSprite; -- cgit v1.2.3-70-g09d2 From fd279ae77295a6babedd31202078862eabcada9f Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sat, 26 Aug 2006 19:26:41 +0000 Subject: Handle "beings move" messages. --- ChangeLog | 2 ++ src/net/beinghandler.cpp | 24 ++++++++++++++++++++++++ src/net/beinghandler.h | 4 ++-- src/net/protocol.h | 1 + 4 files changed, 29 insertions(+), 2 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 97782a6e..de1d030c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,6 +24,8 @@ src/net/charserverhandler.cpp, src/net/messagehandler.cpp, src/net/network.cpp, src/localplayer.h, src/game.h: Made the Network class a purely static interface, as there is only one instance. + * src/net/beinghandler.cpp, src/net/beinghandler.h, src/net/protocol.h: + Added support for "beings move" messages. 2006-08-21 Eugenio Favalli diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index c85e8893..93f5f1a8 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -54,6 +54,7 @@ BeingHandler::BeingHandler() //SMSG_PLAYER_MOVE, //0x0119, GPMSG_BEING_ENTER, + GPMSG_BEINGS_MOVE, 0 }; handledMessages = _messages; @@ -61,11 +62,13 @@ BeingHandler::BeingHandler() void BeingHandler::handleMessage(MessageIn &msg) { + /* Uint32 id; Uint16 job, speed; Sint16 param1; Sint8 type; Being *srcBeing, *dstBeing; + */ switch (msg.getId()) { @@ -73,6 +76,11 @@ void BeingHandler::handleMessage(MessageIn &msg) handleBeingEnterMessage(msg); break; + case GPMSG_BEINGS_MOVE: + handleBeingsMoveMessage(msg); + break; + + /* case SMSG_BEING_VISIBLE: case SMSG_BEING_MOVE: // Information about a being in range @@ -377,6 +385,7 @@ void BeingHandler::handleMessage(MessageIn &msg) msg.readShort(), msg.readShort(), msg.readShort(), msg.readByte()); break; + */ } } @@ -402,3 +411,18 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) being->setHairColor(msg.readByte()); being->setSex(msg.readByte()); } + +void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) +{ + for (int nb = (msg.getLength() - 2) / (4 + 4 * 2); nb > 0; --nb) + { + Uint32 id = msg.readLong(); + Being *being = beingManager->findBeing(id); + if (!being) continue; + int sx = msg.readShort(), sy = msg.readShort(), + dx = msg.readShort(), dy = msg.readShort(); + being->mX = sx / 32; + being->mY = sy / 32; + being->setDestination(dx / 32, dy / 32); + } +} diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h index 2dd81e1a..0b0d10b9 100644 --- a/src/net/beinghandler.h +++ b/src/net/beinghandler.h @@ -34,8 +34,8 @@ class BeingHandler : public MessageHandler void handleMessage(MessageIn &msg); private: - void - handleBeingEnterMessage(MessageIn &msg); + void handleBeingEnterMessage(MessageIn &msg); + void handleBeingsMoveMessage(MessageIn &msg); }; #endif diff --git a/src/net/protocol.h b/src/net/protocol.h index 33d72c96..92405c77 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -156,6 +156,7 @@ enum { // 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 + GPMSG_BEINGS_MOVE = 0x0280, // { L being id, W*2 position, W*2 destination }* PGMSG_SAY = 0x02A0, // S text GPMSG_SAY = 0x02A1, // L being id, S text PGMSG_USE_ITEM = 0x0300, // L item id -- cgit v1.2.3-70-g09d2 From 5980dba7ace73e6587b9966bc2076ad2b2eaa5f0 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sun, 27 Aug 2006 08:58:42 +0000 Subject: Send movements. --- ChangeLog | 6 ++++++ src/localplayer.cpp | 9 +++++---- src/net/beinghandler.cpp | 15 ++++++++++++--- src/net/protocol.h | 2 +- 4 files changed, 24 insertions(+), 8 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 6850a45e..662acc65 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2006-08-26 Guillaume Melquiond + + * src/localplayer.cpp, src/net/protocol.h: Send move message + whenever a destination is selected. + * src/beinghandler.cpp: Smoothed being trajectories. + 2006-08-27 Bjørn Lindeijer * src/localplayer.cpp, src/gui/sell.cpp, src/gui/trade.cpp, diff --git a/src/localplayer.cpp b/src/localplayer.cpp index f157f04c..55f536db 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -32,6 +32,7 @@ #include "sound.h" #include "net/messageout.h" +#include "net/network.h" #include "net/protocol.h" LocalPlayer *player_node = NULL; @@ -214,10 +215,10 @@ void LocalPlayer::walk(unsigned char dir) void LocalPlayer::setDestination(Uint16 x, Uint16 y) { - char temp[3]; - MessageOut outMsg(0x0085); - set_coordinates(temp, x, y, mDirection); - outMsg.writeString(temp, 3); + MessageOut msg(PGMSG_WALK); + msg.writeShort(x * 32 + 16); + msg.writeShort(y * 32 + 16); + Network::send(Network::GAME, msg); mPickUpTarget = NULL; diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 93f5f1a8..4ff92b63 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -421,8 +421,17 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) if (!being) continue; int sx = msg.readShort(), sy = msg.readShort(), dx = msg.readShort(), dy = msg.readShort(); - being->mX = sx / 32; - being->mY = sy / 32; - being->setDestination(dx / 32, dy / 32); + bool update = being != player_node; // the local player already knows where he wants to go + if (abs(being->mX - sx / 32) + abs(being->mY - sy / 32) > 4) + { + // crude handling of synchronization messages + being->mX = sx / 32; + being->mY = sy / 32; + update = true; + } + if (update) + { + being->setDestination(dx / 32, dy / 32); + } } } diff --git a/src/net/protocol.h b/src/net/protocol.h index 92405c77..be6e27cb 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -155,7 +155,7 @@ 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, // L being id, S text -- cgit v1.2.3-70-g09d2 From d3cba1c4beac4a1c98f38bbca076a98f9c90bbc4 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sun, 27 Aug 2006 11:21:10 +0000 Subject: Changed to pixel-based coordinates for beings. --- ChangeLog | 5 +++++ src/being.cpp | 18 +++++++++--------- src/being.h | 2 +- src/beingmanager.cpp | 4 ++-- src/engine.cpp | 16 ++++++++-------- src/game.cpp | 14 +++++--------- src/gui/gui.cpp | 2 +- src/localplayer.cpp | 20 ++++++++++---------- src/map.cpp | 2 +- src/net/beinghandler.cpp | 8 ++++---- src/net/playerhandler.cpp | 6 ++---- 11 files changed, 48 insertions(+), 49 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 662acc65..2c1dd5ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,11 @@ * src/localplayer.cpp, src/net/protocol.h: Send move message whenever a destination is selected. * src/beinghandler.cpp: Smoothed being trajectories. + * src/localplayer.cpp, src/game.cpp, src/map.cpp, src/gui/gui.cpp, + src/engine.cpp, src/beingmanager.cpp, src/being.cpp, src/being.h, + src/net/beinghandler.cpp, src/net/playerhandler.cpp: Changed beings + tile-based coordinates to pixel-based coordinates (almost, they point + to tile centers for now). 2006-08-27 Bjørn Lindeijer diff --git a/src/being.cpp b/src/being.cpp index 87332c7a..b49f790e 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -79,7 +79,7 @@ Being::setDestination(Uint16 destX, Uint16 destY) { if (mMap) { - setPath(mMap->findPath(mX, mY, destX, destY)); + setPath(mMap->findPath(mX / 32, mY / 32, destX / 32, destY / 32)); } } @@ -265,19 +265,19 @@ Being::nextStep() mPath.pop_front(); int dir = 0; - if (node.x > mX) + if (node.x > mX / 32) dir |= RIGHT; - else if (node.x < mX) + else if (node.x < mX / 32) dir |= LEFT; - if (node.y > mY) + if (node.y > mY / 32) dir |= DOWN; - else if (node.y < mY) + else if (node.y < mY / 32) dir |= UP; setDirection(dir); - mX = node.x; - mY = node.y; + mX = node.x * 32 + 16; + mY = node.y * 32 + 16; setAction(WALK); mWalkTime += mWalkSpeed / 10; } @@ -298,8 +298,8 @@ Being::logic() } // Update pixel coordinates - mPx = mX * 32 + getXOffset(); - mPy = mY * 32 + getYOffset(); + mPx = mX - 16 + getXOffset(); + mPy = mY - 16 + getYOffset(); if (mEmotion != 0) { diff --git a/src/being.h b/src/being.h index b99f85a3..7e5645ae 100644 --- a/src/being.h +++ b/src/being.h @@ -100,7 +100,7 @@ class Being : public Sprite std::string mName; /**< Name of character */ Uint16 mJob; /**< Job (player job, npc, monster, ) */ - Uint16 mX, mY; /**< Tile coordinates */ + Uint16 mX, mY; /**< Pixel coordinates (tile center) */ Uint8 mDirection; /**< Facing direction */ Uint8 mAction; /**< Action the being is performing */ Uint8 mFrame; diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp index a6c7974d..74709fdf 100644 --- a/src/beingmanager.cpp +++ b/src/beingmanager.cpp @@ -39,8 +39,8 @@ class FindBeingFunctor bool operator() (Being *being) { Uint16 other_y = y + ((being->getType() == Being::NPC) ? 1 : 0); - return (being->mX == x && - (being->mY == y || being->mY == other_y) && + return (being->mX / 32 == x && + (being->mY / 32 == y || being->mY / 32 == other_y) && being->mAction != Being::MONSTER_DEAD && (type == Being::UNKNOWN || being->getType() == type)); } diff --git a/src/engine.cpp b/src/engine.cpp index 7a33dd3d..f3aff6ce 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -155,11 +155,11 @@ void Engine::logic() void Engine::draw(Graphics *graphics) { - int midTileX = graphics->getWidth() / 32 / 2; - int midTileY = graphics->getHeight() / 32 / 2; + int midTileX = graphics->getWidth() / 2; + int midTileY = graphics->getHeight() / 2; - int map_x = (player_node->mX - midTileX) * 32 + player_node->getXOffset(); - int map_y = (player_node->mY - midTileY) * 32 + player_node->getYOffset(); + int map_x = (player_node->mX - midTileX) + player_node->getXOffset(); + int map_y = (player_node->mY - midTileY) + player_node->getYOffset(); if (mCurrentMap) { if (map_x < 0) { @@ -168,11 +168,11 @@ void Engine::draw(Graphics *graphics) if (map_y < 0) { map_y = 0; } - if (map_x > (mCurrentMap->getWidth() - midTileX) * 32) { - map_x = (mCurrentMap->getWidth() - midTileX) * 32; + if (map_x > mCurrentMap->getWidth() * 32 - midTileX) { + map_x = mCurrentMap->getWidth() * 32 - midTileX; } - if (map_y > (mCurrentMap->getHeight() - midTileY) * 32) { - map_y = (mCurrentMap->getHeight() - midTileY) * 32; + if (map_y > mCurrentMap->getHeight() * 32 - midTileY) { + map_y = mCurrentMap->getHeight() * 32 - midTileY; } } diff --git a/src/game.cpp b/src/game.cpp index f83e9c1f..3e789728 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -462,14 +462,12 @@ void Game::handleInput() case SDLK_z: if (!chatWindow->isFocused()) { - FloorItem *item = floorItemManager->findByCoordinates( - player_node->mX, player_node->mY); + Uint16 x = player_node->mX / 32, y = player_node->mY / 32; + FloorItem *item = floorItemManager->findByCoordinates(x, y); // If none below the player, try the tile in front of // the player if (!item) { - Uint16 x = player_node->mX; - Uint16 y = player_node->mY; if (player_node->mDirection & Being::UP) y--; if (player_node->mDirection & Being::DOWN) @@ -591,8 +589,7 @@ void Game::handleInput() current_npc == 0 && !chatWindow->isFocused()) { - Uint16 x = player_node->mX; - Uint16 y = player_node->mY; + Uint16 x = player_node->mX / 32, y = player_node->mY / 32; unsigned char Direction = 0; // Translate pressed keys to movement and direction @@ -644,7 +641,7 @@ void Game::handleInput() if (player_node->mDirection & Being::RIGHT) targetX++; - // Attack priorioty is: Monster, Player, auto target + // Attack priority is: Monster, Player, auto target target = beingManager->findBeing( targetX, targetY, Being::MONSTER); if (!target) @@ -659,8 +656,7 @@ void Game::handleInput() { if (joystick->buttonPressed(1)) { - FloorItem *item = floorItemManager->findByCoordinates( - player_node->mX, player_node->mY); + FloorItem *item = floorItemManager->findByCoordinates(x, y); if (item) player_node->pickUp(item); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 0e200db3..a3ec299b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -313,7 +313,7 @@ Gui::mousePress(int mx, int my, int button) Uint8 *keys = SDL_GetKeyState(NULL); if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT])) { - player_node->setDestination(tilex, tiley); + player_node->setDestination(tilex * 32 + 16, tiley * 32 + 16); player_node->stopAttack(); } } diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 55f536db..72e2a369 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -152,15 +152,15 @@ void LocalPlayer::dropItem(Item *item, int quantity) void LocalPlayer::pickUp(FloorItem *item) { - int dx = item->getX() - mX; - int dy = item->getY() - mY; + int dx = item->getX() - mX / 32; + int dy = item->getY() - mY / 32; if (dx * dx + dy * dy < 4) { MessageOut outMsg(CMSG_ITEM_PICKUP); outMsg.writeLong(item->getId()); mPickUpTarget = NULL; } else { - setDestination(item->getX(), item->getY()); + setDestination(item->getX() * 32 + 16, item->getY() * 32 + 16); mPickUpTarget = item; stopAttack(); } @@ -189,19 +189,19 @@ void LocalPlayer::walk(unsigned char dir) dx++; // Prevent skipping corners over colliding tiles - if (dx && mMap->tileCollides(mX + dx, mY)) + if (dx && mMap->tileCollides(mX / 32 + dx, mY / 32)) dx = 0; - if (dy && mMap->tileCollides(mX, mY + dy)) + if (dy && mMap->tileCollides(mX / 32, mY / 32 + dy)) dy = 0; // Choose a straight direction when diagonal target is blocked - if (dx && dy && !mMap->getWalk(mX + dx, mY + dy)) + if (dx && dy && !mMap->getWalk(mX / 32 + dx, mY / 32 + dy)) dx = 0; // Walk to where the player can actually go - if ((dx || dy) && mMap->getWalk(mX + dx, mY + dy)) + if ((dx || dy) && mMap->getWalk(mX / 32 + dx, mY / 32 + dy)) { - setDestination(mX + dx, mY + dy); + setDestination(mX + dx * 32, mY + dy * 32); } else if (dir) { @@ -216,8 +216,8 @@ void LocalPlayer::walk(unsigned char dir) void LocalPlayer::setDestination(Uint16 x, Uint16 y) { MessageOut msg(PGMSG_WALK); - msg.writeShort(x * 32 + 16); - msg.writeShort(y * 32 + 16); + msg.writeShort(x); + msg.writeShort(y); Network::send(Network::GAME, msg); mPickUpTarget = NULL; diff --git a/src/map.cpp b/src/map.cpp index 531b0f15..1b2ce1e8 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -225,7 +225,7 @@ Map::getWalk(int x, int y) Beings *beings = beingManager->getAll(); for (BeingIterator i = beings->begin(); i != beings->end(); i++) { // job 45 is a portal, they don't collide - if ((*i)->mX == x && (*i)->mY == y && (*i)->mJob != 45) { + if ((*i)->mX / 32 == x && (*i)->mY / 32 == y && (*i)->mJob != 45) { return false; } } diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 4ff92b63..ac2801c2 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -422,16 +422,16 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) int sx = msg.readShort(), sy = msg.readShort(), dx = msg.readShort(), dy = msg.readShort(); bool update = being != player_node; // the local player already knows where he wants to go - if (abs(being->mX - sx / 32) + abs(being->mY - sy / 32) > 4) + if (abs(being->mX - sx) + abs(being->mY - sy) > 4 * 32) { // crude handling of synchronization messages - being->mX = sx / 32; - being->mY = sy / 32; + being->mX = sx; + being->mY = sy; update = true; } if (update) { - being->setDestination(dx / 32, dy / 32); + being->setDestination(dx, dy); } } } diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp index c73aa2da..fc6bb37d 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/playerhandler.cpp @@ -321,10 +321,8 @@ PlayerHandler::handleMapChangeMessage(MessageIn &msg) player_node->stopAttack(); player_node->mFrame = 0; - // TODO: Server is sending pixel coordinates. Client will need to work with - // these instead of converting them to tile coordinates. - player_node->mX = x / 32; - player_node->mY = y / 32; + player_node->mX = x; + player_node->mY = y; if (newServer) { -- cgit v1.2.3-70-g09d2 From 71bded93f43a02b167ec2a9a46b90a5fcc842180 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sun, 27 Aug 2006 11:39:53 +0000 Subject: Added support for leaving beings. --- ChangeLog | 4 +++- src/net/beinghandler.cpp | 17 +++++++++++++++++ src/net/beinghandler.h | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 86ea7b87..9382ee08 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,7 +9,7 @@ src/net/playerhandler.cpp, src/Makefile.am: Got rid of no longer used protocol.cpp. -2006-08-26 Guillaume Melquiond +2006-08-27 Guillaume Melquiond * src/localplayer.cpp, src/net/protocol.h: Send move message whenever a destination is selected. @@ -19,6 +19,8 @@ src/net/beinghandler.cpp, src/net/playerhandler.cpp: Changed beings tile-based coordinates to pixel-based coordinates (almost, they point to tile centers for now). + * src/net/beinghandler.cpp, src/net/beinghandler.h: Added support for + leaving beings. 2006-08-26 Bjørn Lindeijer diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index ac2801c2..59a4fa9a 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -54,6 +54,7 @@ BeingHandler::BeingHandler() //SMSG_PLAYER_MOVE, //0x0119, GPMSG_BEING_ENTER, + GPMSG_BEING_LEAVE, GPMSG_BEINGS_MOVE, 0 }; @@ -76,6 +77,10 @@ void BeingHandler::handleMessage(MessageIn &msg) handleBeingEnterMessage(msg); break; + case GPMSG_BEING_LEAVE: + handleBeingLeaveMessage(msg); + break; + case GPMSG_BEINGS_MOVE: handleBeingsMoveMessage(msg); break; @@ -412,6 +417,18 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) being->setSex(msg.readByte()); } +void BeingHandler::handleBeingLeaveMessage(MessageIn &msg) +{ + msg.readByte(); // type, assume player for now, TODO + Being *being = beingManager->findBeing(msg.readLong()); + if (!being) return; + if (being == player_node->getTarget()) + { + player_node->stopAttack(); + } + beingManager->destroyBeing(being); +} + void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) { for (int nb = (msg.getLength() - 2) / (4 + 4 * 2); nb > 0; --nb) diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h index 0b0d10b9..59539ffe 100644 --- a/src/net/beinghandler.h +++ b/src/net/beinghandler.h @@ -35,6 +35,7 @@ class BeingHandler : public MessageHandler private: void handleBeingEnterMessage(MessageIn &msg); + void handleBeingLeaveMessage(MessageIn &msg); void handleBeingsMoveMessage(MessageIn &msg); }; -- cgit v1.2.3-70-g09d2 From af61e1e7df91b97c3f7516e9eb2b37b621f069ad Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Sun, 27 Aug 2006 22:49:10 +0000 Subject: Added support for entering monsters. --- ChangeLog | 6 ++++++ src/gui/gui.cpp | 6 ++++-- src/net/beinghandler.cpp | 40 ++++++++++++++++++++++++++-------------- src/net/protocol.h | 14 ++++++++++++++ 4 files changed, 50 insertions(+), 16 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index ecaf0b13..fccfe4b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2006-08-28 Bjørn Lindeijer + + * src/gui/gui.cpp: Fixed crash when map is not loaded yet. + * src/net/beinghandler.cpp, src/net/protocol.h: Added support for + entering monsters. + 2006-08-27 Bjørn Lindeijer * src/localplayer.cpp, src/gui/sell.cpp, src/gui/trade.cpp, diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 5df26d63..69563dc1 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -254,7 +254,8 @@ Gui::mousePress(int mx, int my, int button) Being *being; FloorItem *floorItem; - if ((being = beingManager->findBeing(tilex, tiley)) && being->getType() != Being::LOCALPLAYER) + if ((being = beingManager->findBeing(tilex, tiley)) && + being->getType() != Being::LOCALPLAYER) { showPopup(mx, my, being); return; @@ -307,7 +308,8 @@ Gui::mousePress(int mx, int my, int button) player_node->pickUp(item); } // Just walk around - else if (engine->getCurrentMap()->getWalk(tilex, tiley)) + else if (engine->getCurrentMap() && + engine->getCurrentMap()->getWalk(tilex, tiley)) { // XXX XXX XXX REALLY UGLY! Uint8 *keys = SDL_GetKeyState(NULL); diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 59a4fa9a..e3eb6eba 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -397,24 +397,36 @@ void BeingHandler::handleMessage(MessageIn &msg) void BeingHandler::handleBeingEnterMessage(MessageIn &msg) { - msg.readByte(); // type + int type = msg.readByte(); // type int id = msg.readLong(); - std::string name = msg.readString(); - Being *being; - if (player_node->getName() == name) + + switch (type) { + case OBJECT_PLAYER: { - being = player_node; - being->setId(id); - } - else + std::string name = msg.readString(); + Being *being; + if (player_node->getName() == name) + { + being = player_node; + being->setId(id); + } + else + { + being = beingManager->createBeing(id, 0); + being->setName(name); + } + being->setHairStyle(msg.readByte()); + being->setHairColor(msg.readByte()); + being->setSex(msg.readByte()); + } break; + case OBJECT_MONSTER: { - // assume type is player for now, so job 0, TODO - being = beingManager->createBeing(id, 0); - being->setName(name); + int monsterId = msg.readShort(); + Being *being; + being = beingManager->createBeing(id, 1002 + monsterId); + being->setWalkSpeed(150); // TODO + } break; } - being->setHairStyle(msg.readByte()); - being->setHairColor(msg.readByte()); - being->setSex(msg.readByte()); } void BeingHandler::handleBeingLeaveMessage(MessageIn &msg) diff --git a/src/net/protocol.h b/src/net/protocol.h index d99351f2..6feee9d4 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -223,4 +223,18 @@ enum { CREATE_TOO_MUCH_CHARACTERS }; +// Object type enumeration +enum { + // A simple item + OBJECT_ITEM = 0, + // An item that can be activated (doors, switchs, sign, ...) + OBJECT_ACTOR, + // Non-Playable-Character is an actor capable of movement and maybe actions + OBJECT_NPC, + // A monster (moving actor with AI. able to toggle map/quest actions, too) + OBJECT_MONSTER, + // A player + OBJECT_PLAYER +}; + #endif -- cgit v1.2.3-70-g09d2 From 2b322bf18d80acb464a9dc1820e581e7204cca1e Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sat, 2 Sep 2006 11:58:35 +0000 Subject: Switched to short IDs for beings. --- ChangeLog | 8 ++++++++ src/being.cpp | 2 +- src/being.h | 8 ++++---- src/beingmanager.cpp | 4 ++-- src/beingmanager.h | 4 ++-- src/localplayer.cpp | 4 ++-- src/localplayer.h | 2 +- src/monster.cpp | 2 +- src/monster.h | 2 +- src/net/beinghandler.cpp | 9 ++++----- src/net/charserverhandler.cpp | 2 +- src/net/chathandler.cpp | 6 ++++-- src/net/protocol.h | 9 +++++---- src/npc.cpp | 2 +- src/npc.h | 2 +- src/player.cpp | 2 +- src/player.h | 2 +- 17 files changed, 40 insertions(+), 30 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 28f87459..492fc2b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2006-09-02 Guillaume Melquiond + + * src/localplayer.cpp, src/beingmanager.h, src/beingmanager.cpp, + src/npc.cpp, src/player.cpp, src/monster.h, src/being.cpp, src/npc.h, + src/monster.cpp, src/player.h, src/net/beinghandler.cpp, src/being.h, + src/net/charserverhandler.cpp, src/net/protocol.h, src/localplayer.h, + src/net/chathandler.cpp: Switched to short IDs for beings. + 2006-09-01 Eugenio Favalli * src/gui/serverdialog.cpp, src/gui/serverdialog.h, src/net/network.h: diff --git a/src/being.cpp b/src/being.cpp index b497d58f..a4bee426 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -46,7 +46,7 @@ PATH_NODE::PATH_NODE(Uint16 iX, Uint16 iY): { } -Being::Being(Uint32 id, Uint16 job, Map *map): +Being::Being(Uint16 id, Uint16 job, Map *map): mJob(job), mX(0), mY(0), mDirection(DOWN), mAction(STAND), diff --git a/src/being.h b/src/being.h index 7c08ab81..b2495a29 100644 --- a/src/being.h +++ b/src/being.h @@ -112,7 +112,7 @@ class Being : public Sprite /** * Constructor. */ - Being(Uint32 id, Uint16 job, Map *map); + Being(Uint16 id, Uint16 job, Map *map); /** * Destructor. @@ -274,14 +274,14 @@ class Being : public Sprite /** * Gets the sprite id. */ - Uint32 + Uint16 getId() const { return mId; } /** * Sets the sprite id. */ void - setId(Uint32 id) { mId = id; } + setId(Uint16 id) { mId = id; } /** * Sets the map the being is on @@ -348,7 +348,7 @@ class Being : public Sprite SpriteDirection getSpriteDirection() const; - Uint32 mId; /**< Unique sprite id */ + Uint16 mId; /**< Unique being id */ Uint8 mSex; /**< Character's gender */ Uint16 mWeapon; /**< Weapon picture id */ Uint16 mWalkSpeed; /**< Walking speed */ diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp index 0156ce33..d2db055a 100644 --- a/src/beingmanager.cpp +++ b/src/beingmanager.cpp @@ -62,7 +62,7 @@ void BeingManager::setPlayer(LocalPlayer *player) mBeings.push_back(player); } -Being* BeingManager::createBeing(Uint32 id, Uint16 job) +Being* BeingManager::createBeing(Uint16 id, Uint16 job) { Being *being; @@ -90,7 +90,7 @@ void BeingManager::destroyBeing(Being *being) delete being; } -Being* BeingManager::findBeing(Uint32 id) +Being* BeingManager::findBeing(Uint16 id) { for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++) { diff --git a/src/beingmanager.h b/src/beingmanager.h index 0dbafcc6..c32884a0 100644 --- a/src/beingmanager.h +++ b/src/beingmanager.h @@ -48,7 +48,7 @@ class BeingManager /** * Create a being and add it to the list of beings */ - Being* createBeing(Uint32 id, Uint16 job); + Being* createBeing(Uint16 id, Uint16 job); /** * Remove a Being @@ -58,7 +58,7 @@ class BeingManager /** * Return a specific id Being */ - Being* findBeing(Uint32 id); + Being* findBeing(Uint16 id); /** * Return a being at specific coordinates diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 9df3ac3f..87a55744 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -37,8 +37,8 @@ LocalPlayer *player_node = NULL; -LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map): - Player(id, job, map), +LocalPlayer::LocalPlayer(): + Player(65535, 0, NULL), mLevel(1), mInventory(new Inventory()), mTarget(NULL), mPickUpTarget(NULL), diff --git a/src/localplayer.h b/src/localplayer.h index 613f196a..886c3d11 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -42,7 +42,7 @@ class LocalPlayer : public Player STR = 0, AGI, VIT, INT, DEX, LUK }; - LocalPlayer(Uint32 id, Uint16 job, Map *map); + LocalPlayer(); virtual ~LocalPlayer(); diff --git a/src/monster.cpp b/src/monster.cpp index aba242b6..a4317e5e 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -29,7 +29,7 @@ #include "utils/tostring.h" -Monster::Monster(Uint32 id, Uint16 job, Map *map): +Monster::Monster(Uint16 id, Uint16 job, Map *map): Being(id, job, map) { mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/monster" + toString(job - 1002) + ".xml", 0); diff --git a/src/monster.h b/src/monster.h index 6ce0d69d..0314a035 100644 --- a/src/monster.h +++ b/src/monster.h @@ -29,7 +29,7 @@ class Monster : public Being { public: - Monster(Uint32 id, Uint16 job, Map *map); + Monster(Uint16 id, Uint16 job, Map *map); virtual Type getType() const; }; diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index e3eb6eba..8ccd3dd6 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -398,7 +398,7 @@ void BeingHandler::handleBeingEnterMessage(MessageIn &msg) { int type = msg.readByte(); // type - int id = msg.readLong(); + int id = msg.readShort(); switch (type) { case OBJECT_PLAYER: @@ -431,8 +431,7 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) void BeingHandler::handleBeingLeaveMessage(MessageIn &msg) { - msg.readByte(); // type, assume player for now, TODO - Being *being = beingManager->findBeing(msg.readLong()); + Being *being = beingManager->findBeing(msg.readShort()); if (!being) return; if (being == player_node->getTarget()) { @@ -443,9 +442,9 @@ void BeingHandler::handleBeingLeaveMessage(MessageIn &msg) void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) { - for (int nb = (msg.getLength() - 2) / (4 + 4 * 2); nb > 0; --nb) + for (int nb = (msg.getLength() - 2) / (2 + 4 * 2); nb > 0; --nb) { - Uint32 id = msg.readLong(); + Uint16 id = msg.readShort(); Being *being = beingManager->findBeing(id); if (!being) continue; int sx = msg.readShort(), sy = msg.readShort(), diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp index d67949cc..4e251524 100644 --- a/src/net/charserverhandler.cpp +++ b/src/net/charserverhandler.cpp @@ -195,7 +195,7 @@ CharServerHandler::handleCharSelectResponse(MessageIn &msg) LocalPlayer* CharServerHandler::readPlayerData(MessageIn &msg, int &slot) { - LocalPlayer *tempPlayer = new LocalPlayer(mLoginData->account_ID, 0, NULL); + LocalPlayer *tempPlayer = new LocalPlayer; slot = msg.readByte(); // character slot tempPlayer->mName = msg.readString(); tempPlayer->setSex(msg.readByte()); diff --git a/src/net/chathandler.cpp b/src/net/chathandler.cpp index 02f99c41..f765f0f4 100644 --- a/src/net/chathandler.cpp +++ b/src/net/chathandler.cpp @@ -59,12 +59,12 @@ void ChatHandler::handleMessage(MessageIn &msg) { Being *being; std::string chatMsg; - Sint16 chatMsgLength; + //Sint16 chatMsgLength; switch (msg.getId()) { case GPMSG_SAY: - being = beingManager->findBeing(msg.readLong()); + being = beingManager->findBeing(msg.readShort()); chatMsg = msg.readString(); if (being) { @@ -77,6 +77,7 @@ void ChatHandler::handleMessage(MessageIn &msg) } break; + /* // Received speech from being case SMSG_BEING_CHAT: chatMsgLength = msg.readShort() - 8; @@ -131,5 +132,6 @@ void ChatHandler::handleMessage(MessageIn &msg) msg.readLong(); // id chatWindow->chatLog("MVP player", BY_SERVER); break; + */ } } diff --git a/src/net/protocol.h b/src/net/protocol.h index 6feee9d4..f056f003 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -152,13 +152,14 @@ enum { // [, S32 token, S server, W port] PGMSG_PICKUP = 0x0110, GPMSG_PICKUP_RESPONSE = 0x0111, - GPMSG_BEING_ENTER = 0x0200, // B type, L being id + GPMSG_BEING_ENTER = 0x0200, // B type, W being id // player: S name, B hair style, B hair color, B gender - GPMSG_BEING_LEAVE = 0x0201, // B type, L being id + // monster: W type id + GPMSG_BEING_LEAVE = 0x0201, // W being id PGMSG_WALK = 0x0260, // W*2 destination - GPMSG_BEINGS_MOVE = 0x0280, // { L being id, W*2 position, W*2 destination }* + GPMSG_BEINGS_MOVE = 0x0280, // { W being id, W*2 position, W*2 destination }* PGMSG_SAY = 0x02A0, // S text - GPMSG_SAY = 0x02A1, // L being id, S text + GPMSG_SAY = 0x02A1, // W being id, S text PGMSG_USE_ITEM = 0x0300, // L item id GPMSG_USE_RESPONSE = 0x0301, // B error PGMSG_EQUIP = 0x0302, // L item id, B slot diff --git a/src/npc.cpp b/src/npc.cpp index 13025469..b2b426dd 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -33,7 +33,7 @@ extern Spriteset *npcset; NPC *current_npc = 0; -NPC::NPC(Uint32 id, Uint16 job, Map *map): +NPC::NPC(Uint16 id, Uint16 job, Map *map): Being(id, job, map) { mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/npc.xml", job-100); diff --git a/src/npc.h b/src/npc.h index bbc86d9c..3b61123b 100644 --- a/src/npc.h +++ b/src/npc.h @@ -29,7 +29,7 @@ class NPC : public Being { public: - NPC(Uint32 id, Uint16 job, Map *map); + NPC(Uint16 id, Uint16 job, Map *map); virtual Type getType() const; diff --git a/src/player.cpp b/src/player.cpp index af9a3344..f5f42e9f 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -32,7 +32,7 @@ #include "gui/gui.h" -Player::Player(Uint32 id, Uint16 job, Map *map): +Player::Player(Uint16 id, Uint16 job, Map *map): Being(id, job, map) { /* Load the weapon sprite. When there are more different weapons this diff --git a/src/player.h b/src/player.h index 65b0303d..6ff4babe 100644 --- a/src/player.h +++ b/src/player.h @@ -38,7 +38,7 @@ class Player : public Being /** * Constructor. */ - Player(Uint32 id, Uint16 job, Map *map); + Player(Uint16 id, Uint16 job, Map *map); virtual Type getType() const; -- cgit v1.2.3-70-g09d2 From 3bce14c324e1d7bbd058e18072acc7bd953d6475 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sat, 2 Sep 2006 13:03:20 +0000 Subject: Removed pixel-based synchronisation. Added variable length move messages. --- ChangeLog | 3 +++ src/net/beinghandler.cpp | 30 +++++++++++++++++++++++++----- src/net/messagein.cpp | 11 +++++++++++ src/net/messagein.h | 13 +++++++++++++ src/net/protocol.h | 11 ++++++++++- 5 files changed, 62 insertions(+), 6 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 492fc2b8..9f148845 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,9 @@ src/monster.cpp, src/player.h, src/net/beinghandler.cpp, src/being.h, src/net/charserverhandler.cpp, src/net/protocol.h, src/localplayer.h, src/net/chathandler.cpp: Switched to short IDs for beings. + * src/net/messagein.h, src/net/beinghandler.cpp, src/net/protocol.h, + src/net/messagein.cpp: Removed pixel-based synchronisation. Added + variable length move messages. 2006-09-01 Eugenio Favalli diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 8ccd3dd6..eb5ccb57 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -442,13 +442,33 @@ void BeingHandler::handleBeingLeaveMessage(MessageIn &msg) void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) { - for (int nb = (msg.getLength() - 2) / (2 + 4 * 2); nb > 0; --nb) + while (msg.getUnreadLength()) { Uint16 id = msg.readShort(); + Uint8 flags = msg.readByte(); Being *being = beingManager->findBeing(id); - if (!being) continue; - int sx = msg.readShort(), sy = msg.readShort(), - dx = msg.readShort(), dy = msg.readShort(); + int sx = 0, sy = 0, dx = 0, dy = 0; + if (flags & MOVING_POSITION) + { + Uint16 sx2, sy2; + msg.readCoordinates(sx2, sy2); + sx = sx2 * 32 + 16; + sy = sy2 * 32 + 16; + } + if (flags & MOVING_DESTINATION) + { + dx = msg.readShort(); + dy = msg.readShort(); + if (!(flags & MOVING_POSITION)) + { + sx = dx; + sy = dy; + } + } + if (!being || !(flags & (MOVING_POSITION | MOVING_DESTINATION))) + { + continue; + } bool update = being != player_node; // the local player already knows where he wants to go if (abs(being->mX - sx) + abs(being->mY - sy) > 4 * 32) { @@ -457,7 +477,7 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) being->mY = sy; update = true; } - if (update) + if (update && (flags & MOVING_DESTINATION)) { being->setDestination(dx, dy); } diff --git a/src/net/messagein.cpp b/src/net/messagein.cpp index 2c452a4d..a1707e06 100644 --- a/src/net/messagein.cpp +++ b/src/net/messagein.cpp @@ -77,6 +77,17 @@ long MessageIn::readLong() return value; } +void MessageIn::readCoordinates(Uint16 &x, Uint16 &y) +{ + if (mPos + 3 <= mLength) + { + unsigned char const *p = reinterpret_cast< unsigned char const * >(mData + mPos); + x = p[0] | ((p[1] & 0x07) << 8); + y = (p[1] >> 3) | ((p[2] & 0x3F) << 5); + } + mPos += 3; +} + std::string MessageIn::readString(int length) { // Get string length diff --git a/src/net/messagein.h b/src/net/messagein.h index d5a7593f..68bbb933 100644 --- a/src/net/messagein.h +++ b/src/net/messagein.h @@ -26,6 +26,8 @@ #include +#include + /** * Used for parsing an incoming message. */ @@ -48,6 +50,11 @@ class MessageIn short readShort(); /**< Reads a short. */ long readLong(); /**< Reads a long. */ + /** + * Reads a 3-byte block containing tile-based coordinates. + */ + void readCoordinates(Uint16 &x, Uint16 &y); + /** * Reads a string. If a length is not given (-1), it is assumed * that the length of the string is stored in a short at the @@ -61,6 +68,12 @@ class MessageIn unsigned int getLength() { return mLength; } + /** + * Returns the length of unread data. + */ + unsigned int + getUnreadLength() { return mLength - mPos; } + private: const char* mData; /**< The message data. */ unsigned int mLength; /**< The length of the data. */ diff --git a/src/net/protocol.h b/src/net/protocol.h index f056f003..07b5c926 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -113,6 +113,7 @@ * - PGMSG_*: from client to game server * - GPMSG_*: from game server to client * Components: B byte, W word, D double word, S variable-size string + * C tile-based coordinates (B*3) */ enum { // Login/Register @@ -157,7 +158,7 @@ enum { // monster: W type id GPMSG_BEING_LEAVE = 0x0201, // W being id PGMSG_WALK = 0x0260, // W*2 destination - GPMSG_BEINGS_MOVE = 0x0280, // { W being id, W*2 position, W*2 destination }* + GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, C position] [, W*2 destination] }* PGMSG_SAY = 0x02A0, // S text GPMSG_SAY = 0x02A1, // W being id, S text PGMSG_USE_ITEM = 0x0300, // L item id @@ -238,4 +239,12 @@ enum { OBJECT_PLAYER }; +// Moving object flags +enum { + // Payload contains the current position. + MOVING_POSITION = 1, + // Payload contains the destination. + MOVING_DESTINATION = 2 +}; + #endif -- cgit v1.2.3-70-g09d2 From 81c7e13077dde99ea360f2ab8432aa48444f3b88 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sat, 9 Sep 2006 22:59:22 +0000 Subject: Fitted being trajectories to synchronization messages. --- ChangeLog | 2 + src/being.cpp | 157 ++++++++++++++++++++++++++++++++++++++++++----- src/being.h | 15 ++++- src/localplayer.h | 2 +- src/net/beinghandler.cpp | 15 +++-- 5 files changed, 169 insertions(+), 22 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 4bb5199f..2b395e55 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,8 @@ * src/map.cpp: Removed being collisions. Fixed wrong heuristic cost of the pathfinder. + * src/localplayer.h, src/being.cpp, src/net/beinghandler.cpp, + src/being.h: Fitted being trajectories to synchronization messages. 2006-09-02 Bjørn Lindeijer diff --git a/src/being.cpp b/src/being.cpp index a4bee426..982b0ebf 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -23,6 +23,7 @@ #include "being.h" #include +#include #include #include "animatedsprite.h" @@ -58,6 +59,7 @@ Being::Being(Uint16 id, Uint16 job, Map *map): mSex(2), mWeapon(0), mWalkSpeed(150), + mSpeedModifier(1024), mMap(NULL), mHairStyle(0), mHairColor(0), mSpeechTime(0), @@ -75,34 +77,157 @@ Being::~Being() setMap(NULL); } -void -Being::setDestination(Uint16 destX, Uint16 destY) +void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY) { - if (!mMap || (mX == destX && mY == destY)) + if (!mMap || (mX == dstX && mY == dstY)) { + setPath(Path()); return; } - Path p; - if (mX / 32 != destX / 32 || mY / 32 != destY / 32) + if (mX / 32 == dstX / 32 && mY / 32 == dstY / 32) { - p = mMap->findPath(mX / 32, mY / 32, destX / 32, destY / 32); - if (p.empty()) + // The being is already on the last tile of the path. + Path p; + p.push_back(PATH_NODE(dstX, dstY)); + setPath(p); + return; + } + + Path p1; + int p1_size, p1_length; + Uint16 *p1_dist; + int onPath = -1; + if (srcX / 32 == dstX / 32 && srcY / 32 == dstY / 32) + { + p1_dist = new Uint16[1]; + p1_size = 1; + p1_dist[0] = 0; + p1_length = 0; + } + else + { + p1 = mMap->findPath(srcX / 32, srcY / 32, dstX / 32, dstY / 32); + if (p1.empty()) { - setPath(p); + // No path? Better teleport. + mX = dstX; + mY = dstY; + setPath(p1); return; } + p1_size = p1.size(); + p1_dist = new Uint16[p1_size]; + int j = 0; // Remove last tile so that it can be replaced by the exact destination. - p.pop_back(); - for (Path::iterator i = p.begin(), i_end = p.end(); i != i_end; ++i) + p1.pop_back(); + for (Path::iterator i = p1.begin(), i_end = p1.end(); i != i_end; ++i) { - // Set intermediate step to tile centers. + // Get distance from source to tile i. + p1_dist[j] = mMap->getMetaTile(i->x, i->y)->Gcost; + // Check if the being is already walking on the path. + if (i->x == mX / 32 && i->y == mY / 32) + { + onPath = j; + } + // Set intermediate steps to tile centers. i->x = i->x * 32 + 16; i->y = i->y * 32 + 16; + ++j; } + p1_length = mMap->getMetaTile(dstX / 32, dstY / 32)->Gcost; + p1_dist[p1_size - 1] = p1_length; } - p.push_back(PATH_NODE(destX, destY)); - setPath(p); + p1.push_back(PATH_NODE(dstX, dstY)); + + if (mX / 32 == srcX / 32 && mY / 32 == srcY / 32) + { + // The being is at the start of the path. + setPath(p1); + delete[] p1_dist; + return; + } + + if (onPath >= 0) + { + // The being is already on the path, but it needs to be slowed down. + for (int j = onPath; j >= 0; --j) + { + p1.pop_front(); + } + int r = p1_length - p1_dist[onPath]; // remaining length + assert(r > 0); + setPath(p1, p1_length * 1024 / r); + delete[] p1_dist; + return; + } + + Path bestPath; + int bestRating = -1, bestStart = 0, bestLength = 0; + int j = 0; + + for (Path::iterator i = p1.begin(), i_end = p1.end(); i != i_end; ++i) + { + // Look if it is worth passing by tile i. + Path p2 = mMap->findPath(mX / 32, mY / 32, i->x / 32, i->y / 32); + if (!p2.empty()) + { + int l1 = mMap->getMetaTile(i->x / 32, i->y / 32)->Gcost; + int l2 = p1_length - p1_dist[j]; + int r = l1 + l2 / 2; // TODO: tune rating formula + assert(r > 0); + if (bestRating < 0 || r < bestRating) + { + bestPath.swap(p2); + bestRating = r; + bestStart = j; + bestLength = l1 + l2; + } + } + ++j; + } + + if (bestRating < 0) + { + // Unable to reach the path? Better teleport. + mX = srcX; + mY = srcY; + setPath(p1); + delete[] p1_dist; + return; + } + + bestPath.pop_back(); + for (Path::iterator i = bestPath.begin(), i_end = bestPath.end(); i != i_end; ++i) + { + i->x = i->x * 32 + 16; + i->y = i->y * 32 + 16; + } + + // Concatenate paths. + for (int j = bestStart; j > 0; --j) + { + p1.pop_front(); + } + p1.splice(p1.begin(), bestPath); + + assert(bestLength > 0); + setPath(p1, p1_length * 1024 / bestLength); + delete[] p1_dist; +} + +void Being::adjustCourse(Uint16 srcX, Uint16 srcY) +{ + if (!mPath.empty()) + { + adjustCourse(srcX, srcY, mPath.back().x, mPath.back().y); + } +} + +void +Being::setDestination(Uint16 destX, Uint16 destY) +{ + adjustCourse(mX, mY, destX, destY); } void @@ -112,9 +237,10 @@ Being::clearPath() } void -Being::setPath(const Path &path) +Being::setPath(const Path &path, int mod) { mPath = path; + mSpeedModifier = mod >= 512 ? (mod <= 2048 ? mod : 2048) : 512; // TODO: tune bounds if (mAction != WALK && mAction != DEAD) { @@ -305,7 +431,8 @@ Being::nextStep() mY = node.y; setAction(WALK); mWalkTime += mStepTime / 10; - mStepTime = mWalkSpeed * (int)std::sqrt((double)mStepX * mStepX + (double)mStepY * mStepY) / 32; + mStepTime = mWalkSpeed * (int)std::sqrt((double)mStepX * mStepX + (double)mStepY * mStepY) * + mSpeedModifier / (32 * 1024); } void diff --git a/src/being.h b/src/being.h index b2495a29..d8db9375 100644 --- a/src/being.h +++ b/src/being.h @@ -127,7 +127,17 @@ class Being : public Sprite /** * Sets a new destination for this being to walk to. */ - virtual void setDestination(Uint16 destX, Uint16 destY); + void setDestination(Uint16 destX, Uint16 destY); + + /** + * Adjusts course to expected stat point. + */ + void adjustCourse(Uint16, Uint16); + + /** + * Adjusts course to expected start and end points. + */ + void adjustCourse(Uint16, Uint16, Uint16, Uint16); /** * Puts a "speech balloon" above this being for the specified amount @@ -340,7 +350,7 @@ class Being : public Sprite * Sets the new path for this being. */ void - setPath(const Path &path); + setPath(const Path &path, int mod = 1024); /** * Returns the sprite direction of this being. @@ -352,6 +362,7 @@ class Being : public Sprite Uint8 mSex; /**< Character's gender */ Uint16 mWeapon; /**< Weapon picture id */ Uint16 mWalkSpeed; /**< Walking speed */ + Uint16 mSpeedModifier; /**< Modifier to keep course on sync (1024 = normal speed) */ Map *mMap; /**< Map on which this being resides */ SpriteIterator mSpriteIterator; diff --git a/src/localplayer.h b/src/localplayer.h index 886c3d11..7d5aef87 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -107,7 +107,7 @@ class LocalPlayer : public Player /** * Sets a new destination for this being to walk to. */ - virtual void setDestination(Uint16 x, Uint16 y); + void setDestination(Uint16 x, Uint16 y); void raiseAttribute(Attribute attr); void raiseSkill(Uint16 skillId); diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index eb5ccb57..2d68dd28 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -469,17 +469,24 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) { continue; } - bool update = being != player_node; // the local player already knows where he wants to go if (abs(being->mX - sx) + abs(being->mY - sy) > 4 * 32) { - // crude handling of synchronization messages + // Too large a desynchronization. being->mX = sx; being->mY = sy; - update = true; + being->setDestination(dx, dy); } - if (update && (flags & MOVING_DESTINATION)) + else if (!(flags & MOVING_POSITION)) { being->setDestination(dx, dy); } + else if (!(flags & MOVING_DESTINATION)) + { + being->adjustCourse(sx, sy); + } + else + { + being->adjustCourse(sx, sy, dx, dy); + } } } -- cgit v1.2.3-70-g09d2 From 8da32105732949b4b0273c718d118bcfae70a1c9 Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Mon, 11 Dec 2006 15:47:35 +0000 Subject: Merged 0.0 changes from revision 2825 to 2898 to trunk. --- ChangeLog | 292 +++++++++++++++++++++++- NEWS | 11 + data/CMakeLists.txt | 3 +- data/Makefile.am | 3 +- data/graphics/images/CMakeLists.txt | 1 + data/graphics/images/Makefile.am | 1 + data/graphics/images/error.png | Bin 0 -> 314 bytes src/CMakeLists.txt | 19 +- src/Makefile.am | 19 +- src/action.cpp | 66 ++++++ src/action.h | 61 +++++ src/animatedsprite.cpp | 430 +++++++++--------------------------- src/animatedsprite.h | 131 +++-------- src/animation.cpp | 127 +---------- src/animation.h | 97 ++------ src/base64.cpp | 63 +++--- src/base64.h | 11 +- src/being.cpp | 87 ++++---- src/being.h | 36 +-- src/beingmanager.cpp | 24 +- src/engine.cpp | 147 +----------- src/engine.h | 14 -- src/floor_item.cpp | 4 +- src/floor_item.h | 10 +- src/game.cpp | 94 ++++---- src/graphics.cpp | 3 + src/gui/buy.cpp | 4 +- src/gui/char_select.cpp | 51 +++-- src/gui/char_select.h | 11 +- src/gui/confirm_dialog.cpp | 1 + src/gui/confirm_dialog.h | 2 +- src/gui/debugwindow.cpp | 10 +- src/gui/gui.cpp | 152 +------------ src/gui/gui.h | 38 +--- src/gui/inventorywindow.cpp | 3 +- src/gui/item_amount.cpp | 3 +- src/gui/login.cpp | 1 + src/gui/ok_dialog.cpp | 1 + src/gui/ok_dialog.h | 2 +- src/gui/passwordfield.h | 4 +- src/gui/playerbox.cpp | 37 +--- src/gui/playerbox.h | 24 +- src/gui/popupmenu.cpp | 4 +- src/gui/register.cpp | 1 + src/gui/sell.cpp | 5 +- src/gui/serverdialog.cpp | 1 + src/gui/serverdialog.h | 2 +- src/gui/setup_joystick.cpp | 2 +- src/gui/shop.cpp | 6 +- src/gui/textfield.h | 1 - src/gui/trade.cpp | 36 +-- src/gui/updatewindow.cpp | 2 +- src/gui/viewport.cpp | 392 ++++++++++++++++++++++++++++++++ src/gui/viewport.h | 145 ++++++++++++ src/gui/window.cpp | 3 + src/gui/window.h | 3 +- src/gui/windowcontainer.h | 3 +- src/item.h | 4 +- src/localplayer.cpp | 36 ++- src/localplayer.h | 10 +- src/log.cpp | 23 +- src/main.cpp | 51 ++--- src/map.cpp | 53 +++-- src/map.h | 12 +- src/monster.cpp | 39 +++- src/monster.h | 2 + src/net/beinghandler.cpp | 83 ++++--- src/net/inventoryhandler.cpp | 2 +- src/net/npchandler.cpp | 10 +- src/net/playerhandler.cpp | 18 +- src/net/skillhandler.cpp | 4 +- src/npc.cpp | 17 +- src/npc.h | 8 +- src/openglgraphics.cpp | 3 + src/player.cpp | 109 +++++---- src/player.h | 18 +- src/resources/equipmentdb.cpp | 158 +++++++++++++ src/resources/equipmentdb.h | 52 +++++ src/resources/equipmentinfo.h | 52 +++++ src/resources/image.cpp | 10 +- src/resources/itemdb.cpp | 170 ++++++++++++++ src/resources/itemdb.h | 53 +++++ src/resources/iteminfo.h | 12 +- src/resources/itemmanager.cpp | 173 --------------- src/resources/itemmanager.h | 59 ----- src/resources/mapreader.cpp | 32 +-- src/resources/monsterdb.cpp | 151 +++++++++++++ src/resources/monsterdb.h | 45 ++++ src/resources/monsterinfo.cpp | 70 ++++++ src/resources/monsterinfo.h | 74 +++++++ src/resources/resourcemanager.cpp | 61 +++-- src/resources/resourcemanager.h | 17 +- src/resources/soundeffect.cpp | 19 +- src/resources/spritedef.cpp | 381 ++++++++++++++++++++++++++++++++ src/resources/spritedef.h | 158 +++++++++++++ src/resources/spriteset.h | 6 +- src/sound.cpp | 6 +- src/sound.h | 4 +- src/sprite.h | 2 +- src/utils/wingettimeofday.h | 111 ++++++++++ src/utils/xml.cpp | 54 +++++ src/utils/xml.h | 46 ++++ tmw.cbp | 102 +++++++-- 103 files changed, 3532 insertions(+), 1752 deletions(-) create mode 100644 data/graphics/images/error.png create mode 100644 src/action.cpp create mode 100644 src/action.h create mode 100644 src/gui/viewport.cpp create mode 100644 src/gui/viewport.h create mode 100644 src/resources/equipmentdb.cpp create mode 100644 src/resources/equipmentdb.h create mode 100644 src/resources/equipmentinfo.h create mode 100644 src/resources/itemdb.cpp create mode 100644 src/resources/itemdb.h delete mode 100644 src/resources/itemmanager.cpp delete mode 100644 src/resources/itemmanager.h create mode 100644 src/resources/monsterdb.cpp create mode 100644 src/resources/monsterdb.h create mode 100644 src/resources/monsterinfo.cpp create mode 100644 src/resources/monsterinfo.h create mode 100644 src/resources/spritedef.cpp create mode 100644 src/resources/spritedef.h create mode 100644 src/utils/wingettimeofday.h create mode 100644 src/utils/xml.cpp create mode 100644 src/utils/xml.h (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 807de694..c67d6cd6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,16 +1,305 @@ +2006-12-09 Eugenio Favalli + + * data/graphics/sprites/npcs.png: Added pirate NPC. + +2006-12-09 Bjørn Lindeijer + + * src/sprite.h, src/gui/playerbox.h, src/gui/char_select.cpp, + src/gui/playerbox.cpp, src/gui/passwordfield.h,src/gui/char_select.h, + src/gui/textfield.h, src/main.cpp, src/being.cpp, src/player.h, + src/floor_item.h, src/being.h: Use new animation system in character + selection/creation. Shows equipment and allowed for some cleanup. Had + a bit of help from the patch by VictorSan. + +2006-12-08 Bjørn Lindeijer + + * src/base64.cpp, src/base64.h, src/resources/mapreader.cpp: + Downgraded to base64 codec from PHP 3 to resolve licensing issues. + +2006-12-06 Eugenio Favalli + + * The Mana World.dev, tmw.cbp: Updated project files. + +2006-12-06 Philipp Sehmisch + + * src/net/beinghandler.cpp: Fixed crashs when changing equipment. + * data/graphics/tiles/desert1.png, data/graphics/tiles/desert2.png: + More tiling related fixes at the cliffs. + +2006-12-06 Bjørn Lindeijer + + * src/gui/item_amount.cpp: Fixed visibility of item amount window. + +2006-12-05 Philipp Sehmisch + + * data/graphics/tiles/desert1.png: Improved the tiling behavior + of the cliffs (still not gridless but at least the edges fit + together in the most common situations) + +2006-12-04 Bjørn Lindeijer + + * src/game.cpp, src/engine.h, src/gui/windowcontainer.h, + src/gui/viewport.cpp, src/gui/gui.cpp, src/gui/gui.h, + src/gui/debugwindow.cpp, src/gui/inventorywindow.cpp, + src/gui/viewport.h, src/engine.cpp, src/CMakeLists.txt, + src/Makefile.am: Introduced a new class Viewport which combines the + drawing code from Engine with the (rather misplaced) input handling + from the Gui class. Also, it's a Container itself which should allow + for extending it to show Guichan widgets on map coordinates. + +2006-12-03 Bjørn Lindeijer + + * src/sound.cpp, src/monster.cpp, src/sound.h, + src/resources/soundeffect.cpp, src/resources/resourcemanager.cpp: + Don't try to play empty strings as sounds, and don't return a + SoundEffect instance when Mix_Chunk loading failed. + * src/beingmanager.cpp, src/npc.cpp, src/npc.h: Show NPC names. + * src/game.cpp, src/gui/char_server.cpp, src/gui/window.cpp, + src/gui/login.cpp, src/gui/char_select.cpp, src/gui/ok_dialog.cpp, + src/gui/confirm_dialog.cpp, src/gui/ok_dialog.h, src/gui/window.h, + src/gui/confirm_dialog.h, src/gui/register.cpp: Windows now default + to invisible, since this seems the most common case. + +2006-12-02 Philipp Sehmisch + + * data/graphics/sprites/chest-leather-female.png: A little correction + at the female leather shirt by mangamaniac. + +2006-12-01 Philipp Sehmisch + + * src/net/beinghandler.cpp, src/being.h, src/being.cpp, src/monster.h, + src/gui/gui.cpp: Visible equipment slot numbers are now converted by + the beinghandler from eAthena to our system. No more distinction + between monster attacking and player attacking between beinghandler + and the being classes. + * src/being.cpp, src/monster.cpp, src/being.h, src/monster.h: Moved + the monster specific action handling into the monster class. + * monster.cpp, mosterinfo.cpp, monsterinfo.h: Monsters now make sounds + when they attack, gett hurt or die. + * src/being.cpp: Delayed the damage numbers a bit to synchronize them + better with the hurt sounds. + * data/monsters.xml, data/sfx//bat-dying1.ogg, data/sfx/bat-hit1.ogg, + data/sfx/bow_shoot_1.ogg, data/sfx/fire-goblin-hit1.ogg, + data/sfx/fire-goblin-hit2.ogg, data/sfx/fire-goblin-miss1.ogg, + data/sfx/fist-swish.ogg, data/sfx/flower-hit1.ogg, + data/sfx/flower-hit2.ogg, data/sfx/flower-miss1.ogg, + data/sfx/fluffy-hit1.ogg, data/sfx/fluffy-hit2.ogg, + data/sfx/fluffy-hit3.ogg, data/sfx/fluffy-hurt1.ogg, + data/sfx/fluffy-miss1.ogg, data/sfx/knife-hit1.ogg, + data/sfx/knife-miss1.ogg, data/sfx/levelup.ogg, + data/sfx/scorpion-hit1.ogg, data/sfx/scorpion-hit2.ogg, + data/sfx/scorpion-hit3.ogg, data/sfx/scorpion-hit4.ogg, + data/sfx/scorpion-miss1.ogg, data/sfx/short-sword-hit1.ogg, + data/sfx/short-sword-miss1.ogg, data/sfx/shroom-hit1.ogg, + data/sfx/slime-hit1.ogg, data/sfx/Makefile.AM, + data/sfx/CMakeLists.txt: Added a lot of sound effects by Cosmostrator. + +2006-11-30 Bjørn Lindeijer + + * data/maps/Makefile.am: Fixed small trailing slash issue. + * src/player.cpp: Optimized setSex and setWeapon by first loading the + new sprite and then deleting the old one (prevents potentially + unnecessary reload). + * src/net/beinghandler.cpp: Optimized handling of player walk + messages, by first setting the gender right and then setting the + equipment. Gets rid of reload of complete equipment in the case of + female. + +2006-11-30 Eugenio Favalli + + * The Mana World.dev, tmw.cbp: Updated project files. + +2006-11-29 Bjørn Lindeijer + + * src/monster.cpp: Small fix to resource path. + +2006-11-29 Philipp Sehmisch + + * src/resources/equipment.h: Made getSprite return a constant + reference. + * src/resources/monsterdb.cpp, src/resources/monsterdb.h, + src/resources/monsterinfo.cpp, src/resources/monsterinfo.h, + src/Makefile.AM, src/CMakeLists.txt, src/main.cpp: + Added the MonsterDB namespace that reads the monsters.xml + and maps monster IDs to names, sprite definitions and sound effects. + * src/monster.cpp: Get sprite definition filenames from MonsterDB. + * src/engine.cpp: Show monster name when targeting a monster. + * data/monsters.xml, data/graphics/sprites/Makefile.AM, + data/graphics/sprites/CMakeLists.txt, data/graphics/sprites/monster*: + Renamed all monster sprites to more associative names (whew, we got to + train some monkeys for tasks like that). + +2006-11-27 Bjørn Lindeijer + + * tmw.cbp: Updated Code::Blocks project file. + +2006-11-27 Philipp Sehmisch + + * src/log.cpp, src/util/wingettimeofday.h: Added implementation of + gettimeofday() for windows machines. + +2006-11-26 Bjørn Lindeijer + + * src/log.cpp: Higher precision log timestamps. + * src/graphics.cpp, src/gui/gui.cpp, src/openglgraphics.cpp, + src/main.cpp, src/resources/equipmentdb.cpp, + src/resources/resourcemanager.cpp: Added some additional log + statements. + * src/resources/itemdb.cpp: Removed usage of READ_PROP in favour of + XML::getProperty and updated log statements. + * src/resources/image.cpp: Added support for loading TGA images. + +2006-11-26 Björn Steinbrink + + * src/resources/resourcemanager.cpp: Remove unnecessary check for + file existance, loading will just fail with the correct error message. + +2006-11-26 Bjørn Lindeijer + + * src/game.cpp, src/being.cpp, src/net/beinghandler.cpp, src/being.h: + Made Being::mDirection protected, forcing the use of setDirection. + * src/npc.cpp, src/player.cpp, src/animatedsprite.h, src/monster.cpp, + src/resources/resourcemanager.h: Defaulted variant argument to 0 since + this is the most common situation. + * src/resources/spritedef.cpp, src/resources/spritedef.h: Some + refactoring, splitting up the loading into several methods, in + preparation of adding support for including other sprites. + * src/main.cpp: ItemDB needs to be unloaded before deleting the + resource manager instance, since ItemInfo refers to an Image. + +2006-11-26 Philipp Sehmisch + + * src/being.cpp, src/being.h, src/engine.cpp, src/main.cpp, + src/player.cpp, src/player.h, src/resources/equipmentdb.h, + src/resources/equipmentdb.cpp, src/resources/equipmentinfo.h, + src/resources/itemdb.cpp, src/resources/itemdb.h, + data/graphics/images/error.png, data/graphics/sprites/error.xml: + Added the EquipmentDB namespace that reads the equipment.xml, maps + equipment IDs to sprite definition files and thus allows gender + specific equipment sprites. + * data/graphics/sprites/chest-leather-female.png, + data/graphics/sprites/chest-leather-male.png, + data/graphics/sprites/chest-leather-female.xml, + data/graphics/sprites/chest-leather-male.xml, + data/equipment.xml: Added and defined male and female leather shirt as + proof of concept of the gender specific equipment. + * data/graphics/images/Makefile.am, data/graphics/sprites/Makefile.am, + data/Makefile.am, src/Makefile.am, + data/graphics/images/CMakeLists.txt, + data/graphics/sprites/CMakeLists.txt, data/CMakeLists.txt, + src/CMakeLists.txt: Updated Makefiles and CMake Lists. + +2006-11-24 Philipp Sehmisch + + * src/engine.cpp, src/floor_item.cpp, src/item.h, src/main.cpp, + src/gui/buy.cpp, src/gui/popupmenu.cpp, src/gui/sell.cpp, + src/gui/shop.cpp, src/net/inventoryhandler.cpp, + src/resources/itemdb.cpp, src/resources/itemdb.h, + src/resources/iteminfo.h, src/resources/itemmanager.cpp, + src/resources/itemmanager.h: Refactored the Itemmanager class to an + ItemDB namespace. + +2006-11-23 Eugenio Favalli + + * The Mana World.dev, tmw.cbp: Updated project files. + +2006-11-19 Bjørn Lindeijer + + * src/gui/setup_joystick.cpp: Fixed joystick option to show enabled + when the joystick is enabled. + * src/localplayer.cpp, src/game.cpp, src/action.h, src/action.cpp, + src/player.cpp, src/animatedsprite.h, src/being.cpp, src/animation.h, + src/monster.cpp, src/CMakeLists.txt, src/player.h, + src/animatedsprite.cpp, src/localplayer.h, src/animation.cpp, + src/Makefile.am, src/being.h, src/resources/resourcemanager.cpp, + src/resources/spritedef.cpp, src/resources/resourcemanager.h, + src/resources/spriteset.h, src/resources/spritedef.cpp: Separated + sprite definition from playback. + 2006-11-17 Björn Steinbrink * data/graphics/sprites/CMakeLists.txt: Fixed some filenames. +2006-11-17 Wai Ling Tsang + + * src/gui/gui.cpp: Added mouse following ability/feature under + logic(). + * src/gui/gui.h: Added mouseMotion(), mouseRelease() and private + variables for mouse following. + +2006-11-15 Philipp Sehmisch + + * data/graphics/tiles/Woodland_village.png, + data/graphics/tiles/Woodland_village_x2.png, + data/graphics/tiles/Woodland_x2.png, + data/graphics/tiles/Makefile.AM, + data/graphics/tiles/CMakeList.txt, + data/maps/new_9-1.tmx.gz, data/maps/new_14-1.tmx.gz, + data/maps/new_15-1.tmx.gz, data/maps/new_16-1.tmx.gz, + data/maps/new_17-1.tmx.gz, data/maps/new_18-1.tmx.gz, + data/maps/new_19-1.tmx.gz, data/maps/CMakeList.txt, + data/maps/Makefile.AM: + Added woodland village outdoor tileset and maps. Modified gates on + the nearby maps. + +2006-11-15 Bjørn Lindeijer + + * src/animatedsprite.h, src/CMakeLists.txt, src/animatedsprite.cpp, + src/utils/xml.cpp, src/utils/xml.h, src/Makefile.am, + src/resources/mapreader.cpp: Separated getProperty method to an XML + utility namespace. + +2006-11-15 Eugenio Favalli + + * The Mana World.dev, tmw.cbp: Updated project files. + * The Mana World.dev, tmw.cbp: Fixed dynamic linking of libcurl. + +2006-11-14 Bjørn Lindeijer + + * src/action.h, src/action.cpp, src/animation.h, src/CMakeLists.txt, + src/animatedsprite.cpp, src/animation.cpp, src/Makefile.am: Separated + Action class to its own module. + * src/action.h, src/action.cpp, src/animatedsprite.h, src/animation.h, + src/animatedsprite.cpp, src/animation.cpp: Resolve Image* of animation + phase at load time instead of storing just the spriteset index and + looking it up later (checking validity should still be added). Also + calculate animation length during loading instead of summing it up + each time it is requested. + +2006-11-12 Bjørn Lindeijer + + * src/map.cpp, src/map.h: Made pathfinding algorithm cope better with + beings blocking the road. This is done by allowing walking over other + beings, but at an additional cost so that it is preferable to walk + around them. + * src/game.cpp: Worked around a Guichan exception thrown for mice with + many buttons (patch by Roel van Dijk). + 2006-11-11 Björn Steinbrink * src/Makefile.am: Fixed autotools configuration. +2006-11-09 Eugenio Favalli + + * src/main.cpp, src/net/network.cpp, src/net/network.h, + The Mana World.dev, tmw.cbp: Fixed a conflict with Windows headers and + updated project files. + 2006-11-05 Eugenio Favalli * The Mana World.dev, tmw.cbp: Updated project files. Warning: Dev-Cpp will now build objects in the source folder. +2006-11-05 Bjørn Lindeijer + + * src/gui/trade.cpp: Fixed money field to no longer hide below the + bottom of the window. + * src/CMakeLists.txt: Added shoplistbox.h/cpp files. + * src/gui/updatewindow.cpp: Fixed percentage indicator of update + window. + * src/main.cpp, src/net/beinghandler.cpp, src/net/skillhandler.cpp, + src/net/network.cpp: Changed some printf statements to log statements. + 2006-11-05 Bjørn Lindeijer * data/graphics/images/login_wallpaper.png: Reverted to standard @@ -37,6 +326,7 @@ precisions about the total money in it. * src/gui/shop.h, src/gui/shop.cpp, src/gui/sell.cpp: Fixes to Sell dialog. + * src/gui/sell.cpp: Fixes the money value after selling something. 2006-11-05 Björn Steinbrink @@ -78,7 +368,7 @@ 2006-11-04 Philipp Sehmisch - * data/maps/new_17-1.tmx.gz, + * data/maps/new_17-1.tmx.gz, data/graphics/images/minimap_new_17-1.png, data/graphics/images/Makefile.am, data/graphics/images/CMakeLists.txt: diff --git a/NEWS b/NEWS index 4633c39b..f3b586f8 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,14 @@ +0.0.22 (...) +- Added support for female-specific equipment graphics +- Added support for monster sounds +- Changed to new update host (http://updates.themanaworld.org) +- Worked around a Guichan exception thrown for mice with many buttons +- Changed mouse walk to keep following mouse while button is held down +- Extended font support for Ã¥ and Ã…. +- Fixed joystick setting not to show disabled when it's actually enabled +- Fixed money field to no longer hide below the bottom of the window +- Fixed pathfinding to allow walking through beings when they block your path + 0.0.21.1 (30 October 2006) - Reload wallpaper after loading updates - Added support for gzip compressed map layer data diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 36259082..e60bfe30 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -7,7 +7,8 @@ ADD_SUBDIRECTORY(maps) ADD_SUBDIRECTORY(sfx) SET(FILES + equipment.xml items.xml ) -INSTALL(FILES ${FILES} DESTINATION ${DATA_DIR}) +INSTALL(FILES ${FILES} DESTINATION ${DATA_DIR}) \ No newline at end of file diff --git a/data/Makefile.am b/data/Makefile.am index 7d16a1fc..ed080d08 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -4,7 +4,8 @@ SUBDIRS = graphics help icons maps sfx tmwdatadir = $(pkgdatadir)/data tmwdata_DATA = \ + equipment.xml \ items.xml EXTRA_DIST = \ - $(tmwdata_DATA) + $(tmwdata_DATA) \ No newline at end of file diff --git a/data/graphics/images/CMakeLists.txt b/data/graphics/images/CMakeLists.txt index 53f8b3a7..f02cd2ea 100644 --- a/data/graphics/images/CMakeLists.txt +++ b/data/graphics/images/CMakeLists.txt @@ -1,6 +1,7 @@ ADD_SUBDIRECTORY(ambient) SET(FILES + error.png login_wallpaper.png minimap_new_1-1.png minimap_new_14-1.png diff --git a/data/graphics/images/Makefile.am b/data/graphics/images/Makefile.am index cc71b18a..00d9ed7e 100644 --- a/data/graphics/images/Makefile.am +++ b/data/graphics/images/Makefile.am @@ -3,6 +3,7 @@ SUBDIRS = ambient imagesdir = $(pkgdatadir)/data/graphics/images images_DATA = \ + error.png \ login_wallpaper.png \ minimap_new_1-1.png \ minimap_new_2-1.png \ diff --git a/data/graphics/images/error.png b/data/graphics/images/error.png new file mode 100644 index 00000000..6fd7c1a8 Binary files /dev/null and b/data/graphics/images/error.png differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4fd8d880..e0b93382 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -155,6 +155,8 @@ SET(SRCS gui/vbox.h gui/windowcontainer.cpp gui/windowcontainer.h + gui/viewport.cpp + gui/viewport.h gui/window.cpp gui/window.h gui/widgets/dropdown.cpp @@ -216,17 +218,24 @@ SET(SRCS resources/ambientoverlay.h resources/buddylist.cpp resources/buddylist.h + resources/equipmentdb.cpp + resources/equipmentdb.h + resources/equipmentinfo.h resources/image.cpp resources/image.h resources/imagewriter.cpp resources/imagewriter.h resources/iteminfo.cpp + resources/itemdb.cpp + resources/itemdb.h resources/iteminfo.h - resources/itemmanager.cpp - resources/itemmanager.h resources/mapreader.cpp resources/mapreader.h resources/music.cpp + resources/monsterdb.h + resources/monsterdb.cpp + resources/monsterinfo.h + resources/monsterinfo.cpp resources/music.h resources/openglsdlimageloader.cpp resources/openglsdlimageloader.h @@ -239,9 +248,15 @@ SET(SRCS resources/soundeffect.cpp resources/soundeffect.h resources/spriteset.cpp + resources/spritedef.h + resources/spritedef.cpp resources/spriteset.h utils/dtor.h utils/tostring.h + utils/xml.cpp + utils/xml.h + action.cpp + action.h animatedsprite.cpp animatedsprite.h animation.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 23c57922..1628df18 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -110,6 +110,8 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ gui/textfield.h \ gui/trade.cpp \ gui/trade.h \ + gui/viewport.cpp \ + gui/viewport.h \ gui/window.cpp \ gui/window.h \ gui/windowcontainer.cpp \ @@ -179,16 +181,23 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ net/gameserver/player.h \ resources/ambientoverlay.cpp \ resources/ambientoverlay.h \ + resources/equipmentdb.cpp \ + resources/equipmentdb.h \ + resources/equipmentinfo.h \ resources/image.cpp \ resources/image.h \ resources/imagewriter.cpp \ resources/imagewriter.h \ + resources/itemdb.cpp \ + resources/itemdb.h \ resources/iteminfo.h \ resources/iteminfo.cpp \ - resources/itemmanager.cpp \ - resources/itemmanager.h \ resources/mapreader.cpp \ resources/mapreader.h \ + resources/monsterdb.h \ + resources/monsterdb.cpp \ + resources/monsterinfo.h \ + resources/monsterinfo.cpp \ resources/music.h \ resources/music.cpp \ resources/openglsdlimageloader.h \ @@ -201,12 +210,18 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ resources/sdlimageloader.cpp \ resources/soundeffect.h \ resources/soundeffect.cpp \ + resources/spritedef.h \ + resources/spritedef.cpp \ resources/spriteset.h \ resources/spriteset.cpp \ resources/buddylist.h \ resources/buddylist.cpp \ utils/dtor.h \ utils/tostring.h \ + utils/xml.cpp \ + utils/xml.h \ + action.cpp \ + action.h \ animatedsprite.cpp \ animatedsprite.h \ animation.cpp \ diff --git a/src/action.cpp b/src/action.cpp new file mode 100644 index 00000000..148ea105 --- /dev/null +++ b/src/action.cpp @@ -0,0 +1,66 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "action.h" + +#include + +#include "animation.h" +#include "utils/dtor.h" + + +Action::Action() +{ +} + +Action::~Action() +{ + std::for_each(mAnimations.begin(), mAnimations.end(), + make_dtor(mAnimations)); +} + +Animation* +Action::getAnimation(int direction) const +{ + Animations::const_iterator i = mAnimations.find(direction); + + // When the direction isn't defined, try the default + if (i == mAnimations.end()) + { + i = mAnimations.find(0); + } + + return (i == mAnimations.end()) ? NULL : i->second; +} + +void +Action::setAnimation(int direction, Animation *animation) +{ + // Set first direction as default direction + if (mAnimations.empty()) + { + mAnimations[0] = animation; + } + + mAnimations[direction] = animation; +} diff --git a/src/action.h b/src/action.h new file mode 100644 index 00000000..8d5e8d11 --- /dev/null +++ b/src/action.h @@ -0,0 +1,61 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_ACTION_H +#define _TMW_ACTION_H + +#include + +#include + +class Animation; + +/** + * An action consists of several animations, one for each direction. + */ +class Action +{ + public: + /** + * Constructor. + */ + Action(); + + /** + * Destructor. + */ + ~Action(); + + void + setAnimation(int direction, Animation *animation); + + Animation* + getAnimation(int direction) const; + + protected: + typedef std::map Animations; + typedef Animations::iterator AnimationIterator; + Animations mAnimations; +}; + +#endif diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp index 3815f04a..46369c80 100644 --- a/src/animatedsprite.cpp +++ b/src/animatedsprite.cpp @@ -24,401 +24,177 @@ #include "animatedsprite.h" #include "animation.h" +#include "action.h" #include "graphics.h" #include "log.h" #include "resources/resourcemanager.h" #include "resources/spriteset.h" +#include "resources/image.h" -AnimatedSprite::AnimatedSprite(const std::string& animationFile, int variant): - mAction(NULL), +#include "utils/xml.h" + +#include + +AnimatedSprite::AnimatedSprite(SpriteDef *sprite): mDirection(DIRECTION_DOWN), mLastTime(0), - mSpeed(1.0f), - mAnimationFile(animationFile) + mFrameIndex(0), + mFrameTime(0), + mSprite(sprite), + mAction(0), + mAnimation(0), + mFrame(0) { - int size; - ResourceManager *resman = ResourceManager::getInstance(); - char *data = (char*)resman->loadFile(animationFile.c_str(), size); - - if (!data) { - logger->error("Animation: Could not find " + animationFile + "!"); - } - - xmlDocPtr doc = xmlParseMemory(data, size); - free(data); - - if (!doc) { - logger->error( - "Animation: Error while parsing animation definition file!"); - } - - xmlNodePtr node = xmlDocGetRootElement(doc); - if (!node || !xmlStrEqual(node->name, BAD_CAST "sprite")) { - logger->error( - "Animation: this is not a valid animation definition file!"); - } - - // Get the variant - int variant_num = getProperty(node, "variants", 0); - int variant_offset = getProperty(node, "variant_offset", 0); - - if (variant_num > 0 && variant < variant_num ) { - variant_offset *= variant; - } else { - variant_offset = 0; - } + assert(mSprite); - for (node = node->xmlChildrenNode; node != NULL; node = node->next) - { - if (xmlStrEqual(node->name, BAD_CAST "imageset")) - { - int width = getProperty(node, "width", 0); - int height = getProperty(node, "height", 0); - std::string name = getProperty(node, "name", ""); - std::string imageSrc = getProperty(node, "src", ""); - - Spriteset *spriteset = - resman->getSpriteset(imageSrc, width, height); - - if (!spriteset) { - logger->error("Couldn't load spriteset!"); - } - - mSpritesets[name] = spriteset; - } - // get action - else if (xmlStrEqual(node->name, BAD_CAST "action")) - { - std::string actionName = getProperty(node, "name", ""); - std::string imageset = getProperty(node, "imageset", ""); - - if (mSpritesets.find(imageset) == mSpritesets.end()) { - logger->log("Warning: imageset \"%s\" not defined in %s", - imageset.c_str(), - animationFile.c_str()); - - // skip loading animations - continue; - } - - - SpriteAction actionType = makeSpriteAction(actionName); - if (actionType == ACTION_INVALID) - { - logger->log("Warning: Unknown action \"%s\" defined in %s", - actionName.c_str(), - animationFile.c_str()); - continue; - } - Action *action = new Action(); - action->setSpriteset(mSpritesets[imageset]); - mActions[actionType] = action; - - // When first action set it as default direction - if (mActions.empty()) - { - mActions[ACTION_DEFAULT] = action; - } - - - // get animations - for (xmlNodePtr animationNode = node->xmlChildrenNode; - animationNode != NULL; - animationNode = animationNode->next) - { - // We're only interested in animations - if (!xmlStrEqual(animationNode->name, BAD_CAST "animation")) - continue; - - std::string directionName = getProperty(animationNode, "direction", ""); - - SpriteDirection directionType = makeSpriteDirection(directionName); - if (directionType == DIRECTION_INVALID) - { - logger->log("Warning: Unknown direction \"%s\" defined for action %s in %s", - directionName.c_str(), - actionName.c_str(), - animationFile.c_str()); - continue; - } - - Animation *animation = new Animation(); - action->setAnimation(directionType, animation); - - // Get animation phases - for (xmlNodePtr phaseNode = animationNode->xmlChildrenNode; - phaseNode != NULL; - phaseNode = phaseNode->next) - { - int delay = getProperty(phaseNode, "delay", 0); - - if (xmlStrEqual(phaseNode->name, BAD_CAST "frame")) - { - int index = getProperty(phaseNode, "index", -1); - int offsetX = getProperty(phaseNode, "offsetX", 0); - int offsetY = getProperty(phaseNode, "offsetY", 0); - - offsetY -= mSpritesets[imageset]->getHeight() - 32; - offsetX -= mSpritesets[imageset]->getWidth() / 2 - 16; - animation->addPhase(index + variant_offset, delay, - offsetX, offsetY); - } - else if (xmlStrEqual(phaseNode->name, BAD_CAST "sequence")) - { - int start = getProperty(phaseNode, "start", 0); - int end = getProperty(phaseNode, "end", 0); - int offsetY = -mSpritesets[imageset]->getHeight() + 32; - int offsetX = -mSpritesets[imageset]->getWidth() / 2 + 16; - while (end >= start) - { - animation->addPhase(start + variant_offset, - delay, offsetX, offsetY); - start++; - } - } - else if (xmlStrEqual(phaseNode->name, BAD_CAST "end")) - { - animation->addTerminator(); - }; - } // for phaseNode - } // for animationNode - } // if "" else if "" - } // for node - - // Complete missing actions - substituteAction(ACTION_STAND, ACTION_DEFAULT); - substituteAction(ACTION_WALK, ACTION_STAND); - substituteAction(ACTION_WALK, ACTION_RUN); - substituteAction(ACTION_ATTACK, ACTION_STAND); - substituteAction(ACTION_ATTACK_SWING, ACTION_ATTACK); - substituteAction(ACTION_ATTACK_STAB, ACTION_ATTACK_SWING); - substituteAction(ACTION_ATTACK_BOW, ACTION_ATTACK_STAB); - substituteAction(ACTION_ATTACK_THROW, ACTION_ATTACK_SWING); - substituteAction(ACTION_CAST_MAGIC, ACTION_ATTACK_SWING); - substituteAction(ACTION_USE_ITEM, ACTION_CAST_MAGIC); - substituteAction(ACTION_SIT, ACTION_STAND); - substituteAction(ACTION_SLEEP, ACTION_SIT); - substituteAction(ACTION_HURT, ACTION_STAND); - substituteAction(ACTION_DEAD, ACTION_HURT); + // Take possession of the sprite + mSprite->incRef(); // Play the stand animation by default play(ACTION_STAND); - - xmlFreeDoc(doc); -} - -int -AnimatedSprite::getProperty(xmlNodePtr node, const char* name, int def) -{ - int &ret = def; - - xmlChar *prop = xmlGetProp(node, BAD_CAST name); - if (prop) { - ret = atoi((char*)prop); - xmlFree(prop); - } - - return ret; } -std::string -AnimatedSprite::getProperty(xmlNodePtr node, const char* name, - const std::string& def) +AnimatedSprite::AnimatedSprite(const std::string& filename, int variant): + mDirection(DIRECTION_DOWN), + mLastTime(0), + mFrameIndex(0), + mFrameTime(0), + mAnimation(0), + mFrame(0) { - xmlChar *prop = xmlGetProp(node, BAD_CAST name); - if (prop) { - std::string val = (char*)prop; - xmlFree(prop); - return val; - } - - return def; -} + ResourceManager *resman = ResourceManager::getInstance(); + mSprite = resman->getSprite(filename, variant); + assert(mSprite); -void -AnimatedSprite::substituteAction(SpriteAction complete, - SpriteAction with) -{ - if (mActions.find(complete) == mActions.end()) - { - ActionIterator i = mActions.find(with); - if (i != mActions.end()) { - mActions[complete] = i->second; - } - } + // Play the stand animation by default + play(ACTION_STAND); } AnimatedSprite::~AnimatedSprite() { - for (SpritesetIterator i = mSpritesets.begin(); i != mSpritesets.end(); ++i) - { - i->second->decRef(); - } - mSpritesets.clear(); + mSprite->decRef(); } void AnimatedSprite::reset() { - // Reset all defined actions (because of aliases some will be resetted - // multiple times, but this doesn't matter) - for (ActionIterator i = mActions.begin(); i != mActions.end(); ++i) - { - if (i->second) - { - i->second->reset(); - } - } + mFrameIndex = 0; + mFrameTime = 0; + mLastTime = 0; } void -AnimatedSprite::play(SpriteAction action) +AnimatedSprite::play(SpriteAction spriteAction) { - ActionIterator i = mActions.find(action); - - if (i == mActions.end()) + Action *action = mSprite->getAction(spriteAction); + if (!action) { - //logger->log("Warning: no action %u defined for \"%s\"!", - // action, mAnimationFile.c_str()); - mAction = NULL; return; } - if (mAction != i->second) + mAction = action; + Animation *animation = mAction->getAnimation(mDirection); + + if (animation && animation != mAnimation && animation->getLength() > 0) { - mAction = i->second; - //mAction->reset(); + mAnimation = animation; + mFrame = mAnimation->getFrame(0); + + reset(); } } void AnimatedSprite::update(int time) { - bool notFinished = true; // Avoid freaking out at first frame or when tick_time overflows if (time < mLastTime || mLastTime == 0) + { mLastTime = time; + } // If not enough time has passed yet, do nothing - if (time > mLastTime && mAction) + if (time <= mLastTime || !mAnimation) { - Animation *animation = mAction->getAnimation(mDirection); - if (animation != NULL) { - notFinished = animation->update((unsigned int)(time - mLastTime));} - mLastTime = time; + return; } - if (!notFinished) + unsigned int dt = time - mLastTime; + mLastTime = time; + + if (!updateCurrentAnimation(dt)) { + // Animation finished, reset to default play(ACTION_STAND); } } bool -AnimatedSprite::draw(Graphics* graphics, Sint32 posX, Sint32 posY) const +AnimatedSprite::updateCurrentAnimation(unsigned int time) { - if (!mAction) + if (!mFrame || Animation::isTerminator(*mFrame)) + { return false; + } - Animation *animation = mAction->getAnimation(mDirection); - if (animation == NULL) return false; + mFrameTime += time; - int phase = animation->getCurrentPhase(); - if (phase < 0) - return false; + while (mFrameTime > mFrame->delay && mFrame->delay > 0) + { + mFrameTime -= mFrame->delay; + mFrameIndex++; - Spriteset *spriteset = mAction->getSpriteset(); - Image *image = spriteset->get(phase); - Sint32 offsetX = animation->getOffsetX(); - Sint32 offsetY = animation->getOffsetY(); - return graphics->drawImage(image, posX + offsetX, posY + offsetY); -} + if (mFrameIndex == mAnimation->getLength()) + { + mFrameIndex = 0; + } -int -AnimatedSprite::getWidth() const -{ - return mAction ? mAction->getSpriteset()->getWidth() : 0; -} + mFrame = mAnimation->getFrame(mFrameIndex); -int -AnimatedSprite::getHeight() const -{ - return mAction ? mAction->getSpriteset()->getHeight() : 0; + if (Animation::isTerminator(*mFrame)) + { + mAnimation = 0; + mFrame = 0; + return false; + } + } + + return true; } -SpriteAction -AnimatedSprite::makeSpriteAction(const std::string& action) +bool +AnimatedSprite::draw(Graphics* graphics, int posX, int posY) const { - if (action == "" || action == "default") { - return ACTION_DEFAULT; - } - if (action == "stand") { - return ACTION_STAND; - } - else if (action == "walk") { - return ACTION_WALK; - } - else if (action == "run") { - return ACTION_RUN; - } - else if (action == "attack") { - return ACTION_ATTACK; - } - else if (action == "attack_swing") { - return ACTION_ATTACK_SWING; - } - else if (action == "attack_stab") { - return ACTION_ATTACK_STAB; - } - else if (action == "attack_bow") { - return ACTION_ATTACK_BOW; - } - else if (action == "attack_throw") { - return ACTION_ATTACK_THROW; - } - else if (action == "cast_magic") { - return ACTION_CAST_MAGIC; - } - else if (action == "use_item") { - return ACTION_USE_ITEM; - } - else if (action == "sit") { - return ACTION_SIT; - } - else if (action == "sleep") { - return ACTION_SLEEP; - } - else if (action == "hurt") { - return ACTION_HURT; - } - else if (action == "dead") { - return ACTION_DEAD; - } - else { - return ACTION_INVALID; + if (!mFrame || !mFrame->image) + { + return false; } + + return graphics->drawImage(mFrame->image, + posX + mFrame->offsetX, + posY + mFrame->offsetY); } -SpriteDirection -AnimatedSprite::makeSpriteDirection(const std::string& direction) +void +AnimatedSprite::setDirection(SpriteDirection direction) { - if (direction == "" || direction == "default") { - return DIRECTION_DEFAULT; - } - else if (direction == "up") { - return DIRECTION_UP; - } - else if (direction == "left") { - return DIRECTION_LEFT; - } - else if (direction == "right") { - return DIRECTION_RIGHT; - } - else if (direction == "down") { - return DIRECTION_DOWN; + if (mDirection != direction) + { + mDirection = direction; + + if (!mAction) + { + return; + } + + Animation *animation = mAction->getAnimation(mDirection); + + if (animation && animation != mAnimation && animation->getLength() > 0) + { + mAnimation = animation; + mFrame = mAnimation->getFrame(0); + reset(); + } } - else { - return DIRECTION_INVALID; - }; } diff --git a/src/animatedsprite.h b/src/animatedsprite.h index bda612ab..4e485f14 100644 --- a/src/animatedsprite.h +++ b/src/animatedsprite.h @@ -24,56 +24,34 @@ #ifndef _TMW_ANIMATEDSPRITE_H #define _TMW_ANIMATEDSPRITE_H +#include "resources/spritedef.h" + #include #include -#include - -#include -class Action; class Graphics; -class Spriteset; - -enum SpriteAction -{ - ACTION_DEFAULT = 0, - ACTION_STAND, - ACTION_WALK, - ACTION_RUN, - ACTION_ATTACK, - ACTION_ATTACK_SWING, - ACTION_ATTACK_STAB, - ACTION_ATTACK_BOW, - ACTION_ATTACK_THROW, - ACTION_CAST_MAGIC, - ACTION_USE_ITEM, - ACTION_SIT, - ACTION_SLEEP, - ACTION_HURT, - ACTION_DEAD, - ACTION_INVALID -}; - -enum SpriteDirection -{ - DIRECTION_DEFAULT = 0, - DIRECTION_DOWN, - DIRECTION_UP, - DIRECTION_LEFT, - DIRECTION_RIGHT, - DIRECTION_INVALID -}; +struct AnimationPhase; /** - * Defines a class to load an animation. + * Animates a sprite by adding playback state. */ class AnimatedSprite { public: /** * Constructor. + * @param sprite the sprite to animate */ - AnimatedSprite(const std::string& animationFile, int variant); + AnimatedSprite(SpriteDef *sprite); + + /** + * A convenience constructor, which will request the sprite to animate + * from the resource manager. + * + * @param filename the file of the sprite to animate + * @param variant the sprite variant + */ + AnimatedSprite(const std::string& filename, int variant = 0); /** * Destructor. @@ -81,8 +59,7 @@ class AnimatedSprite ~AnimatedSprite(); /** - * Resets the animated sprite. This is used to synchronize several - * animated sprites. + * Resets the animated sprite. */ void reset(); @@ -97,84 +74,36 @@ class AnimatedSprite * Inform the animation of the passed time so that it can output the * correct animation phase. */ - void update(int time); + void + update(int time); /** * Draw the current animation phase at the coordinates given in screen * pixels. */ bool - draw(Graphics* graphics, Sint32 posX, Sint32 posY) const; - - /** - * gets the width in pixels of the current animation phase. - */ - int - getWidth() const; - - /** - * gets the height in pixels of the current animation phase. - */ - int - getHeight() const; + draw(Graphics* graphics, int posX, int posY) const; /** * Sets the direction. */ void - setDirection(SpriteDirection direction) - { - mDirection = direction; - } + setDirection(SpriteDirection direction); private: - /** - * When there are no animations defined for the action "complete", its - * animations become a copy of those of the action "with". - */ - void - substituteAction(SpriteAction complete, SpriteAction with); - - /** - * Gets an integer property from an xmlNodePtr. - * - * TODO: Same function is present in MapReader. Should probably be - * TODO: shared in a static utility class. - */ - static int - getProperty(xmlNodePtr node, const char *name, int def); - - /** - * Gets a string property from an xmlNodePtr. - */ - static std::string - getProperty(xmlNodePtr node, const char *name, const std::string &def); - - /** - * Converts a string into a SpriteAction enum. - */ - static SpriteAction - makeSpriteAction(const std::string &action); - - /** - * Converts a string into a SpriteDirection enum. - */ - static SpriteDirection - makeSpriteDirection(const std::string &direction); - + bool + updateCurrentAnimation(unsigned int dt); - typedef std::map Spritesets; - typedef Spritesets::iterator SpritesetIterator; + SpriteDirection mDirection; /**< The sprite direction. */ + int mLastTime; /**< The last time update was called. */ - typedef std::map Actions; - typedef Actions::iterator ActionIterator; + unsigned int mFrameIndex; /**< The index of the current frame. */ + unsigned int mFrameTime; /**< The time since start of frame. */ - Spritesets mSpritesets; - Actions mActions; - Action *mAction; - SpriteDirection mDirection; - int mLastTime; - float mSpeed; + SpriteDef *mSprite; /**< The sprite definition. */ + Action *mAction; /**< The currently active action. */ + Animation *mAnimation; /**< The currently active animation. */ + AnimationPhase *mFrame; /**< The currently active frame. */ std::string mAnimationFile; }; diff --git a/src/animation.cpp b/src/animation.cpp index 98a4abb8..67fdae11 100644 --- a/src/animation.cpp +++ b/src/animation.cpp @@ -27,138 +27,29 @@ #include "utils/dtor.h" -Animation::Animation() +Animation::Animation(): + mDuration(0) { - reset(); } void -Animation::reset() +Animation::addPhase(Image *image, unsigned int delay, int offsetX, int offsetY) { - mTime = 0; - iCurrentPhase = mAnimationPhases.begin(); -} - - -bool -Animation::update(unsigned int time) -{ - mTime += time; - if (mAnimationPhases.empty()) - return true; - if (isTerminator(*iCurrentPhase)) - return false; - - unsigned int delay = iCurrentPhase->delay; - - while (mTime > delay) - { - if (!delay) - return true; - mTime -= delay; - iCurrentPhase++; - if (iCurrentPhase == mAnimationPhases.end()) - { - iCurrentPhase = mAnimationPhases.begin(); - } - if (isTerminator(*iCurrentPhase)) - return false; - delay = iCurrentPhase->delay; - } - return true; -} - - -int -Animation::getCurrentPhase() const -{ - return mAnimationPhases.empty() ? -1 : iCurrentPhase->image; -} - - -void -Animation::addPhase(int image, unsigned int delay, int offsetX, int offsetY) -{ - //add new phase to animation list - AnimationPhase newPhase = { image, delay, offsetX, offsetY}; + // Add new phase to animation list + AnimationPhase newPhase = { image, delay, offsetX, offsetY }; mAnimationPhases.push_back(newPhase); - //reset animation circle - iCurrentPhase = mAnimationPhases.begin(); + mDuration += delay; } void Animation::addTerminator() { - AnimationPhase terminator = { -1, 0, 0, 0}; - mAnimationPhases.push_back(terminator); - iCurrentPhase = mAnimationPhases.begin(); + addPhase(NULL, 0, 0, 0); } bool -Animation::isTerminator(AnimationPhase candidate) -{ - return (candidate.image < 0); -} - -int -Animation::getLength() -{ - if (mAnimationPhases.empty()) - return 0; - - std::list::iterator i; - int length = 0; - for (i = mAnimationPhases.begin(); i != mAnimationPhases.end(); i++) - { - length += i->delay; - } - return length; -} - -Action::Action(): - mSpriteset(NULL) -{ -} - -Action::~Action() -{ - std::for_each(mAnimations.begin(), mAnimations.end(), make_dtor(mAnimations)); - mAnimations.clear(); -} - -Animation* -Action::getAnimation(int direction) const -{ - Animations::const_iterator i = mAnimations.find(direction); - - // When the direction isn't defined, try the default - if (i == mAnimations.end()) - { - i = mAnimations.find(0); - } - - return (i == mAnimations.end()) ? NULL : i->second; -} - -void -Action::setAnimation(int direction, Animation *animation) -{ - // Set first direction as default direction - if (mAnimations.empty()) - { - mAnimations[0] = animation; - } - - mAnimations[direction] = animation; -} - -void -Action::reset() +Animation::isTerminator(const AnimationPhase candidate) { - for (AnimationIterator i = mAnimations.begin(); - i != mAnimations.end(); ++i) - { - i->second->reset(); - } + return (candidate.image == NULL); } diff --git a/src/animation.h b/src/animation.h index 605d8cb1..85e950d7 100644 --- a/src/animation.h +++ b/src/animation.h @@ -24,8 +24,7 @@ #ifndef _TMW_ANIMATION_H #define _TMW_ANIMATION_H -#include -#include +#include #include @@ -34,10 +33,12 @@ class Spriteset; /** * A single frame in an animation, with a delay and an offset. + * + * TODO: Rename this struct to Frame */ struct AnimationPhase { - int image; + Image *image; unsigned int delay; int offsetX; int offsetY; @@ -55,106 +56,46 @@ class Animation */ Animation(); - /** - * Restarts the animation from the first frame. - */ - void - reset(); - /** * Appends a new animation at the end of the sequence */ void - addPhase(int image, unsigned int delay, int offsetX, int offsetY); + addPhase(Image *image, unsigned int delay, int offsetX, int offsetY); /** * Appends an animation terminator that states that the animation - * should not loop + * should not loop. */ void addTerminator(); /** - * Updates animation phase. - * true indicates a still running animation while false indicates a - * finished animation + * Returns the frame at the specified index. */ - bool - update(unsigned int time); - - int - getCurrentPhase() const; + AnimationPhase* + getFrame(int index) { return &(mAnimationPhases[index]); } /** - * Returns the x offset of the current frame. + * Returns the length of this animation in frames. */ - int - getOffsetX() const { return iCurrentPhase->offsetX; }; + unsigned int + getLength() const { return mAnimationPhases.size(); } /** - * Returns the y offset of the current frame. + * Returns the duration of this animation. */ int - getOffsetY() const { return iCurrentPhase->offsetY; }; + getDuration() const { return mDuration; } /** - * Returns the length of this animation. + * Determines whether the given animation frame is a terminator. */ - int - getLength(); - - protected: - static bool isTerminator(AnimationPhase); - std::list mAnimationPhases; - std::list::iterator iCurrentPhase; - unsigned int mTime; -}; - -/** - * An action consists of several animations, one for each direction. - */ -class Action -{ - public: - /** - * Constructor. - */ - Action(); - - /** - * Destructor. - */ - ~Action(); - - /** - * Sets the spriteset used by this action. - */ - void - setSpriteset(Spriteset *spriteset) { mSpriteset = spriteset; } - - /** - * Returns the spriteset used by this action. - */ - Spriteset* - getSpriteset() const { return mSpriteset; } - - void - setAnimation(int direction, Animation *animation); - - /** - * Resets all animations associated with this action. - */ - void - reset(); - - Animation* - getAnimation(int direction) const; + static bool + isTerminator(const AnimationPhase phase); protected: - Spriteset *mSpriteset; - typedef std::map Animations; - typedef Animations::iterator AnimationIterator; - Animations mAnimations; + std::vector mAnimationPhases; + int mDuration; }; #endif diff --git a/src/base64.cpp b/src/base64.cpp index 6d503a53..9a8f6356 100644 --- a/src/base64.cpp +++ b/src/base64.cpp @@ -1,16 +1,27 @@ /* +----------------------------------------------------------------------+ - | PHP version 4.0 | + | PHP HTML Embedded Scripting Language Version 3.0 | +----------------------------------------------------------------------+ - | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group | + | Copyright (c) 1997-2000 PHP Development Team (See Credits file) | +----------------------------------------------------------------------+ - | This source file is subject to version 2.02 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available at through the world-wide-web at | - | http://www.php.net/license/2_02.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | + | This program is free software; you can redistribute it and/or modify | + | it under the terms of one of the following licenses: | + | | + | A) the GNU General Public License as published by the Free Software | + | Foundation; either version 2 of the License, or (at your option) | + | any later version. | + | | + | B) the PHP License as published by the PHP Development Team and | + | included in the distribution in the file: LICENSE | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU General Public License for more details. | + | | + | You should have received a copy of both licenses referred to here. | + | If you did not, or have any questions about PHP licensing, please | + | contact core@php.net. | +----------------------------------------------------------------------+ | Author: Jim Winstead (jimw@php.net) | +----------------------------------------------------------------------+ @@ -32,8 +43,8 @@ static char base64_table[] = }; static char base64_pad = '='; -unsigned char *php_base64_encode(const unsigned char *str, int length, int *ret_length) { - const unsigned char *current = str; +unsigned char *php3_base64_encode(const unsigned char *string, int length, int *ret_length) { + const unsigned char *current = string; int i = 0; unsigned char *result = (unsigned char *)malloc(((length + 3 - length % 3) * 4 / 3 + 1) * sizeof(char)); @@ -69,27 +80,13 @@ unsigned char *php_base64_encode(const unsigned char *str, int length, int *ret_ } /* as above, but backwards. :) */ -unsigned char *php_base64_decode(const unsigned char *str, int length, int *ret_length) { - const unsigned char *current = str; +unsigned char *php3_base64_decode(const unsigned char *string, int length, int *ret_length) { + const unsigned char *current = string; int ch, i = 0, j = 0, k; - /* this sucks for threaded environments */ - static short reverse_table[256]; - static int table_built; - unsigned char *result; - - if (++table_built == 1) { - char *chp; - for(ch = 0; ch < 256; ch++) { - chp = strchr(base64_table, ch); - if(chp) { - reverse_table[ch] = chp - base64_table; - } else { - reverse_table[ch] = -1; - } - } - } + char *chp; + + unsigned char *result = (unsigned char *)malloc(length + 1); - result = (unsigned char *)malloc(length + 1); if (result == NULL) { return NULL; } @@ -107,8 +104,9 @@ unsigned char *php_base64_decode(const unsigned char *str, int length, int *ret_ if (ch == ' ') ch = '+'; - ch = reverse_table[ch]; - if (ch < 0) continue; + chp = strchr(base64_table, ch); + if (chp == NULL) continue; + ch = chp - base64_table; switch(i % 4) { case 0: @@ -149,4 +147,3 @@ unsigned char *php_base64_decode(const unsigned char *str, int length, int *ret_ result[k] = '\0'; return result; } - diff --git a/src/base64.h b/src/base64.h index 5b275c45..ff20ac53 100644 --- a/src/base64.h +++ b/src/base64.h @@ -31,14 +31,7 @@ #ifndef _TMW_BASE64_H #define _TMW_BASE64_H -extern unsigned char *php_base64_encode(const unsigned char *, int, int *); -extern unsigned char *php_base64_decode(const unsigned char *, int, int *); +extern unsigned char *php3_base64_encode(const unsigned char *, int, int *); +extern unsigned char *php3_base64_decode(const unsigned char *, int, int *); #endif /* _TMW_BASE64_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - */ diff --git a/src/being.cpp b/src/being.cpp index 50a2dc35..9cd0af0d 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -49,7 +49,7 @@ PATH_NODE::PATH_NODE(Uint16 iX, Uint16 iY): Being::Being(Uint16 id, Uint16 job, Map *map): mJob(job), - mX(0), mY(0), mDirection(DOWN), + mX(0), mY(0), mAction(STAND), mWalkTime(0), mEmotion(0), mEmotionTime(0), @@ -60,12 +60,15 @@ Being::Being(Uint16 id, Uint16 job, Map *map): mWeapon(0), mWalkSpeed(150), mSpeedModifier(1024), + mDirection(DOWN), mMap(NULL), mHairStyle(0), mHairColor(0), mSpeechTime(0), mDamageTime(0), mShowSpeech(false), mShowDamage(false), - mSprites(VECTOREND_SPRITE, NULL) + mPx(0), mPy(0), + mSprites(VECTOREND_SPRITE, NULL), + mEquipmentSpriteIDs(VECTOREND_SPRITE, 0) { setMap(map); } @@ -110,9 +113,7 @@ void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY) p1 = mMap->findPath(srcX / 32, srcY / 32, dstX / 32, dstY / 32); if (p1.empty()) { - // No path? Better teleport. - mX = dstX; - mY = dstY; + // No path, but don't teleport since it could be user input. setPath(p1); return; } @@ -189,9 +190,8 @@ void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY) if (bestRating < 0) { - // Unable to reach the path? Better teleport. - mX = srcX; - mY = srcY; + // Unable to reach the path? Still, don't teleport since it could be + // user input instead of server command. setPath(p1); delete[] p1_dist; return; @@ -263,8 +263,9 @@ Being::setHairStyle(Uint16 style) } void -Being::setVisibleEquipment(Uint8 slot, Uint8 id) +Being::setVisibleEquipment(Uint8 slot, int id) { + mEquipmentSpriteIDs[slot] = id; } void @@ -304,7 +305,7 @@ Being::setMap(Map *map) void Being::setAction(Uint8 action) { - SpriteAction currentAction = ACTION_STAND; + SpriteAction currentAction = ACTION_INVALID; switch (action) { case WALK: @@ -314,37 +315,21 @@ Being::setAction(Uint8 action) currentAction = ACTION_SIT; break; case ATTACK: - if (getType() == MONSTER) + switch (getWeapon()) { - currentAction = ACTION_DEAD; + case 3: + currentAction = ACTION_ATTACK; + break; + case 2: + currentAction = ACTION_ATTACK_BOW; + break; + case 1: + currentAction = ACTION_ATTACK_STAB; + break; + case 0: + currentAction = ACTION_ATTACK; + break; } - else { - switch (getWeapon()) - { - case 3: - currentAction = ACTION_ATTACK; - break; - case 2: - currentAction = ACTION_ATTACK_BOW; - break; - case 1: - currentAction = ACTION_ATTACK_STAB; - break; - case 0: - currentAction = ACTION_ATTACK; - break; - } - for (int i = 0; i < VECTOREND_SPRITE; i++) - { - if (mSprites[i]) - { - mSprites[i]->reset(); - } - } - }; - break; - case MONSTER_ATTACK: - currentAction = ACTION_ATTACK; for (int i = 0; i < VECTOREND_SPRITE; i++) { if (mSprites[i]) @@ -353,25 +338,33 @@ Being::setAction(Uint8 action) } } break; + case HURT: + //currentAction = ACTION_HURT; // Buggy: makes the player stop + // attacking and unable to attack + // again until he moves + break; case DEAD: currentAction = ACTION_DEAD; break; - default: + case STAND: currentAction = ACTION_STAND; break; } - for (int i = 0; i < VECTOREND_SPRITE; i++) + if (currentAction != ACTION_INVALID) { - if (mSprites[i]) + for (int i = 0; i < VECTOREND_SPRITE; i++) { - mSprites[i]->play(currentAction); + if (mSprites[i]) + { + mSprites[i]->play(currentAction); + } } + mAction = action; } - - mAction = action; } + void Being::setDirection(Uint8 direction) { @@ -487,7 +480,7 @@ Being::logic() } void -Being::draw(Graphics *graphics, int offsetX, int offsetY) +Being::draw(Graphics *graphics, int offsetX, int offsetY) const { int px = mPx + offsetX; int py = mPy + offsetY; @@ -528,7 +521,7 @@ Being::drawSpeech(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) } // Draw damage above this being - if (mShowDamage) + if (mShowDamage && get_elapsed_time(mDamageTime) > 250) { // Selecting the right color if (mDamage == "miss") diff --git a/src/being.h b/src/being.h index 2804b20b..c95cd191 100644 --- a/src/being.h +++ b/src/being.h @@ -68,14 +68,12 @@ class Being : public Sprite }; enum Action { - STAND = 0, - WALK = 1, - MONSTER_ATTACK = 5, - SIT = 7, - DEAD = 8, - ATTACK = 9, - MONSTER_DEAD = 9, - HIT = 17 + STAND, + WALK, + ATTACK, + SIT, + DEAD, + HURT }; enum Sprite { @@ -101,7 +99,6 @@ class Being : public Sprite std::string mName; /**< Name of character */ Uint16 mJob; /**< Job (player job, npc, monster, ) */ Uint16 mX, mY; /**< Pixel coordinates (tile center) */ - Uint8 mDirection; /**< Facing direction */ Uint8 mAction; /**< Action the being is performing */ Uint16 mWalkTime; Uint8 mEmotion; /**< Currently showing emotion */ @@ -199,7 +196,7 @@ class Being : public Sprite * Sets visible equipments for this being. */ virtual void - setVisibleEquipment(Uint8 slot, Uint8 id); + setVisibleEquipment(Uint8 slot, int id); /** * Sets the sex for this being. @@ -216,7 +213,7 @@ class Being : public Sprite /** * Makes this being take the next step of his path. */ - void + virtual void nextStep(); /** @@ -301,7 +298,13 @@ class Being : public Sprite /** * Sets the current action. */ - void setAction(Uint8 action); + virtual void + setAction(Uint8 action); + + /** + * Returns the current direction. + */ + Uint8 getDirection() const { return mDirection; } /** * Sets the current direction. @@ -314,7 +317,7 @@ class Being : public Sprite * @see Sprite::draw(Graphics, int, int) */ virtual void - draw(Graphics *graphics, Sint32 offsetX, Sint32 offsetY); + draw(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) const; /** * Returns the pixel X coordinate. @@ -343,7 +346,6 @@ class Being : public Sprite getYOffset() const { return getOffset(mStepY); } std::auto_ptr mEquipment; - int mVisibleEquipment[6]; /**< Visible equipments */ protected: /** @@ -363,6 +365,7 @@ class Being : public Sprite Uint16 mWeapon; /**< Weapon picture id */ Uint16 mWalkSpeed; /**< Walking speed */ Uint16 mSpeedModifier; /**< Modifier to keep course on sync (1024 = normal speed) */ + Uint8 mDirection; /**< Facing direction */ Map *mMap; /**< Map on which this being resides */ SpriteIterator mSpriteIterator; @@ -376,11 +379,14 @@ class Being : public Sprite Sint32 mPx, mPy; /**< Pixel coordinates */ std::vector mSprites; + std::vector mEquipmentSpriteIDs; private: + int + getOffset(int step) const; + Sint16 mStepX, mStepY; Uint16 mStepTime; - int getOffset(int) const; }; #endif diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp index 923283b5..14b4ea7e 100644 --- a/src/beingmanager.cpp +++ b/src/beingmanager.cpp @@ -38,7 +38,7 @@ class FindBeingFunctor Uint16 other_y = y + ((being->getType() == Being::NPC) ? 1 : 0); return (being->mX / 32 == x && (being->mY / 32 == y || being->mY / 32 == other_y) && - being->mAction != Being::MONSTER_DEAD && + being->mAction != Being::DEAD && (type == Being::UNKNOWN || being->getType() == type)); } @@ -64,14 +64,7 @@ Being* BeingManager::createBeing(Uint16 id, Uint16 job) Being *being; if (job < 10) - { being = new Player(id, job, mMap); - // XXX Convert for new server - /* - MessageOut outMsg(0x0094); - outMsg.writeLong(id); - */ - } else if (job >= 100 & job < 200) being = new NPC(id, job, mMap); else if (job >= 1000 && job < 1200) @@ -79,6 +72,17 @@ Being* BeingManager::createBeing(Uint16 id, Uint16 job) else being = new Being(id, job, mMap); + // Player or NPC + if (job < 200) + { + // XXX Convert for new server + /* + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0094); + outMsg.writeInt32(id);//readLong(2)); + */ + } + mBeings.push_back(being); return being; @@ -127,7 +131,8 @@ void BeingManager::logic() being->logic(); - /*if (being->mAction == Being::MONSTER_DEAD && being->mFrame >= 20) + /* + if (being->mAction == Being::DEAD && being->mFrame >= 20) { delete being; i = mBeings.erase(i); @@ -168,7 +173,6 @@ Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist, if ((being->getType() == type || type == Being::UNKNOWN) && (d < dist || closestBeing == NULL) // it is closer && being->mAction != Being::DEAD // no dead beings - && being->mAction != Being::MONSTER_DEAD ) { dist = d; diff --git a/src/engine.cpp b/src/engine.cpp index 231313c4..30f0097e 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -39,9 +39,10 @@ #include "gui/gui.h" #include "gui/minimap.h" +#include "gui/viewport.h" -#include "resources/itemmanager.h" #include "resources/mapreader.h" +#include "resources/monsterdb.h" #include "resources/resourcemanager.h" #include "resources/spriteset.h" @@ -51,16 +52,12 @@ extern Minimap *minimap; char itemCurrenyQ[10] = "0"; -int camera_x, camera_y; - -ItemManager *itemDb; /**< Item database object */ Spriteset *emotionset; Spriteset *npcset; std::vector weaponset; Engine::Engine(): - mShowDebugPath(false), mCurrentMap(NULL) { // Load the sprite sets @@ -82,9 +79,6 @@ Engine::Engine(): if (!npcset) logger->error("Unable to load NPC spriteset!"); if (!emotionset) logger->error("Unable to load emotions spriteset!"); - - // Initialize item manager - itemDb = new ItemManager(); } Engine::~Engine() @@ -96,8 +90,6 @@ Engine::~Engine() std::for_each(weaponset.begin(), weaponset.end(), std::mem_fun(&Spriteset::decRef)); weaponset.clear(); - - delete itemDb; } void Engine::changeMap(const std::string &mapPath) @@ -125,6 +117,7 @@ void Engine::changeMap(const std::string &mapPath) } minimap->setMapImage(mapImage); beingManager->setMap(newMap); + viewport->setMap(newMap); // Start playing new music file when necessary std::string oldMusic = ""; @@ -152,139 +145,5 @@ void Engine::logic() void Engine::draw(Graphics *graphics) { - int midTileX = graphics->getWidth() / 2; - int midTileY = graphics->getHeight() / 2; - static int lastTick = tick_time; - - int player_x = player_node->mX - midTileX + player_node->getXOffset(); - int player_y = player_node->mY - midTileY + player_node->getYOffset(); - - scrollLaziness = (int)config.getValue("ScrollLaziness", 32); - scrollRadius = (int)config.getValue("ScrollRadius", 32); - - if (scrollLaziness < 1) - scrollLaziness = 1; //avoids division by zero - - //apply lazy scrolling - int nbTicks = get_elapsed_time(lastTick) / 10; - lastTick += nbTicks; - for (; nbTicks > 0; --nbTicks) - { - if (player_x > view_x + scrollRadius) - { - view_x += (player_x - view_x - scrollRadius) / scrollLaziness; - } - if (player_x < view_x - scrollRadius) - { - view_x += (player_x - view_x + scrollRadius) / scrollLaziness; - } - if (player_y > view_y + scrollRadius) - { - view_y += (player_y - view_y - scrollRadius) / scrollLaziness; - } - if (player_y < view_y - scrollRadius) - { - view_y += (player_y - view_y + scrollRadius) / scrollLaziness; - } - } - - //auto center when player is off screen - if ( player_x - view_x > graphics->getWidth() / 2 - || view_x - player_x > graphics->getWidth() / 2 - || view_y - player_y > graphics->getHeight() / 2 - || player_y - view_y > graphics->getHeight() / 2 - ) - { - view_x = player_x; - view_y = player_y; - }; - - if (mCurrentMap) { - if (view_x < 0) { - view_x = 0; - } - if (view_y < 0) { - view_y = 0; - } - if (view_x > mCurrentMap->getWidth() * 32 - midTileX) { - view_x = mCurrentMap->getWidth() * 32 - midTileX; - } - if (view_y > mCurrentMap->getHeight() * 32 - midTileY) { - view_y = mCurrentMap->getHeight() * 32 - midTileY; - } - } - - camera_x = (int)view_x; - camera_y = (int)view_y; - - // Draw tiles and sprites - if (mCurrentMap != NULL) - { - mCurrentMap->draw(graphics, camera_x, camera_y, 0); - mCurrentMap->draw(graphics, camera_x, camera_y, 1); - mCurrentMap->draw(graphics, camera_x, camera_y, 2); - mCurrentMap->drawOverlay( graphics, - view_x, - view_y, - (int)config.getValue("OverlayDetail", 2) - ); - } - else - { - // When no map is loaded, draw a replacement background - graphics->setColor(gcn::Color(128, 128, 128)); - graphics->fillRectangle(gcn::Rectangle(0, 0, - graphics->getWidth(), graphics->getHeight())); - } - - // Find a path from the player to the mouse, and draw it. This is for debug - // purposes. - if (mShowDebugPath && mCurrentMap != NULL) - { - // Get the current mouse position - int mouseX, mouseY; - SDL_GetMouseState(&mouseX, &mouseY); - - int mouseTileX = (mouseX + camera_x) / 32; - int mouseTileY = (mouseY + camera_y) / 32; - - Path debugPath = mCurrentMap->findPath( - player_node->mX / 32, player_node->mY / 32, - mouseTileX, mouseTileY); - - graphics->setColor(gcn::Color(255, 0, 0)); - for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++) - { - int squareX = i->x * 32 - camera_x + 12; - int squareY = i->y * 32 - camera_y + 12; - - graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8)); - graphics->drawText( - toString(mCurrentMap->getMetaTile(i->x, i->y)->Gcost), - squareX + 4, squareY + 12, gcn::Graphics::CENTER); - } - } - - // Draw player nickname, speech, and emotion sprite as needed - Beings &beings = beingManager->getAll(); - for (BeingIterator i = beings.begin(); i != beings.end(); i++) - { - (*i)->drawSpeech(graphics, -camera_x, -camera_y); - (*i)->drawName(graphics, -camera_x, -camera_y); - (*i)->drawEmotion(graphics, -camera_x, -camera_y); - } - - // Draw target marker if needed - Being *target; - if ((target = player_node->getTarget())) - { - graphics->setFont(speechFont); - graphics->setColor(gcn::Color(255, 255, 255)); - int dy = (target->getType() == Being::PLAYER) ? 90 : 52; - - graphics->drawText("[TARGET]", target->getPixelX() - camera_x + 15, - target->getPixelY() - camera_y - dy, gcn::Graphics::CENTER); - } - gui->draw(); } diff --git a/src/engine.h b/src/engine.h index e8ef7e33..62e82a49 100644 --- a/src/engine.h +++ b/src/engine.h @@ -26,8 +26,6 @@ #include -extern int camera_x, camera_y; - class Graphics; class Map; @@ -67,20 +65,8 @@ class Engine */ void draw(Graphics *graphics); - /** - * Toggles whether the path debug graphics are shown - */ - void toggleDebugPath() { mShowDebugPath = !mShowDebugPath; }; - private: - bool mShowDebugPath; - Map *mCurrentMap; - - int scrollRadius; - int scrollLaziness; - float view_x; // current viewpoint in pixels - float view_y; // current viewpoint in pixels }; extern Engine *engine; diff --git a/src/floor_item.cpp b/src/floor_item.cpp index 9a179a21..f33f7eb4 100644 --- a/src/floor_item.cpp +++ b/src/floor_item.cpp @@ -25,7 +25,7 @@ #include "map.h" -#include "resources/itemmanager.h" +#include "resources/itemdb.h" #include "resources/iteminfo.h" #include "resources/spriteset.h" @@ -42,7 +42,7 @@ FloorItem::FloorItem(unsigned int id, mMap(map) { // Retrieve item image from item info - mImage = itemDb->getItemInfo(itemId).getImage(); + mImage = ItemDB::get(itemId).getImage(); // Add ourselves to the map mSpriteIterator = mMap->addSprite(this); diff --git a/src/floor_item.h b/src/floor_item.h index 386d0759..36f81585 100644 --- a/src/floor_item.h +++ b/src/floor_item.h @@ -53,25 +53,25 @@ class FloorItem : public Sprite * Returns instance id of this item. */ unsigned int - getId() { return mId; } + getId() const { return mId; } /** * Returns the item id. */ unsigned int - getItemId() { return mItemId; } + getItemId() const { return mItemId; } /** * Returns the x coordinate. */ unsigned short - getX() { return mX; } + getX() const { return mX; } /** * Returns the y coordinate. */ unsigned short - getY() { return mY; } + getY() const { return mY; } /** * Returns the pixel y coordinate. @@ -87,7 +87,7 @@ class FloorItem : public Sprite * @see Sprite::draw(Graphics, int, int) */ void - draw(Graphics *graphics, int offsetX, int offsetY) + draw(Graphics *graphics, int offsetX, int offsetY) const { graphics->drawImage(mImage, mX * 32 + offsetX, diff --git a/src/game.cpp b/src/game.cpp index 5052f2ce..15298ec6 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -29,6 +29,7 @@ #include #include +#include #include "beingmanager.h" #include "configuration.h" @@ -42,23 +43,25 @@ #include "gui/buy.h" #include "gui/buysell.h" -#include "gui/chargedialog.h" +//#include "gui/chargedialog.h" #include "gui/chat.h" #include "gui/confirm_dialog.h" +#include "gui/debugwindow.h" #include "gui/equipmentwindow.h" +#include "gui/gui.h" #include "gui/help.h" #include "gui/inventorywindow.h" +#include "gui/menuwindow.h" #include "gui/minimap.h" +#include "gui/ministatus.h" #include "gui/npclistdialog.h" #include "gui/npc_text.h" #include "gui/sell.h" #include "gui/setup.h" #include "gui/skill.h" -#include "gui/menuwindow.h" #include "gui/status.h" -#include "gui/ministatus.h" #include "gui/trade.h" -#include "gui/debugwindow.h" +#include "gui/viewport.h" #include "net/beinghandler.h" #include "net/buysellhandler.h" @@ -85,7 +88,7 @@ bool done = false; volatile int tick_time; volatile int fps = 0, frame = 0; Engine *engine = NULL; -Joystick *joystick; +Joystick *joystick = NULL; extern Window *weightNotice; extern Window *deathNotice; @@ -106,7 +109,7 @@ SkillDialog *skillDialog; Setup* setupWindow; Minimap *minimap; EquipmentWindow *equipmentWindow; -ChargeDialog *chargeDialog; +//ChargeDialog *chargeDialog; TradeWindow *tradeWindow; //BuddyWindow *buddyWindow; HelpWindow *helpWindow; @@ -182,47 +185,23 @@ void createGuiWindows() setupWindow = new Setup(); minimap = new Minimap(); equipmentWindow = new EquipmentWindow(player_node->mEquipment.get()); - chargeDialog = new ChargeDialog(); + //chargeDialog = new ChargeDialog(); tradeWindow = new TradeWindow; //buddyWindow = new BuddyWindow(); helpWindow = new HelpWindow(); debugWindow = new DebugWindow(); // Initialize window positions - int screenW = graphics->getWidth(); - int screenH = graphics->getHeight(); - - chargeDialog->setPosition( - screenW - 5 - chargeDialog->getWidth(), - screenH - chargeDialog->getHeight() - 15); + //chargeDialog->setPosition( + // graphics->getWidth() - 5 - chargeDialog->getWidth(), + // graphics->getHeight() - chargeDialog->getHeight() - 15); - /*buddyWindow->setPosition(10, - minimap->getHeight() + 30);*/ + //buddyWindow->setPosition(10, minimap->getHeight() + 30); // Set initial window visibility -// chatWindow->setSticky(true); -// miniStatusWindow->setSticky(true); -// menuWindow->setSticky(true); - chatWindow->setVisible(true); miniStatusWindow->setVisible(true); - statusWindow->setVisible(false); menuWindow->setVisible(true); - buyDialog->setVisible(false); - sellDialog->setVisible(false); - buySellDialog->setVisible(false); - inventoryWindow->setVisible(false); - npcTextDialog->setVisible(false); - npcListDialog->setVisible(false); - skillDialog->setVisible(false); - //newSkillWindow->setVisible(false); - setupWindow->setVisible(false); - equipmentWindow->setVisible(false); - chargeDialog->setVisible(false); - tradeWindow->setVisible(false); - //buddyWindow->setVisible(false); - helpWindow->setVisible(false); - debugWindow->setVisible(false); } /** @@ -244,7 +223,7 @@ void destroyGuiWindows() delete setupWindow; delete minimap; delete equipmentWindow; - delete chargeDialog; + //delete chargeDialog; //delete newSkillWindow; delete tradeWindow; //delete buddyWindow; @@ -511,13 +490,13 @@ void Game::handleInput() // If none below the player, try the tile in front of // the player if (!item) { - if (player_node->mDirection & Being::UP) + if (player_node->getDirection() & Being::UP) y--; - if (player_node->mDirection & Being::DOWN) + if (player_node->getDirection() & Being::DOWN) y++; - if (player_node->mDirection & Being::LEFT) + if (player_node->getDirection() & Being::LEFT) x--; - if (player_node->mDirection & Being::RIGHT) + if (player_node->getDirection() & Being::RIGHT) x++; item = floorItemManager->findByCoordinates(x, y); @@ -584,7 +563,7 @@ void Game::handleInput() case SDLK_f: // Find path to mouse (debug purpose) - engine->toggleDebugPath(); + viewport->toggleDebugPath(); used = true; break; } @@ -621,8 +600,17 @@ void Game::handleInput() } // Push input to GUI when not used - if (!used) { - guiInput->pushInput(event); + if (!used) + { + try + { + guiInput->pushInput(event); + } + catch (gcn::Exception e) + { + const char* err = e.getMessage().c_str(); + logger->log("Warning: guichan input exception: %s", err); + } } } // End while @@ -633,35 +621,35 @@ void Game::handleInput() !chatWindow->isFocused()) { Uint16 x = player_node->mX / 32, y = player_node->mY / 32; - unsigned char Direction = 0; + unsigned char direction = 0; // Translate pressed keys to movement and direction if (keys[SDLK_UP] || keys[SDLK_KP8] || keys[SDLK_KP7] || keys[SDLK_KP9] || joystick && joystick->isUp()) { - Direction |= Being::UP; + direction |= Being::UP; } else if (keys[SDLK_DOWN] || keys[SDLK_KP2] || keys[SDLK_KP1] || keys[SDLK_KP3] || joystick && joystick->isDown()) { - Direction |= Being::DOWN; + direction |= Being::DOWN; } if (keys[SDLK_LEFT] || keys[SDLK_KP4] || keys[SDLK_KP1] || keys[SDLK_KP7] || joystick && joystick->isLeft()) { - Direction |= Being::LEFT; + direction |= Being::LEFT; } else if (keys[SDLK_RIGHT] || keys[SDLK_KP6] || keys[SDLK_KP3] || keys[SDLK_KP9] || joystick && joystick->isRight()) { - Direction |= Being::RIGHT; + direction |= Being::RIGHT; } - player_node->walk(Direction); + player_node->walk(direction); // Attacking monsters if (keys[SDLK_LCTRL] || keys[SDLK_RCTRL] || @@ -675,13 +663,13 @@ void Game::handleInput() { Uint16 targetX = x, targetY = y; - if (player_node->mDirection & Being::UP) + if (player_node->getDirection() & Being::UP) targetY--; - if (player_node->mDirection & Being::DOWN) + if (player_node->getDirection() & Being::DOWN) targetY++; - if (player_node->mDirection & Being::LEFT) + if (player_node->getDirection() & Being::LEFT) targetX--; - if (player_node->mDirection & Being::RIGHT) + if (player_node->getDirection() & Being::RIGHT) targetX++; // Attack priority is: Monster, Player, auto target diff --git a/src/graphics.cpp b/src/graphics.cpp index 065c0a46..f007470a 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -39,6 +39,9 @@ Graphics::~Graphics() bool Graphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel) { + logger->log("Setting video mode %dx%d %s", + w, h, fs ? "fullscreen" : "windowed"); + int displayFlags = SDL_ANYFORMAT; mFullscreen = fs; diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp index b681b683..9fcf752b 100644 --- a/src/gui/buy.cpp +++ b/src/gui/buy.cpp @@ -32,7 +32,7 @@ #include "../npc.h" -#include "../resources/itemmanager.h" +#include "../resources/itemdb.h" #include "../utils/tostring.h" @@ -266,7 +266,7 @@ void BuyDialog::selectionChanged(const SelectionEvent &event) if (selectedItem > -1) { const ItemInfo &info = - itemDb->getItemInfo(mShopItems->at(selectedItem).id); + ItemDB::get(mShopItems->at(selectedItem).id); mItemDescLabel->setCaption("Description: " + info.getDescription()); mItemEffectLabel->setCaption("Effect: " + info.getEffect()); diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp index d825db31..3cb42078 100644 --- a/src/gui/char_select.cpp +++ b/src/gui/char_select.cpp @@ -83,7 +83,7 @@ CharSelectDialog::CharSelectDialog(LockedArray *charInfo): mNameLabel = new gcn::Label("Name"); mLevelLabel = new gcn::Label("Level"); mMoneyLabel = new gcn::Label("Money"); - mPlayerBox = new PlayerBox(0); + mPlayerBox = new PlayerBox(); int w = 195; int h = 220; @@ -116,8 +116,9 @@ CharSelectDialog::CharSelectDialog(LockedArray *charInfo): add(mLevelLabel); add(mMoneyLabel); - mSelectButton->requestFocus(); setLocationRelativeTo(getParent()); + setVisible(true); + mSelectButton->requestFocus(); updatePlayerInfo(); } @@ -171,7 +172,8 @@ void CharSelectDialog::updatePlayerInfo() { LocalPlayer *pi = mCharInfo->getEntry(); - if (pi) { + if (pi) + { mNameLabel->setCaption(pi->getName()); mLevelLabel->setCaption("Lvl: " + toString(pi->mLevel)); mMoneyLabel->setCaption("Money: " + toString(pi->mMoney)); @@ -181,22 +183,17 @@ void CharSelectDialog::updatePlayerInfo() mDelCharButton->setEnabled(true); mSelectButton->setEnabled(true); } - mPlayerBox->mHairStyle = pi->getHairStyle(); - mPlayerBox->mHairColor = pi->getHairColor(); - mPlayerBox->mSex = pi->getSex(); - mPlayerBox->mShowPlayer = true; - } else { + } + else { mNameLabel->setCaption("Name"); mLevelLabel->setCaption("Level"); mMoneyLabel->setCaption("Money"); mNewCharButton->setEnabled(true); mDelCharButton->setEnabled(false); mSelectButton->setEnabled(false); - - mPlayerBox->mHairStyle = 0; - mPlayerBox->mHairColor = 0; - mPlayerBox->mShowPlayer = false; } + + mPlayerBox->setPlayer(pi); } void CharSelectDialog::attemptCharDelete() @@ -240,6 +237,10 @@ std::string CharSelectDialog::getName() CharCreateDialog::CharCreateDialog(Window *parent, int slot): Window("Create Character", true, parent), mSlot(slot) { + mPlayer = new Player(0, 0, NULL); + mPlayer->setHairStyle(rand() % NR_HAIR_STYLES + 1); + mPlayer->setHairColor(rand() % NR_HAIR_COLORS + 1); + mNameField = new TextField(""); mNameLabel = new gcn::Label("Name:"); mNextHairColorButton = new Button(">", "nextcolor", this); @@ -250,8 +251,7 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot): mHairStyleLabel = new gcn::Label("Hair Style:"); mCreateButton = new Button("Create", "create", this); mCancelButton = new Button("Cancel", "cancel", this); - mPlayerBox = new PlayerBox(0); - mPlayerBox->mShowPlayer = true; + mPlayerBox = new PlayerBox(mPlayer); mNameField->setEventId("create"); @@ -290,6 +290,12 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot): add(mCancelButton); setLocationRelativeTo(getParent()); + setVisible(true); +} + +CharCreateDialog::~CharCreateDialog() +{ + delete mPlayer; } void CharCreateDialog::action(const std::string &eventId, gcn::Widget *widget) @@ -299,7 +305,9 @@ void CharCreateDialog::action(const std::string &eventId, gcn::Widget *widget) // Attempt to create the character mCreateButton->setEnabled(false); Net::AccountServer::Account::createCharacter( - getName(), mPlayerBox->mHairStyle, mPlayerBox->mHairColor, + getName(), + mPlayer->getHairStyle(), + mPlayer->getHairColor(), 0, // gender 10, // STR 10, // AGI @@ -318,20 +326,19 @@ void CharCreateDialog::action(const std::string &eventId, gcn::Widget *widget) scheduleDelete(); } else if (eventId == "nextcolor") { - mPlayerBox->mHairColor++; + mPlayer->setHairColor(mPlayer->getHairColor() % NR_HAIR_COLORS + 1); } else if (eventId == "prevcolor") { - mPlayerBox->mHairColor += NR_HAIR_COLORS - 1; + int prevColor = mPlayer->getHairColor() + NR_HAIR_COLORS - 2; + mPlayer->setHairColor(prevColor % NR_HAIR_COLORS + 1); } else if (eventId == "nextstyle") { - mPlayerBox->mHairStyle++; + mPlayer->setHairStyle(mPlayer->getHairStyle() % NR_HAIR_STYLES + 1); } else if (eventId == "prevstyle") { - mPlayerBox->mHairStyle += NR_HAIR_STYLES - 1; + int prevStyle = mPlayer->getHairStyle() + NR_HAIR_STYLES - 2; + mPlayer->setHairStyle(prevStyle % NR_HAIR_STYLES + 1); } - - mPlayerBox->mHairColor %= NR_HAIR_COLORS; - mPlayerBox->mHairStyle %= NR_HAIR_STYLES; } std::string CharCreateDialog::getName() diff --git a/src/gui/char_select.h b/src/gui/char_select.h index 6d9d1a83..9d2d77da 100644 --- a/src/gui/char_select.h +++ b/src/gui/char_select.h @@ -31,6 +31,7 @@ #include +class Player; class LocalPlayer; class PlayerBox; @@ -48,7 +49,7 @@ class CharSelectDialog : public Window, public gcn::ActionListener */ CharSelectDialog(LockedArray *charInfo); - void action(const std::string& eventId, gcn::Widget* widget); + void action(const std::string &eventId, gcn::Widget *widget); void updatePlayerInfo(); @@ -103,7 +104,12 @@ class CharCreateDialog : public Window, public gcn::ActionListener */ CharCreateDialog(Window *parent, int slot); - void action(const std::string& eventId, gcn::Widget* widget); + /** + * Destructor. + */ + ~CharCreateDialog(); + + void action(const std::string &eventId, gcn::Widget *widget); std::string getName(); @@ -119,6 +125,7 @@ class CharCreateDialog : public Window, public gcn::ActionListener gcn::Button *mCreateButton; gcn::Button *mCancelButton; + Player *mPlayer; PlayerBox *mPlayerBox; int mSlot; diff --git a/src/gui/confirm_dialog.cpp b/src/gui/confirm_dialog.cpp index ed2f8680..5a70544f 100644 --- a/src/gui/confirm_dialog.cpp +++ b/src/gui/confirm_dialog.cpp @@ -61,6 +61,7 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg, setLocationRelativeTo(getParent()); getParent()->moveToTop(this); } + setVisible(true); yesButton->requestFocus(); } diff --git a/src/gui/confirm_dialog.h b/src/gui/confirm_dialog.h index 1c206b03..771ecc36 100644 --- a/src/gui/confirm_dialog.h +++ b/src/gui/confirm_dialog.h @@ -47,7 +47,7 @@ class ConfirmDialog : public Window, public gcn::ActionListener { /** * Called when receiving actions from the widgets. */ - void action(const std::string& eventId, gcn::Widget* widget); + void action(const std::string &eventId, gcn::Widget *widget); }; #endif diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp index d467d4d3..f8a4154e 100644 --- a/src/gui/debugwindow.cpp +++ b/src/gui/debugwindow.cpp @@ -72,15 +72,15 @@ DebugWindow::logic() // Get the current mouse position int mouseX, mouseY; SDL_GetMouseState(&mouseX, &mouseY); - int mouseTileX = mouseX / 32 + camera_x; - int mouseTileY = mouseY / 32 + camera_y; + //int mouseTileX = mouseX / 32 + camera_x; + //int mouseTileY = mouseY / 32 + camera_y; mFPSLabel->setCaption("[" + toString(fps) + " FPS"); mFPSLabel->adjustSize(); - mTileMouseLabel->setCaption("[Mouse: " + - toString(mouseTileX) + ", " + toString(mouseTileY) + "]"); - mTileMouseLabel->adjustSize(); + //mTileMouseLabel->setCaption("[Mouse: " + + // toString(mouseTileX) + ", " + toString(mouseTileY) + "]"); + //mTileMouseLabel->adjustSize(); Map *currentMap = engine->getCurrentMap(); if (currentMap != NULL) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 38b17781..fb7144a1 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -35,22 +35,14 @@ #endif #include "focushandler.h" -#include "popupmenu.h" #include "window.h" #include "windowcontainer.h" +#include "viewport.h" -#include "../being.h" -#include "../beingmanager.h" #include "../configlistener.h" #include "../configuration.h" -#include "../engine.h" -#include "../flooritemmanager.h" #include "../graphics.h" -#include "../localplayer.h" #include "../log.h" -#include "../main.h" -#include "../map.h" -#include "../npc.h" #include "../resources/image.h" #include "../resources/resourcemanager.h" @@ -61,7 +53,8 @@ // Guichan stuff Gui *gui; -gcn::SDLInput *guiInput; // GUI input +Viewport *viewport; /**< Viewport on the map. */ +gcn::SDLInput *guiInput; /**< GUI input. */ // Fonts used in showing hits gcn::Font *hitRedFont; @@ -91,9 +84,9 @@ class GuiConfigListener : public ConfigListener Gui::Gui(Graphics *graphics): mHostImageLoader(NULL), mMouseCursor(NULL), - mCustomCursor(false), - mPopupActive(false) + mCustomCursor(false) { + logger->log("Initializing GUI..."); // Set graphics setGraphics(graphics); @@ -122,7 +115,6 @@ Gui::Gui(Graphics *graphics): guiTop->setDimension(gcn::Rectangle(0, 0, graphics->getWidth(), graphics->getHeight())); guiTop->setOpaque(false); - guiTop->addMouseListener(this); Window::setWindowContainer(guiTop); setTop(guiTop); @@ -172,13 +164,15 @@ Gui::Gui(Graphics *graphics): mConfigListener = new GuiConfigListener(this); config.addListener("customcursor", mConfigListener); - mPopup = new PopupMenu(); + // Create the viewport + viewport = new Viewport(); + viewport->setDimension(gcn::Rectangle(0, 0, + graphics->getWidth(), graphics->getHeight())); + guiTop->add(viewport); } Gui::~Gui() { - delete mPopup; - config.removeListener("customcursor", mConfigListener); delete mConfigListener; @@ -193,6 +187,7 @@ Gui::~Gui() delete mGuiFont; delete speechFont; + delete viewport; delete mTop; delete mImageLoader; delete mHostImageLoader; @@ -230,113 +225,6 @@ Gui::draw() mGraphics->popClipArea(); } -void -Gui::mousePress(int mx, int my, int button) -{ - // Mouse pressed on window container (basically, the map) - - // Are we in-game yet? - if (state != STATE_GAME) - return; - - // Check if we are alive and kickin' - if (!player_node || player_node->mAction == Being::DEAD) - return; - - // Check if we are busy - if (current_npc) - return; - - int tilex = (mx + camera_x) / 32; - int tiley = (my + camera_y) / 32; - - // Right click might open a popup - if (button == gcn::MouseInput::RIGHT) - { - Being *being; - FloorItem *floorItem; - - if ((being = beingManager->findBeing(tilex, tiley)) && - being->getType() != Being::LOCALPLAYER) - { - showPopup(mx, my, being); - return; - } - else if((floorItem = floorItemManager->findByCoordinates(tilex, tiley))) - { - showPopup(mx, my, floorItem); - return; - } - } - - // If a popup is active, just remove it - if (mPopupActive) - { - mPopup->setVisible(false); - mPopupActive = false; - return; - } - - // Left click can cause different actions - if (button == gcn::MouseInput::LEFT) - { - Being *being; - FloorItem *item; - - // Interact with some being - if ((being = beingManager->findBeing(tilex, tiley))) - { - switch (being->getType()) - { - case Being::NPC: - dynamic_cast(being)->talk(); - break; - - case Being::MONSTER: - case Being::PLAYER: - if (being->mAction == Being::MONSTER_DEAD) - break; - - player_node->attack(being, true); - break; - - default: - break; - } - } - // Pick up some item - else if ((item = floorItemManager->findByCoordinates(tilex, tiley))) - { - player_node->pickUp(item); - } - // Just walk around - else if (engine->getCurrentMap() && - engine->getCurrentMap()->getWalk(tilex, tiley)) - { - // XXX XXX XXX REALLY UGLY! - Uint8 *keys = SDL_GetKeyState(NULL); - if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT])) - { - player_node->setDestination(mx + camera_x, my + camera_y); - player_node->stopAttack(); - } - } - } - - if (button == gcn::MouseInput::MIDDLE) - { - // Find the being nearest to the clicked position - Being *target = beingManager->findNearestLivingBeing( - tilex, tiley, - 20, Being::MONSTER); - - if (target) - { - player_node->setTarget(target); - } - } -} - void Gui::setUseCustomCursor(bool customCursor) { @@ -369,21 +257,3 @@ Gui::setUseCustomCursor(bool customCursor) } } } - -void Gui::showPopup(int x, int y, Item *item) -{ - mPopup->showPopup(x, y, item); - mPopupActive = true; -} - -void Gui::showPopup(int x, int y, FloorItem *floorItem) -{ - mPopup->showPopup(x, y, floorItem); - mPopupActive = true; -} - -void Gui::showPopup(int x, int y, Being *being) -{ - mPopup->showPopup(x, y, being); - mPopupActive = true; -} diff --git a/src/gui/gui.h b/src/gui/gui.h index c4c47a88..caf27744 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -25,17 +25,13 @@ #define _TMW_GUI #include -#include #include "../guichanfwd.h" -class Being; -class FloorItem; class GuiConfigListener; class Graphics; class Image; -class Item; -class PopupMenu; +class Viewport; /** * \defgroup GUI Core GUI related classes (widgets) @@ -50,7 +46,7 @@ class PopupMenu; * * \ingroup GUI */ -class Gui : public gcn::Gui, public gcn::MouseListener +class Gui : public gcn::Gui { public: /** @@ -76,12 +72,6 @@ class Gui : public gcn::Gui, public gcn::MouseListener void draw(); - /** - * Handles mouse press on map. - */ - void - mousePress(int mx, int my, int button); - /** * Return game font */ @@ -94,37 +84,17 @@ class Gui : public gcn::Gui, public gcn::MouseListener void setUseCustomCursor(bool customCursor); - /** - * Shows a popup for an item - * TODO Find some way to get rid of Item here - */ - void showPopup(int x, int y, Item *item); - - /** - * Shows a popup for a floor item - * TODO Find some way to get rid of FloorItem here - */ - void showPopup(int x, int y, FloorItem *floorItem); - - /** - * Shows a popup for a being - * TODO Find some way to get rid of Being here - */ - void showPopup(int x, int y, Being *being); - private: GuiConfigListener *mConfigListener; gcn::ImageLoader *mHostImageLoader; /**< For loading images in GL */ gcn::ImageLoader *mImageLoader; /**< For loading images */ - gcn::Font *mGuiFont; /**< The global GUI font */ + gcn::Font *mGuiFont; /**< The global GUI font */ Image *mMouseCursor; /**< Mouse cursor image */ bool mCustomCursor; /**< Show custom cursor */ - - PopupMenu *mPopup; /**< Popup window */ - bool mPopupActive; }; extern Gui *gui; /**< The GUI system */ +extern Viewport *viewport; /**< The viewport */ extern gcn::SDLInput *guiInput; /**< GUI input */ /** diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index 452b7c16..7f9ba3b9 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -34,6 +34,7 @@ #include "item_amount.h" #include "itemcontainer.h" #include "scrollarea.h" +#include "viewport.h" #include "../item.h" #include "../localplayer.h" @@ -169,7 +170,7 @@ void InventoryWindow::mouseClick(int x, int y, int button, int count) */ int mx = x + getX(); int my = y + getY(); - gui->showPopup(mx, my, item); + viewport->showPopup(mx, my, item); } } diff --git a/src/gui/item_amount.cpp b/src/gui/item_amount.cpp index 30c899a8..5ebc0213 100644 --- a/src/gui/item_amount.cpp +++ b/src/gui/item_amount.cpp @@ -18,7 +18,7 @@ * along with The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id $ + * $Id$ */ #include "item_amount.h" @@ -87,6 +87,7 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item): setContentSize(200, 80); setLocationRelativeTo(getParentWindow()); + setVisible(true); } void ItemAmountWindow::resetAmount() diff --git a/src/gui/login.cpp b/src/gui/login.cpp index 1d9b6e1e..b8d4df2b 100644 --- a/src/gui/login.cpp +++ b/src/gui/login.cpp @@ -102,6 +102,7 @@ LoginDialog::LoginDialog(LoginData *loginData): add(mRegisterButton); setLocationRelativeTo(getParent()); + setVisible(true); if (mUserField->getText().empty()) { mUserField->requestFocus(); diff --git a/src/gui/ok_dialog.cpp b/src/gui/ok_dialog.cpp index 906fd61f..4f9623d7 100644 --- a/src/gui/ok_dialog.cpp +++ b/src/gui/ok_dialog.cpp @@ -51,6 +51,7 @@ OkDialog::OkDialog(const std::string &title, const std::string &msg, add(okButton); setLocationRelativeTo(getParent()); + setVisible(true); okButton->requestFocus(); } diff --git a/src/gui/ok_dialog.h b/src/gui/ok_dialog.h index 06f703cc..8ae08955 100644 --- a/src/gui/ok_dialog.h +++ b/src/gui/ok_dialog.h @@ -46,7 +46,7 @@ class OkDialog : public Window, public gcn::ActionListener { /** * Called when receiving actions from the widgets. */ - void action(const std::string& eventId, gcn::Widget* widget); + void action(const std::string &eventId, gcn::Widget *widget); }; #endif diff --git a/src/gui/passwordfield.h b/src/gui/passwordfield.h index 15ca85c9..cae1f92e 100644 --- a/src/gui/passwordfield.h +++ b/src/gui/passwordfield.h @@ -21,8 +21,8 @@ * $Id$ */ -#ifndef __PASSWORDFIELD_H__ -#define __PASSWORDFIELD_H__ +#ifndef _TMW_PASSWORDFIELD_H_ +#define _TMW_PASSWORDFIELD_H_ #include "textfield.h" diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp index 568c3350..5fbe79b7 100644 --- a/src/gui/playerbox.cpp +++ b/src/gui/playerbox.cpp @@ -23,7 +23,7 @@ #include "playerbox.h" -#include "../being.h" +#include "../player.h" #include "../graphics.h" #include "../resources/image.h" @@ -32,17 +32,11 @@ #include "../utils/dtor.h" -extern std::vector hairset; -extern Spriteset *playerset[2]; - int PlayerBox::instances = 0; ImageRect PlayerBox::background; -PlayerBox::PlayerBox(unsigned char sex): - mHairColor(0), - mHairStyle(0), - mSex(sex), - mShowPlayer(false) +PlayerBox::PlayerBox(const Player *player): + mPlayer(player) { setBorderSize(2); @@ -81,29 +75,18 @@ PlayerBox::~PlayerBox() } } -void PlayerBox::draw(gcn::Graphics *graphics) +void +PlayerBox::draw(gcn::Graphics *graphics) { - if (!mShowPlayer) { - return; - } - - // Draw character - dynamic_cast(graphics)->drawImage( - playerset[mSex]->get(0), 23, 12); - - // Draw his hair - if (mHairStyle > 0 && mHairColor < NR_HAIR_COLORS && - mHairStyle < NR_HAIR_STYLES) + if (mPlayer) { - int hf = 5 * mHairColor; - if (hf >= 0 && hf < (int)hairset[mHairStyle]->size()) { - dynamic_cast(graphics)->drawImage( - hairset[mHairStyle - 1]->get(hf), 35, 7); - } + // Draw character + mPlayer->draw(dynamic_cast(graphics), 40, 42); } } -void PlayerBox::drawBorder(gcn::Graphics *graphics) +void +PlayerBox::drawBorder(gcn::Graphics *graphics) { int w, h, bs; bs = getBorderSize(); diff --git a/src/gui/playerbox.h b/src/gui/playerbox.h index ec04eaf6..6bba1b51 100644 --- a/src/gui/playerbox.h +++ b/src/gui/playerbox.h @@ -27,10 +27,10 @@ #include class ImageRect; +class Player; /** - * A box showing a player. Draws the various hair styles a player can have - * currently. + * A box showing a player character. * * \ingroup GUI */ @@ -38,15 +38,24 @@ class PlayerBox : public gcn::ScrollArea { public: /** - * Constructor. + * Constructor. Takes the initial player character that this box should + * display, which defaults to NULL. */ - PlayerBox(unsigned char sex); + PlayerBox(const Player *player = NULL); /** * Destructor. */ ~PlayerBox(); + /** + * Sets a new player character to be displayed by this box. Setting the + * player to NULL causes the box not to draw any + * character. + */ + void + setPlayer(const Player *player) { mPlayer = player; } + /** * Draws the scroll area. */ @@ -57,12 +66,9 @@ class PlayerBox : public gcn::ScrollArea */ void drawBorder(gcn::Graphics *graphics); - unsigned char mHairColor; /**< The hair color index */ - unsigned char mHairStyle; /**< The hair style index */ - unsigned char mSex; /**< Sex */ - bool mShowPlayer; /**< Wether to show the player or not */ - private: + const Player *mPlayer; /**< The character used for display */ + static int instances; static ImageRect background; }; diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index ab81f7d0..c2959e1d 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -40,7 +40,7 @@ #include "../npc.h" #include "../resources/iteminfo.h" -#include "../resources/itemmanager.h" +#include "../resources/itemdb.h" extern std::string tradePartnerName; @@ -106,7 +106,7 @@ void PopupMenu::showPopup(int x, int y, FloorItem *floorItem) mBrowserBox->clearRows(); // Floor item can be picked up (single option, candidate for removal) - std::string name = itemDb->getItemInfo(mFloorItem->getItemId()).getName(); + std::string name = ItemDB::get(mFloorItem->getItemId()).getName(); mBrowserBox->addRow("@@pickup|Pick Up " + name + "@@"); //browserBox->addRow("@@look|Look To@@"); diff --git a/src/gui/register.cpp b/src/gui/register.cpp index 7cef62a2..70cd6dc4 100644 --- a/src/gui/register.cpp +++ b/src/gui/register.cpp @@ -97,6 +97,7 @@ RegisterDialog::RegisterDialog(LoginData *loginData): add(mCancelButton); setLocationRelativeTo(getParent()); + setVisible(true); mUserField->requestFocus(); mUserField->setCaretPosition(mUserField->getText().length()); } diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index fd63633c..499bbd05 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -37,7 +37,7 @@ #include "../npc.h" #include "../resources/iteminfo.h" -#include "../resources/itemmanager.h" +#include "../resources/itemdb.h" #include "../utils/tostring.h" @@ -232,6 +232,7 @@ void SellDialog::action(const std::string &eventId, gcn::Widget *widget) mMaxItems -= mAmountItems; mShopItems->getShop()->at(selectedItem).quantity = mMaxItems; + mPlayerMoney += (mAmountItems * mShopItems->at(selectedItem).price); mAmountItems = 0; mSlider->setValue(0); mSlider->setEnabled(mMaxItems != 0); @@ -274,7 +275,7 @@ void SellDialog::selectionChanged(const SelectionEvent &event) if (selectedItem > -1) { const ItemInfo &info = - itemDb->getItemInfo(mShopItems->at(selectedItem).id); + ItemDB::get(mShopItems->at(selectedItem).id); mItemDescLabel->setCaption("Description: " + info.getDescription()); mItemEffectLabel->setCaption("Effect: " + info.getEffect()); diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp index 39abd5ed..bd17bff7 100644 --- a/src/gui/serverdialog.cpp +++ b/src/gui/serverdialog.cpp @@ -174,6 +174,7 @@ ServerDialog::ServerDialog(LoginData *loginData): add(mCancelButton); setLocationRelativeTo(getParent()); + setVisible(true); if (mServerNameField->getText().empty()) { mServerNameField->requestFocus(); diff --git a/src/gui/serverdialog.h b/src/gui/serverdialog.h index 5b265c17..d907f340 100644 --- a/src/gui/serverdialog.h +++ b/src/gui/serverdialog.h @@ -132,7 +132,7 @@ class ServerDialog : public Window, public gcn::ActionListener /** * Called when receiving actions from the widgets. */ - void action(const std::string& eventId, gcn::Widget* widget); + void action(const std::string &eventId, gcn::Widget *widget); private: gcn::TextField *mServerNameField; diff --git a/src/gui/setup_joystick.cpp b/src/gui/setup_joystick.cpp index d9212728..685d88cf 100644 --- a/src/gui/setup_joystick.cpp +++ b/src/gui/setup_joystick.cpp @@ -42,7 +42,7 @@ Setup_Joystick::Setup_Joystick(): mCalibrateLabel->setPosition(10, 25); mCalibrateButton->setPosition(10, 30 + mCalibrateLabel->getHeight()); - mOriginalJoystickEnabled = (joystick ? joystick->isEnabled() : false); + mOriginalJoystickEnabled = (int)config.getValue("joystickEnabled", 0) != 0; mJoystickEnabled->setMarked(mOriginalJoystickEnabled); mJoystickEnabled->setEventId("joystickEnabled"); diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp index 3f30732a..2d33e8a8 100644 --- a/src/gui/shop.cpp +++ b/src/gui/shop.cpp @@ -23,7 +23,7 @@ #include "shop.h" #include "../utils/tostring.h" -#include "../resources/itemmanager.h" +#include "../resources/itemdb.h" ShopItems::~ShopItems() { @@ -44,11 +44,11 @@ void ShopItems::addItem(short id, int price) { ITEM_SHOP item_shop; - item_shop.name = itemDb->getItemInfo(id).getName() + item_shop.name = ItemDB::get(id).getName() + " " + toString(price) + " GP"; item_shop.price = price; item_shop.id = id; - item_shop.image = itemDb->getItemInfo(id).getImage(); + item_shop.image = ItemDB::get(id).getImage(); mItemsShop.push_back(item_shop); } diff --git a/src/gui/textfield.h b/src/gui/textfield.h index 1ed802d7..4748830c 100644 --- a/src/gui/textfield.h +++ b/src/gui/textfield.h @@ -28,7 +28,6 @@ class ImageRect; - /** * A text field. * diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp index 2ac56ae5..82262563 100644 --- a/src/gui/trade.cpp +++ b/src/gui/trade.cpp @@ -48,7 +48,7 @@ TradeWindow::TradeWindow(): mPartnerInventory(new Inventory()) { setWindowName("Trade"); - setDefaultSize(115, 197, 322, 150); + setDefaultSize(115, 197, 332, 209); mAddButton = new Button("Add", "add", this); mOkButton = new Button("Ok", "ok", this); @@ -95,33 +95,33 @@ TradeWindow::TradeWindow(): add(mMoneyField); add(mMoneyLabel); - mMoneyField->setPosition(8 + 60, getHeight() - 20); + gcn::Rectangle area = getChildrenArea(); + int width = area.width; + int height = area.height; + + mMoneyField->setPosition(8 + 60, height - 20); mMoneyField->setWidth(50); - mMoneyLabel->setPosition(8 + 60 + 50 + 6, getHeight() - 20); - mMoneyLabel2->setPosition(8, getHeight() - 20); + mMoneyLabel->setPosition(8 + 60 + 50 + 6, height - 20); + mMoneyLabel2->setPosition(8, height - 20); - mCancelButton->setPosition(getWidth() - 54, getHeight() - 49); - mTradeButton->setPosition(mCancelButton->getX() - 41 - , getHeight() - 49); - mOkButton->setPosition(mTradeButton->getX() - 24, - getHeight() - 49); - mAddButton->setPosition(mOkButton->getX() - 31, - getHeight() - 49); + mCancelButton->setPosition(width - 54, height - 49); + mTradeButton->setPosition(mCancelButton->getX() - 41, height - 49); + mOkButton->setPosition(mTradeButton->getX() - 24, height - 49); + mAddButton->setPosition(mOkButton->getX() - 31, height - 49); - mMyItemContainer->setSize(getWidth() - 24 - 12 - 1, - (INVENTORY_SIZE * 24) / (getWidth() / 24) - 1); - mMyScroll->setSize(getWidth() - 16, (getHeight() - 76) / 2); + mMyItemContainer->setSize(width - 24 - 12 - 1, + (INVENTORY_SIZE * 24) / (width / 24) - 1); + mMyScroll->setSize(width - 16, (height - 76) / 2); - mPartnerItemContainer->setSize(getWidth() - 24 - 12 - 1, - (INVENTORY_SIZE * 24) / (getWidth() / 24) - 1); - mPartnerScroll->setSize(getWidth() - 16, (getHeight() - 76) / 2); + mPartnerItemContainer->setSize(width - 24 - 12 - 1, + (INVENTORY_SIZE * 24) / (width / 24) - 1); + mPartnerScroll->setSize(width - 16, (height - 76) / 2); mItemNameLabel->setPosition(8, mPartnerScroll->getY() + mPartnerScroll->getHeight() + 4); mItemDescriptionLabel->setPosition(8, mItemNameLabel->getY() + mItemNameLabel->getHeight() + 4); - } TradeWindow::~TradeWindow() diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index c29906a1..73343483 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -192,7 +192,7 @@ int UpdaterWindow::updateProgress(void *ptr, if (progress > 1) progress = 1.0f; uw->setLabel( - uw->mCurrentFile + " (" + toString((int)progress * 100) + "%)"); + uw->mCurrentFile + " (" + toString((int) (progress * 100)) + "%)"); uw->setProgress(progress); if (state != STATE_UPDATE || uw->mDownloadStatus == UPDATE_ERROR) diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp new file mode 100644 index 00000000..d0525a2f --- /dev/null +++ b/src/gui/viewport.cpp @@ -0,0 +1,392 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "viewport.h" + +#include + +#include "gui.h" +#include "popupmenu.h" + +#include "../beingmanager.h" +#include "../configuration.h" +#include "../flooritemmanager.h" +#include "../graphics.h" +#include "../localplayer.h" +#include "../map.h" +#include "../npc.h" + +#include "../resources/monsterdb.h" + +#include "../utils/tostring.h" + +Viewport::Viewport(): + mMap(0), + mViewX(0.0f), + mViewY(0.0f), + mCameraX(0), + mCameraY(0), + mShowDebugPath(false), + mPopupActive(false) +{ + setOpaque(false); + addMouseListener(this); + + mScrollLaziness = (int) config.getValue("ScrollLaziness", 32); + mScrollRadius = (int) config.getValue("ScrollRadius", 32); + + config.addListener("ScrollLaziness", this); + config.addListener("ScrollRadius", this); + + mPopupMenu = new PopupMenu(); +} + +Viewport::~Viewport() +{ + delete mPopupMenu; +} + +void +Viewport::setMap(Map *map) +{ + mMap = map; +} + +void +Viewport::draw(gcn::Graphics *gcnGraphics) +{ + static int lastTick = tick_time; + + if (!mMap || !player_node) + return; + + Graphics *graphics = static_cast(gcnGraphics); + + // Avoid freaking out when tick_time overflows + if (tick_time < lastTick) + { + lastTick = tick_time; + } + + // Calculate viewpoint + int midTileX = graphics->getWidth() / 2; + int midTileY = graphics->getHeight() / 2; + + int player_x = player_node->mX - midTileX + player_node->getXOffset(); + int player_y = player_node->mY - midTileY + player_node->getYOffset(); + + if (mScrollLaziness < 1) + mScrollLaziness = 1; // Avoids division by zero + + // Apply lazy scrolling + while (lastTick < tick_time) + { + if (player_x > mViewX + mScrollRadius) + { + mViewX += (player_x - mViewX - mScrollRadius) / mScrollLaziness; + } + if (player_x < mViewX - mScrollRadius) + { + mViewX += (player_x - mViewX + mScrollRadius) / mScrollLaziness; + } + if (player_y > mViewY + mScrollRadius) + { + mViewY += (player_y - mViewY - mScrollRadius) / mScrollLaziness; + } + if (player_y < mViewY - mScrollRadius) + { + mViewY += (player_y - mViewY + mScrollRadius) / mScrollLaziness; + } + lastTick++; + } + + // Auto center when player is off screen + if ( player_x - mViewX > graphics->getWidth() / 2 + || mViewX - player_x > graphics->getWidth() / 2 + || mViewY - player_y > graphics->getHeight() / 2 + || player_y - mViewY > graphics->getHeight() / 2 + ) + { + mViewX = player_x; + mViewY = player_y; + }; + + if (mMap) { + if (mViewX < 0) { + mViewX = 0; + } + if (mViewY < 0) { + mViewY = 0; + } + if (mViewX > mMap->getWidth() * 32 - midTileX) { + mViewX = mMap->getWidth() * 32 - midTileX; + } + if (mViewY > mMap->getHeight() * 32 - midTileY) { + mViewY = mMap->getHeight() * 32 - midTileY; + } + } + + mCameraX = (int) mViewX; + mCameraY = (int) mViewY; + + // Draw tiles and sprites + if (mMap) + { + mMap->draw(graphics, mCameraX, mCameraY, 0); + mMap->draw(graphics, mCameraX, mCameraY, 1); + mMap->draw(graphics, mCameraX, mCameraY, 2); + mMap->drawOverlay(graphics, mViewX, mViewY, + (int) config.getValue("OverlayDetail", 2)); + } + + // Find a path from the player to the mouse, and draw it. This is for debug + // purposes. + if (mShowDebugPath && mMap) + { + // Get the current mouse position + int mouseX, mouseY; + SDL_GetMouseState(&mouseX, &mouseY); + + int mouseTileX = (mouseX + mCameraX) / 32; + int mouseTileY = (mouseY + mCameraY) / 32; + + Path debugPath = mMap->findPath( + player_node->mX / 32, player_node->mY / 32, + mouseTileX, mouseTileY); + + graphics->setColor(gcn::Color(255, 0, 0)); + for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++) + { + int squareX = i->x * 32 - mCameraX + 12; + int squareY = i->y * 32 - mCameraY + 12; + + graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8)); + graphics->drawText( + toString(mMap->getMetaTile(i->x, i->y)->Gcost), + squareX + 4, squareY + 12, gcn::Graphics::CENTER); + } + } + + // Draw player nickname, speech, and emotion sprite as needed + Beings &beings = beingManager->getAll(); + for (BeingIterator i = beings.begin(); i != beings.end(); i++) + { + (*i)->drawSpeech(graphics, -mCameraX, -mCameraY); + (*i)->drawName(graphics, -mCameraX, -mCameraY); + (*i)->drawEmotion(graphics, -mCameraX, -mCameraY); + } + + // Draw target marker if needed + Being *target; + if ((target = player_node->getTarget())) + { + graphics->setFont(speechFont); + graphics->setColor(gcn::Color(255, 32, 32)); + int dy = (target->getType() == Being::PLAYER) ? 80 : 42; + + std::string mobName = ""; + + if (target->mJob >= 1002) + { + int mobId = target->mJob - 1002; + mobName = MonsterDB::get(mobId).getName(); + + graphics->drawText(mobName, + target->getPixelX() - mCameraX + 15, + target->getPixelY() - mCameraY - dy, + gcn::Graphics::CENTER); + } + } + + // Draw contained widgets + WindowContainer::draw(gcnGraphics); +} + +void +Viewport::logic() +{ + WindowContainer::logic(); + + if (!mMap || !player_node) + return; + + int mouseX, mouseY; + Uint8 button = SDL_GetMouseState(&mouseX, &mouseY); + + if (mPlayerFollowMouse && button & SDL_BUTTON(1) && + mWalkTime != player_node->mWalkTime) + { + player_node->setDestination(mouseX + mCameraX, + mouseY + mCameraY); + mWalkTime = player_node->mWalkTime; + } +} + +void +Viewport::mousePress(int mx, int my, int button) +{ + // Check if we are alive and kickin' + if (!mMap || !player_node || player_node->mAction == Being::DEAD) + return; + + // Check if we are busy + if (current_npc) + return; + + mPlayerFollowMouse = false; + + int tilex = (mx + mCameraX) / 32; + int tiley = (my + mCameraY) / 32; + + // Right click might open a popup + if (button == gcn::MouseInput::RIGHT) + { + Being *being; + FloorItem *floorItem; + + if ((being = beingManager->findBeing(tilex, tiley)) && + being->getType() != Being::LOCALPLAYER) + { + showPopup(mx, my, being); + return; + } + else if((floorItem = floorItemManager->findByCoordinates(tilex, tiley))) + { + showPopup(mx, my, floorItem); + return; + } + } + + // If a popup is active, just remove it + if (mPopupActive) + { + mPopupMenu->setVisible(false); + mPopupActive = false; + return; + } + + // Left click can cause different actions + if (button == gcn::MouseInput::LEFT) + { + Being *being; + FloorItem *item; + + // Interact with some being + if ((being = beingManager->findBeing(tilex, tiley))) + { + switch (being->getType()) + { + case Being::NPC: + dynamic_cast(being)->talk(); + break; + + case Being::MONSTER: + case Being::PLAYER: + if (being->mAction == Being::DEAD) + break; + + player_node->attack(being, true); + break; + + default: + break; + } + } + // Pick up some item + else if ((item = floorItemManager->findByCoordinates(tilex, tiley))) + { + player_node->pickUp(item); + } + // Just walk around + else if (mMap->getWalk(tilex, tiley)) + { + // XXX XXX XXX REALLY UGLY! + Uint8 *keys = SDL_GetKeyState(NULL); + if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT])) + { + player_node->setDestination(mx + mCameraX, my + mCameraY); + player_node->stopAttack(); + } + mPlayerFollowMouse = true; + } + } + + if (button == gcn::MouseInput::MIDDLE) + { + // Find the being nearest to the clicked position + Being *target = beingManager->findNearestLivingBeing( + tilex, tiley, + 20, Being::MONSTER); + + if (target) + { + player_node->setTarget(target); + } + } +} + +void +Viewport::mouseMotion(int mx, int my) +{ + if (!mMap || !player_node) + return; + + if (mPlayerFollowMouse && mWalkTime == player_node->mWalkTime) + { + player_node->setDestination(mx + mCameraX, my + mCameraY); + } +} + +void +Viewport::mouseRelease(int mx, int my, int button) +{ + mPlayerFollowMouse = false; +} + +void +Viewport::showPopup(int x, int y, Item *item) +{ + mPopupMenu->showPopup(x, y, item); + mPopupActive = true; +} + +void +Viewport::showPopup(int x, int y, FloorItem *floorItem) +{ + mPopupMenu->showPopup(x, y, floorItem); + mPopupActive = true; +} + +void +Viewport::showPopup(int x, int y, Being *being) +{ + mPopupMenu->showPopup(x, y, being); + mPopupActive = true; +} + +void +Viewport::optionChanged(const std::string &name) +{ + mScrollLaziness = (int) config.getValue("ScrollLaziness", 32); + mScrollRadius = (int) config.getValue("ScrollRadius", 32); +} diff --git a/src/gui/viewport.h b/src/gui/viewport.h new file mode 100644 index 00000000..df78b1da --- /dev/null +++ b/src/gui/viewport.h @@ -0,0 +1,145 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_VIEWPORT_H_ +#define _TMW_VIEWPORT_H_ + +#include + +#include "windowcontainer.h" + +#include "../configlistener.h" + +class Map; +class Being; +class FloorItem; +class Item; +class PopupMenu; + +/** + * The viewport on the map. Displays the current map and handles mouse input + * and the popup menu. + * + * TODO: This class is planned to be extended to allow floating widgets on top + * of it such as NPC messages, which are positioned using map pixel + * coordinates. + */ +class Viewport : public WindowContainer, public gcn::MouseListener, + public ConfigListener +{ + public: + /** + * Constructor. + */ + Viewport(); + + /** + * Destructor. + */ + ~Viewport(); + + /** + * Sets the map displayed by the viewport. + */ + void + setMap(Map *map); + + /** + * Draws the viewport. + */ + void + draw(gcn::Graphics *graphics); + + /** + * Implements player to keep following mouse. + */ + void + logic(); + + /** + * Toggles whether the path debug graphics are shown + */ + void toggleDebugPath() { mShowDebugPath = !mShowDebugPath; } + + /** + * Handles mouse press on map. + */ + void + mousePress(int mx, int my, int button); + + /** + * Handles mouse move on map + */ + void + mouseMotion(int mx, int my); + + /** + * Handles mouse button release on map. + */ + void + mouseRelease(int mx, int my, int button); + + /** + * Shows a popup for an item. + * TODO Find some way to get rid of Item here + */ + void showPopup(int x, int y, Item *item); + + /** + * A relevant config option changed. + */ + void + optionChanged(const std::string &name); + + private: + /** + * Shows a popup for a floor item. + * TODO Find some way to get rid of FloorItem here + */ + void showPopup(int x, int y, FloorItem *floorItem); + + /** + * Shows a popup for a being. + * TODO Find some way to get rid of Being here + */ + void showPopup(int x, int y, Being *being); + + + Map *mMap; /**< The current map. */ + + int mScrollRadius; + int mScrollLaziness; + float mViewX; /**< Current viewpoint in pixels. */ + float mViewY; /**< Current viewpoint in pixels. */ + int mCameraX; + int mCameraY; + bool mShowDebugPath; /**< Show a path from player to pointer. */ + + bool mPlayerFollowMouse; + int mWalkTime; + + PopupMenu *mPopupMenu; /**< Popup menu. */ + bool mPopupActive; +}; + +#endif diff --git a/src/gui/window.cpp b/src/gui/window.cpp index 13d42c78..1960d6ca 100644 --- a/src/gui/window.cpp +++ b/src/gui/window.cpp @@ -113,6 +113,9 @@ Window::Window(const std::string& caption, bool modal, Window *parent): { requestModalFocus(); } + + // Windows are invisible by default + setVisible(false); } Window::~Window() diff --git a/src/gui/window.h b/src/gui/window.h index 51c876e3..158035c0 100644 --- a/src/gui/window.h +++ b/src/gui/window.h @@ -36,7 +36,8 @@ class WindowContainer; /** - * A window. This window can be dragged around and has a title bar. + * A window. This window can be dragged around and has a title bar. Windows are + * invisible by default. * * \ingroup GUI */ diff --git a/src/gui/windowcontainer.h b/src/gui/windowcontainer.h index b860fa3c..df255f84 100644 --- a/src/gui/windowcontainer.h +++ b/src/gui/windowcontainer.h @@ -27,7 +27,8 @@ #include /** - * A window container. This container makes draggable windows possible. + * A window container. This container adds functionality for more convenient + * widget (windows in particular) destruction. * * \ingroup GUI */ diff --git a/src/item.h b/src/item.h index 1375886e..47cdb1a9 100644 --- a/src/item.h +++ b/src/item.h @@ -24,7 +24,7 @@ #ifndef _ITEM_H_ #define _ITEM_H_ -#include "resources/itemmanager.h" +#include "resources/itemdb.h" /** * Represents one or more instances of a certain item type. @@ -119,7 +119,7 @@ class Item * Returns information about this item type. */ const ItemInfo& - getInfo() const { return itemDb->getItemInfo(mId); } + getInfo() const { return ItemDB::get(mId); } protected: int mId; /**< Item type id. */ diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 6898dfb7..c887dd1c 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -30,6 +30,7 @@ #include "item.h" #include "main.h" #include "sound.h" +#include "log.h" #include "net/gameserver/player.h" @@ -65,9 +66,19 @@ void LocalPlayer::logic() void LocalPlayer::nextStep() { - if (mPath.empty() && mPickUpTarget) { - pickUp(mPickUpTarget); + if (mPath.empty()) + { + if (mPickUpTarget) + { + pickUp(mPickUpTarget); + } + + if (mWalkingDir) + { + walk(mWalkingDir); + } } + Player::nextStep(); } @@ -161,10 +172,15 @@ void LocalPlayer::pickUp(FloorItem *item) void LocalPlayer::walk(unsigned char dir) { + if (mWalkingDir != dir) + { + mWalkingDir = dir; + } + if (!mMap || !dir) return; - if (mAction == WALK) + if (mAction == WALK && !mPath.empty()) { // Just finish the current action, otherwise we get out of sync Being::setDestination(mX, mY); @@ -198,10 +214,8 @@ void LocalPlayer::walk(unsigned char dir) } else if (dir) { - // Update the player direction to where he wants to walk - // Warning: Not communicated to the server yet - // If the being can't move, just change direction + // TODO: Communicate this to the server (waiting on tmwserv) setDirection(dir); } } @@ -216,10 +230,16 @@ void LocalPlayer::setDestination(Uint16 x, Uint16 y) x = tx * 32 + fx; y = ty * 32 + fy; - Net::GameServer::Player::walk(x, y); + // Only send a new message to the server when destination changes + if (x != mDestX || y != mDestY) + { + mDestX = x; + mDestY = y; - mPickUpTarget = NULL; + Net::GameServer::Player::walk(x, y); + } + mPickUpTarget = NULL; Being::setDestination(x, y); } diff --git a/src/localplayer.h b/src/localplayer.h index dbf2a147..f632b1b9 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -47,6 +47,11 @@ class LocalPlayer : public Player virtual ~LocalPlayer(); virtual void logic(); + + /** + * Adds a new step when walking before calling super. Also, when + * specified it picks up an item at the end of a path. + */ virtual void nextStep(); /** @@ -151,7 +156,10 @@ class LocalPlayer : public Player FloorItem *mPickUpTarget; bool mTrading; - int mLastAction; /**< Time stamp of the last action, -1 if none */ + int mLastAction; /**< Time stamp of the last action, -1 if none. */ + int mWalkingDir; /**< The direction the player is walking in. */ + int mDestX; /**< X coordinate of destination. */ + int mDestY; /**< Y coordinate of destination. */ }; extern LocalPlayer *player_node; diff --git a/src/log.cpp b/src/log.cpp index 07eb55f7..3a3c91b8 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -21,7 +21,9 @@ #include "log.h" #ifdef WIN32 -#include + #include "utils/wingettimeofday.h" +#else + #include #endif #ifdef __APPLE__ #include @@ -64,7 +66,6 @@ void Logger::log(const char *log_text, ...) char* buf = new char[1024]; va_list ap; - time_t t; // Use a temporary buffer to fill in the variables va_start(ap, log_text); @@ -72,19 +73,23 @@ void Logger::log(const char *log_text, ...) va_end(ap); // Get the current system time - time(&t); + timeval tv; + gettimeofday(&tv, NULL); // Print the log entry std::stringstream timeStr; timeStr << "[" - << ((((t / 60) / 60) % 24 < 10) ? "0" : "") - << (int)(((t / 60) / 60) % 24) + << ((((tv.tv_sec / 60) / 60) % 24 < 10) ? "0" : "") + << (int)(((tv.tv_sec / 60) / 60) % 24) << ":" - << (((t / 60) % 60 < 10) ? "0" : "") - << (int)((t / 60) % 60) + << (((tv.tv_sec / 60) % 60 < 10) ? "0" : "") + << (int)((tv.tv_sec / 60) % 60) << ":" - << ((t % 60 < 10) ? "0" : "") - << (int)(t % 60) + << ((tv.tv_sec % 60 < 10) ? "0" : "") + << (int)(tv.tv_sec % 60) + << "." + << (((tv.tv_usec / 10000) % 100) < 10 ? "0" : "") + << (int)((tv.tv_usec / 10000) % 100) << "] "; mLogFile << timeStr.str() << buf << std::endl; diff --git a/src/main.cpp b/src/main.cpp index 59bb1566..90368b7d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -76,7 +76,10 @@ #include "net/gameserver/gameserver.h" +#include "resources/equipmentdb.h" #include "resources/image.h" +#include "resources/itemdb.h" +#include "resources/monsterdb.h" #include "resources/resourcemanager.h" #include "resources/spriteset.h" @@ -87,8 +90,6 @@ char n_character; std::string token; -std::vector hairset; -Spriteset *playerset[2]; Graphics *graphics; unsigned char state; @@ -171,6 +172,7 @@ void initHomeDir() void initConfiguration(const Options &options) { // Fill configuration with defaults + logger->log("Initializing configuration..."); config.setValue("host", "animesites.de"); config.setValue("port", 9601); config.setValue("hwaccel", 0); @@ -219,6 +221,7 @@ void initConfiguration(const Options &options) void init_engine() { // Initialize SDL + logger->log("Initializing SDL..."); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { std::cerr << "Could not initialize SDL: " << SDL_GetError() << std::endl; @@ -288,26 +291,6 @@ void init_engine() // Initialize for drawing graphics->_beginDraw(); - playerset[0] = resman->getSpriteset( - "graphics/sprites/player_male_base.png", 64, 64); - if (!playerset[0]) logger->error("Couldn't load male player spriteset!"); - playerset[1] = resman->getSpriteset( - "graphics/sprites/player_female_base.png", 64, 64); - if (!playerset[1]) logger->error("Couldn't load female player spriteset!"); - - - for (int i = 0; i < NR_HAIR_STYLES - 1; i++) - { - Spriteset *tmp = ResourceManager::getInstance()->getSpriteset( - "graphics/sprites/hairstyle" + toString(i + 1) + ".png", - 40, 40); - if (!tmp) { - logger->error("Unable to load hairstyle"); - } else { - hairset.push_back(tmp); - } - } - gui = new Gui(graphics); state = STATE_CHOOSE_SERVER; /**< Initial game state */ @@ -316,8 +299,9 @@ void init_engine() if (config.getValue("sound", 0) == 1) { sound.init(); } - sound.setSfxVolume((int)config.getValue("sfxVolume", defaultSfxVolume)); - sound.setMusicVolume((int)config.getValue("musicVolume", + sound.setSfxVolume((int) config.getValue("sfxVolume", + defaultSfxVolume)); + sound.setMusicVolume((int) config.getValue("musicVolume", defaultMusicVolume)); } catch (const char *err) { @@ -325,6 +309,11 @@ void init_engine() errorMessage = err; logger->log("Warning: %s", err); } + + // Load XML databases + EquipmentDB::load(); + ItemDB::load(); + MonsterDB::load(); } /** Clear the engine */ @@ -334,19 +323,17 @@ void exit_engine() delete gui; delete graphics; - std::for_each(hairset.begin(), hairset.end(), - std::mem_fun(&Spriteset::decRef)); - hairset.clear(); - - playerset[0]->decRef(); - playerset[1]->decRef(); - // Shutdown libxml xmlCleanupParser(); // Shutdown sound sound.close(); + // Unload XML databases + EquipmentDB::unload(); + ItemDB::unload(); + MonsterDB::unload(); + ResourceManager::deleteInstance(); } @@ -599,7 +586,7 @@ int main(int argc, char *argv[]) gui->logic(); Net::flush(); - if (state > STATE_CONNECT_ACCOUNT && state < STATE_GAME) + if (state > STATE_CONNECT_ACCOUNT && state < STATE_GAME) { if (!accountServerConnection->isConnected()) { diff --git a/src/map.cpp b/src/map.cpp index 1cdc1077..1bd8f235 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -282,35 +282,35 @@ Map::setWalk(int x, int y, bool walkable) bool Map::getWalk(int x, int y) { - // Check for being walkable - if (tileCollides(x, y)) { - return false; - } + return !tileCollides(x, y) && !occupied(x, y); +} - /* - // Check for collision with a being +bool +Map::occupied(int x, int y) +{ Beings &beings = beingManager->getAll(); - for (BeingIterator i = beings.begin(); i != beings.end(); i++) { + for (BeingIterator i = beings.begin(); i != beings.end(); i++) + { // job 45 is a portal, they don't collide - if ((*i)->mX / 32 == x && (*i)->mY / 32 == y && (*i)->mJob != 45) { - return false; + if ((*i)->mX / 32 == x && (*i)->mY / 32 == y && (*i)->mJob != 45) + { + return true; } } - */ - return true; + return false; } bool Map::tileCollides(int x, int y) { - // You can't walk outside of the map - if (x < 0 || y < 0 || x >= mWidth || y >= mHeight) { - return true; - } + return !(contains(x, y) && mMetaTiles[x + y * mWidth].walkable); +} - // Check if the tile is walkable - return !mMetaTiles[x + y * mWidth].walkable; +bool +Map::contains(int x, int y) +{ + return x >= 0 && y >= 0 && x < mWidth && y < mHeight; } void @@ -355,8 +355,9 @@ Map::findPath(int startX, int startY, int destX, int destY) // Declare open list, a list with open tiles sorted on F cost std::priority_queue openList; - // Return empty path when destination not walkable - if (!getWalk(destX, destY)) return path; + // Return empty path when destination collides + if (tileCollides(destX, destY)) + return path; // Reset starting tile's G cost to 0 MetaTile *startTile = getMetaTile(startX, startY); @@ -395,16 +396,15 @@ Map::findPath(int startX, int startY, int destX, int destY) // Skip if if we're checking the same tile we're leaving from, // or if the new location falls outside of the map boundaries - if ((dx == 0 && dy == 0) || - (x < 0 || y < 0 || x >= mWidth || y >= mHeight)) + if ((dx == 0 && dy == 0) || !contains(x, y)) { continue; } MetaTile *newTile = getMetaTile(x, y); - // Skip if the tile is on the closed list or is not walkable - if (newTile->whichList == mOnClosedList || !getWalk(x, y)) + // Skip if the tile is on the closed list or collides + if (newTile->whichList == mOnClosedList || tileCollides(x, y)) { continue; } @@ -441,6 +441,13 @@ Map::findPath(int startX, int startY, int destX, int destY) ++Gcost; } + // It costs extra to walk through a being (needs to be enough + // to make it more attractive to walk around). + if (occupied(x, y)) + { + Gcost += 30; + } + // Skip if Gcost becomes too much // Warning: probably not entirely accurate if (Gcost > 20 * basicCost) diff --git a/src/map.h b/src/map.h index 961326b8..15b9b0dc 100644 --- a/src/map.h +++ b/src/map.h @@ -129,7 +129,7 @@ class Map : public Properties MetaTile *getMetaTile(int x, int y); /** - * Set walkability flag for a tile + * Set walkability flag for a tile. */ void setWalk(int x, int y, bool walkable); @@ -199,6 +199,16 @@ class Map : public Properties Tileset* getTilesetWithGid(int gid); + /** + * Tells whether a tile is occupied by a being. + */ + bool occupied(int x, int y); + + /** + * Tells whether the given coordinates fall within the map boundaries. + */ + bool contains(int x, int y); + int mWidth, mHeight; int mTileWidth, mTileHeight; MetaTile *mMetaTiles; diff --git a/src/monster.cpp b/src/monster.cpp index a4317e5e..f2e4d93d 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -25,6 +25,9 @@ #include "animatedsprite.h" #include "game.h" +#include "sound.h" + +#include "resources/monsterdb.h" #include "utils/tostring.h" @@ -32,7 +35,8 @@ Monster::Monster(Uint16 id, Uint16 job, Map *map): Being(id, job, map) { - mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/monster" + toString(job - 1002) + ".xml", 0); + mSprites[BASE_SPRITE] = new AnimatedSprite( + "graphics/sprites/" + MonsterDB::get(job - 1002).getSprite()); } Being::Type @@ -41,3 +45,36 @@ Monster::getType() const return MONSTER; } +void +Monster::setAction(Uint8 action) +{ + SpriteAction currentAction = ACTION_INVALID; + + switch (action) + { + case WALK: + currentAction = ACTION_WALK; + break; + case DEAD: + currentAction = ACTION_DEAD; + sound.playSfx(MonsterDB::get(mJob - 1002).getSound(EVENT_DIE)); + break; + case ATTACK: + currentAction = ACTION_ATTACK; + sound.playSfx(MonsterDB::get(mJob - 1002).getSound(EVENT_HIT)); + mSprites[BASE_SPRITE]->reset(); + break; + case STAND: + currentAction = ACTION_STAND; + break; + case HURT: + // Not implemented yet + break; + } + + if (currentAction != ACTION_INVALID) + { + mSprites[BASE_SPRITE]->play(currentAction); + mAction = action; + } +} diff --git a/src/monster.h b/src/monster.h index 0314a035..7f129e14 100644 --- a/src/monster.h +++ b/src/monster.h @@ -31,6 +31,8 @@ class Monster : public Being public: Monster(Uint16 id, Uint16 job, Map *map); + virtual void setAction(Uint8 action); + virtual Type getType() const; }; diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 2d68dd28..6d8ff6c6 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -66,6 +66,7 @@ void BeingHandler::handleMessage(MessageIn &msg) /* Uint32 id; Uint16 job, speed; + Uint16 headBottom, headTop, headMid; Sint16 param1; Sint8 type; Being *srcBeing, *dstBeing; @@ -124,7 +125,8 @@ void BeingHandler::handleMessage(MessageIn &msg) dstBeing->mJob = job; dstBeing->setHairStyle(msg.readShort()); dstBeing->setWeapon(msg.readShort()); - dstBeing->setVisibleEquipment(3, msg.readShort()); // head bottom + dstBeing->setVisibleEquipment( + Being::BOTTOMCLOTHES_SPRITE, msg.readShort()); if (msg.getId() == SMSG_BEING_MOVE) { @@ -132,8 +134,9 @@ void BeingHandler::handleMessage(MessageIn &msg) } msg.readShort(); // shield - dstBeing->setVisibleEquipment(4, msg.readShort()); // head top - dstBeing->setVisibleEquipment(5, msg.readShort()); // head mid + dstBeing->setVisibleEquipment(Being::HAIT_SPRITE, msg.readShort()); + dstBeing->setVisibleEquipment( + Being::TOPCLOTHES_SPRITE, msg.readShort()); dstBeing->setHairColor(msg.readShort()); msg.readShort(); // unknown msg.readShort(); // head dir @@ -156,7 +159,9 @@ void BeingHandler::handleMessage(MessageIn &msg) } else { - //msg.readCoordinates(dstBeing->mX, dstBeing->mY, dstBeing->mDirection); + //Uint8 dir; + //msg->readCoordinates(dstBeing->mX, dstBeing->mY, dir); + //dstBeing->setDirection(dir); } msg.readByte(); // unknown @@ -173,19 +178,7 @@ void BeingHandler::handleMessage(MessageIn &msg) if (msg.readByte() == 1) { - // Death - switch (dstBeing->getType()) - { - case Being::MONSTER: - dstBeing->setAction(Being::MONSTER_DEAD); - dstBeing->mFrame = 0; - dstBeing->mWalkTime = tick_time; - break; - - default: - dstBeing->setAction(Being::DEAD); - break; - } + dstBeing->setAction(Being::DEAD); } else { @@ -219,15 +212,7 @@ void BeingHandler::handleMessage(MessageIn &msg) if (srcBeing != NULL && srcBeing != player_node) { - // buggy - if (srcBeing->getType() == Being::MONSTER) - { - srcBeing->setAction(Being::MONSTER_ATTACK); - } - else - { - srcBeing->setAction(Being::ATTACK); - } + srcBeing->setAction(Being::ATTACK); srcBeing->mFrame = 0; srcBeing->mWalkTime = tick_time; } @@ -275,27 +260,35 @@ void BeingHandler::handleMessage(MessageIn &msg) } int type = msg.readByte(); + int id = msg.readByte(); switch (type) { case 1: - dstBeing->setHairStyle(msg.readByte()); + dstBeing->setHairStyle(id); break; case 2: - dstBeing->setWeapon(msg.readByte()); + dstBeing->setWeapon(id); + break; + case 3: // Change lower headgear for eAthena, pants for us + dstBeing->setVisibleEquipment( + Being::BOTTOMCLOTHES_SPRITE, + id); + break; + case 4: // Change upper headgear for eAthena, hat for us + dstBeing->setVisibleEquipment( + Being::HAT_SPRITE, + id); break; - case 3: - case 4: - case 5: - // Equip/unequip head 3. Bottom 4. Top 5. Middle - dstBeing->setVisibleEquipment(type, msg.readByte()); - // First 3 slots of mVisibleEquipments are reserved for - // later use, probably accessories. + case 5: // Change middle headgear for eathena, armor for us + dstBeing->setVisibleEquipment( + Being::TOPCLOTHES_SPRITE, + id); break; case 6: - dstBeing->setHairColor(msg.readByte()); + dstBeing->setHairColor(id); break; default: - printf("c3: %i\n", msg.readByte()); // unsupported + logger->log("c3: %i\n", id); // unsupported break; } } @@ -331,15 +324,15 @@ void BeingHandler::handleMessage(MessageIn &msg) dstBeing->setHairStyle(msg.readShort()); dstBeing->setWeaponById(msg.readShort()); // item id 1 msg.readShort(); // item id 2 - dstBeing->setVisibleEquipment(3, msg.readShort()); // head bottom + headBottom = msg.readShort(); if (msg.getId() == SMSG_PLAYER_MOVE) { msg.readLong(); // server tick } - dstBeing->setVisibleEquipment(4, msg.readShort()); // head top - dstBeing->setVisibleEquipment(5, msg.readShort()); // head mid + headTop = msg.readShort(); + headMid = msg.readShort(); dstBeing->setHairColor(msg.readShort()); msg.readShort(); // unknown msg.readShort(); // head dir @@ -348,6 +341,10 @@ void BeingHandler::handleMessage(MessageIn &msg) msg.readShort(); // manner msg.readByte(); // karma dstBeing->setSex(1 - msg.readByte()); // sex + dstBeing->setVisibleEquipment( + Being::BOTTOMCLOTHES_SPRITE, headBottom); + dstBeing->setVisibleEquipment(Being::HAT_SPRITE, headTop); + dstBeing->setVisibleEquipment(Being::TOPCLOTHES_SPRITE, headMid); if (msg.getId() == SMSG_PLAYER_MOVE) { @@ -359,7 +356,9 @@ void BeingHandler::handleMessage(MessageIn &msg) } else { - //msg.readCoordinates(dstBeing->mX, dstBeing->mY, dstBeing->mDirection); + //Uint8 dir; + //msg->readCoordinates(dstBeing->mX, dstBeing->mY, dir); + //dstBeing->setDirection(dir); } msg.readByte(); // unknown @@ -386,7 +385,7 @@ void BeingHandler::handleMessage(MessageIn &msg) case 0x0119: // Change in players look - printf("0x0119 %li %i %i %x %i\n", msg.readLong(), + logger->log("0x0119 %li %i %i %x %i\n", msg.readLong(), msg.readShort(), msg.readShort(), msg.readShort(), msg.readByte()); break; diff --git a/src/net/inventoryhandler.cpp b/src/net/inventoryhandler.cpp index 3f7e8709..f003d77a 100644 --- a/src/net/inventoryhandler.cpp +++ b/src/net/inventoryhandler.cpp @@ -92,7 +92,7 @@ void InventoryHandler::handleMessage(MessageIn &msg) if (msg.readByte()> 0) { chatWindow->chatLog("Unable to pick up item", BY_SERVER); } else { - const ItemInfo &itemInfo = itemDb->getItemInfo(itemId); + const ItemInfo &itemInfo = ItemDB::get(itemId); chatWindow->chatLog("You picked up a " + itemInfo.getName(), BY_SERVER); player_node->addInvItem(index, itemId, amount, equipType != 0); diff --git a/src/net/npchandler.cpp b/src/net/npchandler.cpp index 9c89e71f..02204a84 100644 --- a/src/net/npchandler.cpp +++ b/src/net/npchandler.cpp @@ -49,20 +49,22 @@ NPCHandler::NPCHandler() void NPCHandler::handleMessage(MessageIn &msg) { + int id; + switch (msg.getId()) { case SMSG_NPC_CHOICE: msg.readShort(); // length - current_npc = dynamic_cast( - beingManager->findBeing(msg.readLong())); + id = msg.readLong(); + current_npc = dynamic_cast(beingManager->findBeing(id)); npcListDialog->parseItems(msg.readString(msg.getLength() - 8)); npcListDialog->setVisible(true); break; case SMSG_NPC_MESSAGE: msg.readShort(); // length - current_npc = dynamic_cast( - beingManager->findBeing(msg.readLong())); + id = msg.readLong(); + current_npc = dynamic_cast(beingManager->findBeing(id)); npcTextDialog->addText(msg.readString(msg.getLength() - 8)); npcListDialog->setVisible(false); npcTextDialog->setVisible(true); diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp index 6eb80d59..37291c0a 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/playerhandler.cpp @@ -46,7 +46,8 @@ OkDialog *deathNotice = NULL; namespace { struct WeightListener : public gcn::ActionListener { - void action(const std::string &eventId, gcn::Widget *widget) { + void action(const std::string &eventId, gcn::Widget *widget) + { weightNotice = NULL; } } weightListener; @@ -57,8 +58,10 @@ namespace { */ // TODO Move somewhere else namespace { - struct DeathListener : public gcn::ActionListener { - void action(const std::string &eventId, gcn::Widget *widget) { + struct DeathListener : public gcn::ActionListener + { + void action(const std::string &eventId, gcn::Widget *widget) + { player_node->revive(); deathNotice = NULL; } @@ -114,10 +117,11 @@ void PlayerHandler::handleMessage(MessageIn &msg) player_node->mMaxWeight / 2) { weightNotice = new OkDialog("Message", - "You are carrying more then half your " - "weight. You are unable to regain " - "health."); - weightNotice->addActionListener(&weightListener); + "You are carrying more then half " + "your weight. You are unable to " + "regain health."); + weightNotice->addActionListener( + &weightListener); } player_node->mTotalWeight = value; break; diff --git a/src/net/skillhandler.cpp b/src/net/skillhandler.cpp index d9bea775..17dea606 100644 --- a/src/net/skillhandler.cpp +++ b/src/net/skillhandler.cpp @@ -26,6 +26,8 @@ #include "messagein.h" #include "protocol.h" +#include "../log.h" + #include "../gui/chat.h" #include "../gui/skill.h" @@ -85,7 +87,7 @@ void SkillHandler::handleMessage(MessageIn &msg) if (action.success != SKILL_FAILED && action.bskill == BSKILL_EMOTE) { - printf("Action: %d/%d", action.bskill, action.success); + logger->log("Action: %d/%d", action.bskill, action.success); } chatWindow->chatLog(action); break; diff --git a/src/npc.cpp b/src/npc.cpp index 3bd4371b..3c142889 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -24,6 +24,9 @@ #include "npc.h" #include "animatedsprite.h" +#include "graphics.h" + +#include "gui/gui.h" class Spriteset; extern Spriteset *npcset; @@ -33,7 +36,8 @@ NPC *current_npc = 0; NPC::NPC(Uint16 id, Uint16 job, Map *map): Being(id, job, map) { - mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/npc.xml", job-100); + mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/npc.xml", + job - 100); } Being::Type @@ -42,6 +46,17 @@ NPC::getType() const return Being::NPC; } +void +NPC::drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) +{ + int px = mPx + offsetX; + int py = mPy + offsetY; + + graphics->setFont(speechFont); + graphics->setColor(gcn::Color(200, 200, 255)); + graphics->drawText(mName, px + 15, py + 30, gcn::Graphics::CENTER); +} + void NPC::talk() { diff --git a/src/npc.h b/src/npc.h index 3b61123b..cf5defbc 100644 --- a/src/npc.h +++ b/src/npc.h @@ -26,12 +26,18 @@ #include "being.h" +class Graphics; + class NPC : public Being { public: NPC(Uint16 id, Uint16 job, Map *map); - virtual Type getType() const; + virtual Type + getType() const; + + virtual void + drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY); void talk(); void nextDialog(); diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp index 05bbb6b3..ec6c1ee3 100644 --- a/src/openglgraphics.cpp +++ b/src/openglgraphics.cpp @@ -52,6 +52,9 @@ OpenGLGraphics::~OpenGLGraphics() bool OpenGLGraphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel) { + logger->log("Setting video mode %dx%d %s", + w, h, fs ? "fullscreen" : "windowed"); + int displayFlags = SDL_ANYFORMAT | SDL_OPENGL; mFullscreen = fs; diff --git a/src/player.cpp b/src/player.cpp index 0acf8262..63ed5455 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -28,6 +28,8 @@ #include "graphics.h" #include "log.h" +#include "resources/equipmentdb.h" + #include "utils/tostring.h" #include "gui/gui.h" @@ -35,9 +37,6 @@ Player::Player(Uint16 id, Uint16 job, Map *map): Being(id, job, map) { - // Load the weapon sprite. - // When there are more different weapons this should be moved to the - // setWeapon Method. setWeapon(0); } @@ -70,52 +69,72 @@ Player::setSex(Uint8 sex) if (sex != mSex) { - delete mSprites[BASE_SPRITE]; + Being::setSex(sex); + + // Reload base sprite + AnimatedSprite *newBaseSprite; if (sex == 0) { - mSprites[BASE_SPRITE] = new AnimatedSprite( - "graphics/sprites/player_male_base.xml", 0); + newBaseSprite = new AnimatedSprite( + "graphics/sprites/player_male_base.xml"); } else { - mSprites[BASE_SPRITE] = new AnimatedSprite( - "graphics/sprites/player_female_base.xml", 0); + newBaseSprite = new AnimatedSprite( + "graphics/sprites/player_female_base.xml"); } - Being::setSex(sex); - resetAnimations(); + delete mSprites[BASE_SPRITE]; + mSprites[BASE_SPRITE] = newBaseSprite; + + // Reload equipment + for (int i = 1; i < VECTOREND_SPRITE; i++) + { + if (i != HAIR_SPRITE && mEquipmentSpriteIDs.at(i) != 0) + { + AnimatedSprite *newEqSprite = new AnimatedSprite( + "graphics/sprites/" + EquipmentDB::get( + mEquipmentSpriteIDs.at(i))->getSprite(sex)); + delete mSprites[i]; + mSprites[i] = newEqSprite; + } + } } } - void Player::setWeapon(Uint16 weapon) { if (weapon != mWeapon) { - delete mSprites[WEAPON_SPRITE]; - mSprites[WEAPON_SPRITE] = NULL; + AnimatedSprite *newWeaponSprite = NULL; switch (weapon) { case 0: - mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapon-fist.xml", 0); + newWeaponSprite = + new AnimatedSprite("graphics/sprites/weapon-fist.xml"); break; case 1: - mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapon-dagger.xml", 0); + newWeaponSprite = + new AnimatedSprite("graphics/sprites/weapon-dagger.xml"); break; case 2: - mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapon-bow.xml", 0); + newWeaponSprite = + new AnimatedSprite("graphics/sprites/weapon-bow.xml"); break; case 3: - mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapon-scythe.xml", 0); + newWeaponSprite = + new AnimatedSprite("graphics/sprites/weapon-scythe.xml"); break; } + + delete mSprites[WEAPON_SPRITE]; + mSprites[WEAPON_SPRITE] = newWeaponSprite; } Being::setWeapon(weapon); } - void Player::setHairColor(Uint16 color) { @@ -128,7 +147,6 @@ Player::setHairColor(Uint16 color) delete mSprites[HAIR_SPRITE]; mSprites[HAIR_SPRITE] = newHairSprite; - resetAnimations(); setAction(mAction); } @@ -148,7 +166,6 @@ Player::setHairStyle(Uint16 style) delete mSprites[HAIR_SPRITE]; mSprites[HAIR_SPRITE] = newHairSprite; - resetAnimations(); setAction(mAction); } @@ -157,55 +174,35 @@ Player::setHairStyle(Uint16 style) } void -Player::setVisibleEquipment(Uint8 slot, Uint8 id) +Player::setVisibleEquipment(Uint8 slot, int id) { - // Translate eAthena specific slot - Uint8 position = 0; - switch (slot) { - case 3: - position = BOTTOMCLOTHES_SPRITE; - break; - case 4: - position = HAT_SPRITE; - break; - case 5: - position = TOPCLOTHES_SPRITE; - break; - } - // id = 0 means unequip if (id == 0) { - delete mSprites[position]; - mSprites[position] = NULL; + delete mSprites[slot]; + mSprites[slot] = NULL; } else { - char stringId[4]; - sprintf(stringId, "%03i", id); + AnimatedSprite *equipmentSprite; + + if (mSex == 0) + { + equipmentSprite = new AnimatedSprite( + "graphics/sprites/" + EquipmentDB::get(id)->getSprite(0)); + } + else { + equipmentSprite = new AnimatedSprite( + "graphics/sprites/" + EquipmentDB::get(id)->getSprite(1)); + } - AnimatedSprite *equipmentSprite = new AnimatedSprite( - "graphics/sprites/item" + toString(stringId) + ".xml", 0); equipmentSprite->setDirection(getSpriteDirection()); - delete mSprites[position]; - mSprites[position] = equipmentSprite; - resetAnimations(); + delete mSprites[slot]; + mSprites[slot] = equipmentSprite; setAction(mAction); } Being::setVisibleEquipment(slot, id); } - -void -Player::resetAnimations() -{ - for (int i = 0; i < VECTOREND_SPRITE; i++) - { - if (mSprites[i] != NULL) - { - mSprites[i]->reset(); - } - } -} diff --git a/src/player.h b/src/player.h index 3c061be6..b062a55f 100644 --- a/src/player.h +++ b/src/player.h @@ -26,12 +26,14 @@ #include "being.h" -#include - class Graphics; class Map; -class AnimatedSprite; +/** + * A player being. Players have their name drawn beneath them. This class also + * implements player-specific loading of base sprite, hair sprite and equipment + * sprites. + */ class Player : public Being { public: @@ -56,18 +58,10 @@ class Player : public Being setHairStyle(Uint16 style); virtual void - setVisibleEquipment(Uint8 slot, Uint8 id); + setVisibleEquipment(Uint8 slot, int id); virtual void setWeapon(Uint16 weapon); - - private: - /** - * Resets all animations associated with this player. This is used to - * synchronize the animations after a new one has been added. - */ - void - resetAnimations(); }; #endif diff --git a/src/resources/equipmentdb.cpp b/src/resources/equipmentdb.cpp new file mode 100644 index 00000000..78ae3b6a --- /dev/null +++ b/src/resources/equipmentdb.cpp @@ -0,0 +1,158 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: + */ + +#include "equipmentdb.h" + +#include "resourcemanager.h" + +#include "../log.h" + +#include "../utils/dtor.h" +#include "../utils/xml.h" + +namespace +{ + EquipmentDB::EquipmentInfos mEquipmentInfos; + EquipmentInfo mUnknown; + bool mLoaded = false; +} + +void +EquipmentDB::load() +{ + logger->log("Initializing equipment database..."); + mUnknown.setSprite("error.xml", 0); + mUnknown.setSprite("error.xml", 1); + + ResourceManager *resman = ResourceManager::getInstance(); + int size; + char *data = (char*)resman->loadFile("equipment.xml", size); + + if (!data) + { + logger->error("Equipment Database: Could not find equipment.xml!"); + } + + xmlDocPtr doc = xmlParseMemory(data, size); + free(data); + + if (!doc) + { + logger->error("Equipment Database: Error while parsing equipment database (equipment.xml)!"); + } + + xmlNodePtr rootNode = xmlDocGetRootElement(doc); + if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "equipments")) + { + logger->error("Equipment Database: equipment.xml is not a valid database file!"); + } + + //iterate s + for ( xmlNodePtr equipmentNode = rootNode->xmlChildrenNode; + equipmentNode != NULL; + equipmentNode = equipmentNode->next) + { + + if (!xmlStrEqual(equipmentNode->name, BAD_CAST "equipment")) + { + continue; + } + + EquipmentInfo *currentInfo = new EquipmentInfo(); + + currentInfo->setSlot (XML::getProperty(equipmentNode, "slot", 0)); + + //iterate s + for ( xmlNodePtr spriteNode = equipmentNode->xmlChildrenNode; + spriteNode != NULL; + spriteNode = spriteNode->next) + { + if (!xmlStrEqual(spriteNode->name, BAD_CAST "sprite")) + { + continue; + } + + std::string gender = XML::getProperty(spriteNode, "gender", "unisex"); + std::string filename = (const char*) spriteNode->xmlChildrenNode->content; + + if (gender == "male" || gender == "unisex") + { + currentInfo->setSprite(filename, 0); + } + + if (gender == "female" || gender == "unisex") + { + currentInfo->setSprite(filename, 1); + } + } + + setEquipment( XML::getProperty(equipmentNode, "id", 0), + currentInfo); + } + + mLoaded = true; +} + +void +EquipmentDB::unload() +{ + // kill EquipmentInfos + for_each ( mEquipmentInfos.begin(), mEquipmentInfos.end(), + make_dtor(mEquipmentInfos)); + mEquipmentInfos.clear(); + + mLoaded = false; +} + +EquipmentInfo* +EquipmentDB::get(int id) +{ + if (!mLoaded) { + logger->error("Error: Equipment database used before initialization!"); + } + + EquipmentInfoIterator i = mEquipmentInfos.find(id); + + if (i == mEquipmentInfos.end() ) + { + logger->log("EquipmentDB: Error, unknown equipment ID# %d", id); + return &mUnknown; + } + else + { + return i->second; + } +} + +void +EquipmentDB::setEquipment(int id, EquipmentInfo* equipmentInfo) +{ + if (mEquipmentInfos.find(id) != mEquipmentInfos.end()) { + logger->log("Warning: Equipment Piece with ID %d defined multiple times", + id); + delete equipmentInfo; + } + else { + mEquipmentInfos[id] = equipmentInfo; + }; +} diff --git a/src/resources/equipmentdb.h b/src/resources/equipmentdb.h new file mode 100644 index 00000000..b8618f5f --- /dev/null +++ b/src/resources/equipmentdb.h @@ -0,0 +1,52 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: + */ + +#ifndef _TMW_EQUIPMENT_DB_H +#define _TMW_EQUIPMENT_DB_H + +#include + +#include "equipmentinfo.h" + +namespace EquipmentDB +{ + /** + * Loads the equipment info from Items.xml + */ + void load(); + + /** + * Frees equipment data + */ + void unload(); + + void setEquipment(int id, EquipmentInfo* equipmentInfo); + + EquipmentInfo* get(int id); + + // Equipment database types + typedef std::map EquipmentInfos; + typedef EquipmentInfos::iterator EquipmentInfoIterator; +} + +#endif diff --git a/src/resources/equipmentinfo.h b/src/resources/equipmentinfo.h new file mode 100644 index 00000000..93a1cb42 --- /dev/null +++ b/src/resources/equipmentinfo.h @@ -0,0 +1,52 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: + */ + +#ifndef _TMW_EQUIPMENTINFO_H_ +#define _TMW_EQUIPMENTINFO_H_ + +#include +#include + +class EquipmentInfo +{ + public: + EquipmentInfo(): + mSlot (0) + { + }; + + void + setSlot (int slot) { mSlot = slot; }; + + const std::string& + getSprite(int gender) {return animationFiles[gender]; }; + + void + setSprite(std::string animationFile, int gender) {animationFiles[gender] = animationFile; }; + + private: + int mSlot; //not used at the moment but maybe useful on our own server + std::map animationFiles; +}; + +#endif diff --git a/src/resources/image.cpp b/src/resources/image.cpp index eb3a2409..48818f6f 100644 --- a/src/resources/image.cpp +++ b/src/resources/image.cpp @@ -68,9 +68,17 @@ Image* Image::load(void *buffer, unsigned int bufferSize, { // Load the raw file data from the buffer in an RWops structure SDL_RWops *rw = SDL_RWFromMem(buffer, bufferSize); + SDL_Surface *tmpImage; // Use SDL_Image to load the raw image data and have it free the data - SDL_Surface *tmpImage = IMG_Load_RW(rw, 1); + if (!idPath.compare(idPath.length() - 4, 4, ".tga")) + { + tmpImage = IMG_LoadTyped_RW(rw, 1, const_cast("TGA")); + } + else + { + tmpImage = IMG_Load_RW(rw, 1); + } if (tmpImage == NULL) { logger->log("Error, image load failed: %s", IMG_GetError()); diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp new file mode 100644 index 00000000..b91e34cc --- /dev/null +++ b/src/resources/itemdb.cpp @@ -0,0 +1,170 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: + */ + +#include "itemdb.h" + +#include + +#include "iteminfo.h" +#include "resourcemanager.h" + +#include "../log.h" + +#include "../utils/dtor.h" +#include "../utils/xml.h" + +namespace +{ + ItemDB::ItemInfos mItemInfos; + ItemInfo mUnknown; +} + + +void ItemDB::load() +{ + logger->log("Initializing item database..."); + mUnknown.setName("Unknown item"); + + ResourceManager *resman = ResourceManager::getInstance(); + int size; + char *data = (char*)resman->loadFile("items.xml", size); + + if (!data) { + logger->error("ItemDB: Could not find items.xml!"); + } + + xmlDocPtr doc = xmlParseMemory(data, size); + free(data); + + if (!doc) + { + logger->error("ItemDB: Error while parsing item database (items.xml)!"); + } + + xmlNodePtr node = xmlDocGetRootElement(doc); + if (!node || !xmlStrEqual(node->name, BAD_CAST "items")) + { + logger->error("ItemDB: items.xml is not a valid database file!"); + } + + for (node = node->xmlChildrenNode; node != NULL; node = node->next) + { + if (!xmlStrEqual(node->name, BAD_CAST "item")) { + continue; + } + + int id = XML::getProperty(node, "id", 0); + int art = XML::getProperty(node, "art", 0); + int type = XML::getProperty(node, "type", 0); + int weight = XML::getProperty(node, "weight", 0); + int slot = XML::getProperty(node, "slot", 0); + + std::string name = XML::getProperty(node, "name", ""); + std::string image = XML::getProperty(node, "image", ""); + std::string description = XML::getProperty(node, "description", ""); + std::string effect = XML::getProperty(node, "effect", ""); + + if (id && name != "") + { + ItemInfo *itemInfo = new ItemInfo(); + itemInfo->setImage(image); + itemInfo->setArt(art); + itemInfo->setName(name); + itemInfo->setDescription(description); + itemInfo->setEffect(effect); + itemInfo->setType(type); + itemInfo->setWeight(weight); + itemInfo->setSlot(slot); + mItemInfos[id] = itemInfo; + } + + + if (id == 0) + { + logger->log("ItemDB: An item has no ID in items.xml!"); + } + if (name == "") + { + logger->log("ItemDB: Missing name for item %d!", id); + } + + if (image == "") + { + logger->log("ItemDB: Missing image parameter for item: %i. %s", + id, name.c_str()); + } + /* + if (art == 0) + { + logger->log("Item Manager: Missing art parameter for item: %i. %s", + id, name.c_str()); + } + if (description == "") + { + logger->log("ItemDB: Missing description parameter for item: %i. %s", + id, name.c_str()); + } + if (effect == "") + { + logger->log("ItemDB: Missing effect parameter for item: %i. %s", + id, name.c_str()); + } + if (type == 0) + { + logger->log("Item Manager: Missing type parameter for item: %i. %s", + id, name.c_str()); + } + */ + if (weight == 0) + { + logger->log("Item Manager: Missing weight parameter for item: %i. %s", + id, name.c_str()); + } + /* + if (slot == 0) + { + logger->log("Item Manager: Missing slot parameter for item: %i. %s", + id, name.c_str()); + } + */ + } + + xmlFreeDoc(doc); +} + +void ItemDB::unload() +{ + for (ItemInfoIterator i = mItemInfos.begin(); i != mItemInfos.end(); i++) + { + delete i->second; + } + mItemInfos.clear(); +} + +const ItemInfo& +ItemDB::get(int id) +{ + ItemInfoIterator i = mItemInfos.find(id); + + return (i != mItemInfos.end()) ? *(i->second) : mUnknown; +} diff --git a/src/resources/itemdb.h b/src/resources/itemdb.h new file mode 100644 index 00000000..5922984a --- /dev/null +++ b/src/resources/itemdb.h @@ -0,0 +1,53 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: itemdb.h 2650 2006-09-03 15:00:47Z b_lindeijer $ + */ + +#ifndef _TMW_ITEM_MANAGER_H +#define _TMW_ITEM_MANAGER_H + +#include "iteminfo.h" + +#include + +/** + * The namespace that holds the item information + */ +namespace ItemDB +{ + /** + * Loads the item data from Items.xml + */ + void load(); + + /** + * Frees item data + */ + void unload(); + + const ItemInfo& get(int id); + + // Items database + typedef std::map ItemInfos; + typedef ItemInfos::iterator ItemInfoIterator; +} + +#endif diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h index 9a04bb2e..e4f851bb 100644 --- a/src/resources/iteminfo.h +++ b/src/resources/iteminfo.h @@ -33,8 +33,6 @@ class Image; */ class ItemInfo { - friend class ItemManager; - public: /** * Constructor. @@ -49,6 +47,11 @@ class ItemInfo { } + /** + * Destructor. + */ + ~ItemInfo(); + void setArt(short art) { mArt = art; } @@ -101,11 +104,6 @@ class ItemInfo getSlot() const { return mSlot; } protected: - /** - * Destructor. - */ - ~ItemInfo(); - std::string mImageName; /* TODO (BL): I do not think the item info should keep a reference to diff --git a/src/resources/itemmanager.cpp b/src/resources/itemmanager.cpp deleted file mode 100644 index 7d0b13f2..00000000 --- a/src/resources/itemmanager.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * The Mana World - * Copyright 2004 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id$ - */ - -#include "itemmanager.h" - -#include - -#include "iteminfo.h" -#include "resourcemanager.h" - -#include "../log.h" - -#include "../utils/dtor.h" - -#define READ_PROP(node, prop, name, target, cast) \ - prop = xmlGetProp(node, BAD_CAST name); \ - if (prop) { \ - target = cast((const char*)prop); \ - xmlFree(prop); \ - } - -ItemManager::ItemManager() -{ - mUnknown.setName("Unknown item"); - - ResourceManager *resman = ResourceManager::getInstance(); - int size; - char *data = (char*)resman->loadFile("items.xml", size); - - if (!data) { - logger->error("Item Manager: Could not find items.xml!"); - } - - xmlDocPtr doc = xmlParseMemory(data, size); - free(data); - - if (!doc) - { - logger->error("Item Manager: Error while parsing item database (items.xml)!"); - } - - xmlNodePtr node = xmlDocGetRootElement(doc); - if (!node || !xmlStrEqual(node->name, BAD_CAST "items")) - { - logger->error("Item Manager: items.xml is not a valid database file!"); - } - - for (node = node->xmlChildrenNode; node != NULL; node = node->next) - { - int id = 0, art = 0, type = 0, weight = 0, slot = 0; - std::string name = "", description = "", effect = "", image = ""; - - if (!xmlStrEqual(node->name, BAD_CAST "item")) { - continue; - } - - xmlChar *prop = NULL; - READ_PROP(node, prop, "id", id, atoi); - READ_PROP(node, prop, "image", image, ); - READ_PROP(node, prop, "art", art, atoi); - READ_PROP(node, prop, "name", name, ); - READ_PROP(node, prop, "description", description, ); - READ_PROP(node, prop, "effect", effect, ); - READ_PROP(node, prop, "type", type, atoi); - READ_PROP(node, prop, "weight", weight, atoi); - READ_PROP(node, prop, "slot", slot, atoi); - - - if (id && name != "") - { - ItemInfo *itemInfo = new ItemInfo(); - itemInfo->setImage(image); - itemInfo->setArt(art); - itemInfo->setName(name); - itemInfo->setDescription(description); - itemInfo->setEffect(effect); - itemInfo->setType(type); - itemInfo->setWeight(weight); - itemInfo->setSlot(slot); - mItemInfos[id] = itemInfo; - } - - - if (id == 0) - { - logger->log("Item Manager: An item has no ID in items.xml!"); - } - if (name == "") - { - logger->log("Item Manager: An item has no name in items.xml!"); - } - - if (image == "") - { - logger->log("Item Manager: Missing image parameter for item: %i. %s", - id, name.c_str()); - } - /*if (art == 0) - { - logger->log("Item Manager: Missing art parameter for item: %i. %s", - id, name.c_str()); - }*/ - if (description == "") - { - logger->log("Item Manager: Missing description parameter for item: %i. %s", - id, name.c_str()); - } - if (effect == "") - { - logger->log("Item Manager: Missing effect parameter for item: %i. %s", - id, name.c_str()); - } - /*if (type == 0) - { - logger->log("Item Manager: Missing type parameter for item: %i. %s", - id, name.c_str()); - }*/ - if (weight == 0) - { - logger->log("Item Manager: Missing weight parameter for item: %i. %s", - id, name.c_str()); - } - if (slot == 0) - { - logger->log("Item Manager: Missing slot parameter for item: %i. %s", - id, name.c_str()); - } - - /*logger->log("Item: %i %i %i %s %s %i %i %i", id, - getImage(id), getArt(id), getName(id).c_str(), - getDescription(id).c_str(), getType(id), getWeight(id), - getSlot(id));*/ - } - - xmlFreeDoc(doc); -} - -ItemManager::~ItemManager() -{ - for (ItemInfoIterator i = mItemInfos.begin(); i != mItemInfos.end(); i++) - { - delete i->second; - } - mItemInfos.clear(); -} - -const ItemInfo& -ItemManager::getItemInfo(int id) -{ - ItemInfoIterator i = mItemInfos.find(id); - - return (i != mItemInfos.end()) ? *(i->second) : mUnknown; -} diff --git a/src/resources/itemmanager.h b/src/resources/itemmanager.h deleted file mode 100644 index b1f2b95c..00000000 --- a/src/resources/itemmanager.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * The Mana World - * Copyright 2004 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id$ - */ - -#ifndef _TMW_ITEM_MANAGER_H -#define _TMW_ITEM_MANAGER_H - -#include "iteminfo.h" - -#include - -/** - * Defines a class to load items database. - */ -class ItemManager -{ - public: - /** - * Constructor. - */ - ItemManager(); - - /** - * Destructor. - */ - ~ItemManager(); - - const ItemInfo& getItemInfo(int id); - - protected: - // Items database - typedef std::map ItemInfos; - typedef ItemInfos::iterator ItemInfoIterator; - ItemInfos mItemInfos; - ItemInfo mUnknown; -}; - -extern ItemManager *itemDb; - -#endif diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index 2aea3dc5..09a6eb74 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -36,6 +36,7 @@ #include "../tileset.h" #include "../utils/tostring.h" +#include "../utils/xml.h" const unsigned int DEFAULT_TILE_WIDTH = 32; const unsigned int DEFAULT_TILE_HEIGHT = 32; @@ -205,10 +206,10 @@ MapReader::readMap(xmlNodePtr node, const std::string &path) prop = xmlGetProp(node, BAD_CAST "version"); xmlFree(prop); - int w = getProperty(node, "width", 0); - int h = getProperty(node, "height", 0); - int tilew = getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH); - int tileh = getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT); + int w = XML::getProperty(node, "width", 0); + int h = XML::getProperty(node, "height", 0); + int tilew = XML::getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH); + int tileh = XML::getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT); int layerNr = 0; Map *map = new Map(w, h, tilew, tileh); @@ -308,7 +309,7 @@ MapReader::readLayer(xmlNodePtr node, Map *map, int layer) int binLen; unsigned char *binData = - php_base64_decode(charData, strlen((char*)charData), &binLen); + php3_base64_decode(charData, strlen((char*)charData), &binLen); delete[] charData; @@ -354,7 +355,7 @@ MapReader::readLayer(xmlNodePtr node, Map *map, int layer) if (!xmlStrEqual(n2->name, BAD_CAST "tile")) continue; - int gid = getProperty(n2, "gid", -1); + int gid = XML::getProperty(n2, "gid", -1); map->setTileWithGid(x, y, layer, gid); x++; @@ -387,9 +388,9 @@ MapReader::readTileset(xmlNodePtr node, return NULL; } - int firstGid = getProperty(node, "firstgid", 0); - int tw = getProperty(node, "tilewidth", map->getTileWidth()); - int th = getProperty(node, "tileheight", map->getTileHeight()); + int firstGid = XML::getProperty(node, "firstgid", 0); + int tw = XML::getProperty(node, "tilewidth", map->getTileWidth()); + int th = XML::getProperty(node, "tileheight", map->getTileHeight()); for (node = node->xmlChildrenNode; node; node = node->next) { if (!xmlStrEqual(node->name, BAD_CAST "image")) @@ -422,16 +423,3 @@ MapReader::readTileset(xmlNodePtr node, return NULL; } - -int -MapReader::getProperty(xmlNodePtr node, const char* name, int def) -{ - int &ret = def; - - xmlChar *prop = xmlGetProp(node, BAD_CAST name); - if (prop) { - ret = atoi((char*)prop); - xmlFree(prop); - } - return ret; -} diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp new file mode 100644 index 00000000..fb03f6c1 --- /dev/null +++ b/src/resources/monsterdb.cpp @@ -0,0 +1,151 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: + */ + +#include "monsterdb.h" + +#include "resourcemanager.h" + +#include "../log.h" + +#include "../utils/dtor.h" +#include "../utils/xml.h" + +namespace +{ + MonsterDB::MonsterInfos mMonsterInfos; + MonsterInfo mUnknown; +} + +void +MonsterDB::load() +{ + mUnknown.setSprite("error.xml"); + mUnknown.setName("unnamed"); + + logger->log("Initializing monster database..."); + + ResourceManager *resman = ResourceManager::getInstance(); + int size; + char *data = (char*)resman->loadFile("monsters.xml", size); + + if (!data) + { + logger->error("Monster Database: Could not find monsters.xml!"); + } + + xmlDocPtr doc = xmlParseMemory(data, size); + free(data); + + if (!doc) + { + logger->error("Monster Database: Error while parsing monster database (monsters.xml)!"); + } + + xmlNodePtr rootNode = xmlDocGetRootElement(doc); + if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "monsters")) + { + logger->error("Monster Database: monster.xml is not a valid database file!"); + } + + //iterate s + for ( xmlNodePtr monsterNode = rootNode->xmlChildrenNode; + monsterNode != NULL; + monsterNode = monsterNode->next) + { + + if (!xmlStrEqual(monsterNode->name, BAD_CAST "monster")) + { + continue; + } + + MonsterInfo *currentInfo = new MonsterInfo(); + + currentInfo->setName (XML::getProperty(monsterNode, "name", "unnamed")); + + //iterate s and s + for ( xmlNodePtr spriteNode = monsterNode->xmlChildrenNode; + spriteNode != NULL; + spriteNode = spriteNode->next) + { + if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite")) + { + currentInfo->setSprite((const char*) spriteNode->xmlChildrenNode->content); + } + + if (xmlStrEqual(spriteNode->name, BAD_CAST "sound")) + { + std::string event = XML::getProperty(spriteNode, "event", ""); + const char *filename; + filename = (const char*) spriteNode->xmlChildrenNode->content; + + if (event == "hit") + { + currentInfo->addSound(EVENT_HIT, filename); + } + else if (event == "miss") + { + currentInfo->addSound(EVENT_MISS, filename); + } + else if (event == "hurt") + { + currentInfo->addSound(EVENT_HURT, filename); + } + else if (event == "die") + { + currentInfo->addSound(EVENT_DIE, filename); + } + else + { + logger->log("MonsterDB: Warning, sound effect %s for unknown event %s of monster %s", + filename, event.c_str(), currentInfo->getName().c_str()); + } + } + } + mMonsterInfos[XML::getProperty(monsterNode, "id", 0)] = currentInfo; + } +} + +void +MonsterDB::unload() +{ + for_each ( mMonsterInfos.begin(), mMonsterInfos.end(), + make_dtor(mMonsterInfos)); + mMonsterInfos.clear(); +} + + +const MonsterInfo& +MonsterDB::get (int id) +{ + MonsterInfoIterator i = mMonsterInfos.find(id); + + if (i == mMonsterInfos.end()) + { + logger->log("MonsterDB: Warning, unknown monster ID %d requested", id); + return mUnknown; + } + else + { + return *(i->second); + } +} diff --git a/src/resources/monsterdb.h b/src/resources/monsterdb.h new file mode 100644 index 00000000..b105665a --- /dev/null +++ b/src/resources/monsterdb.h @@ -0,0 +1,45 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: + */ + +#ifndef _TMW_MONSTER_DB_H +#define _TMW_MONSTER_DB_H + +#include + +#include "monsterinfo.h" + +namespace MonsterDB +{ + void + load(); + + void + unload(); + + const MonsterInfo& get (int id); + + typedef std::map MonsterInfos; + typedef MonsterInfos::iterator MonsterInfoIterator; +} + +#endif diff --git a/src/resources/monsterinfo.cpp b/src/resources/monsterinfo.cpp new file mode 100644 index 00000000..43aac32a --- /dev/null +++ b/src/resources/monsterinfo.cpp @@ -0,0 +1,70 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: monsterinfo.cpp 2650 2006-09-03 15:00:47Z b_lindeijer $ + */ + +#include "monsterinfo.h" + +#include "../utils/dtor.h" + +MonsterInfo::MonsterInfo(): + mSprite("error.xml") +{ + +} + +MonsterInfo::~MonsterInfo() +{ + //kill vectors in mSoundEffects + for_each ( mSounds.begin(), mSounds.end(), + make_dtor(mSounds)); + mSounds.clear(); +} + + +void +MonsterInfo::addSound (SoundEvent event, std::string filename) +{ + if (mSounds.find(event) == mSounds.end()) + { + mSounds[event] = new std::vector; + } + + mSounds[event]->push_back("sfx/" + filename); +} + + +std::string +MonsterInfo::getSound (SoundEvent event) const +{ + std::map* >::const_iterator i; + + i = mSounds.find(event); + + if (i == mSounds.end()) + { + return ""; + } + else + { + return i->second->at(rand()%i->second->size()); + } +} diff --git a/src/resources/monsterinfo.h b/src/resources/monsterinfo.h new file mode 100644 index 00000000..413dafa0 --- /dev/null +++ b/src/resources/monsterinfo.h @@ -0,0 +1,74 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: monsterinfo.h 2650 2006-09-03 15:00:47Z b_lindeijer $ + */ + +#ifndef _TMW_MONSTERINFO_H_ +#define _TMW_MONSTERINFO_H_ + +#include +#include +#include + + +enum SoundEvent +{ + EVENT_HIT, + EVENT_MISS, + EVENT_HURT, + EVENT_DIE +}; + + +class MonsterInfo +{ + public: + MonsterInfo(); + + ~MonsterInfo(); + + void + setName(std::string name) { mName = name; } ; + + void + setSprite(std::string filename) { mSprite = filename; } + + void + addSound (SoundEvent event, std::string filename); + + const std::string& + getName () const { return mName; }; + + const std::string& + getSprite () const { return mSprite; }; + + std::string + getSound (SoundEvent event) const; + + private: + + std::string mName; + std::string mSprite; + + std::map* > mSounds; +}; + +#endif diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index bb51d023..45067302 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -32,6 +32,7 @@ #include "music.h" #include "soundeffect.h" #include "spriteset.h" +#include "spritedef.h" #include "../log.h" @@ -40,15 +41,33 @@ ResourceManager *ResourceManager::instance = NULL; ResourceManager::ResourceManager() { + logger->log("Initializing resource manager..."); } ResourceManager::~ResourceManager() { - // Release any remaining spritesets first because they depend on images + // Release any remaining spritedefs first because they depend on spritesets ResourceIterator iter = mResources.begin(); while (iter != mResources.end()) { - if (dynamic_cast(iter->second) != NULL) + if (dynamic_cast(iter->second) != 0) + { + cleanUp(iter->second); + ResourceIterator toErase = iter; + ++iter; + mResources.erase(toErase); + } + else + { + ++iter; + } + } + + // Release any remaining spritesets first because they depend on images + iter = mResources.begin(); + while (iter != mResources.end()) + { + if (dynamic_cast(iter->second) != 0) { cleanUp(iter->second); ResourceIterator toErase = iter; @@ -83,7 +102,7 @@ ResourceManager::cleanUp(Resource *res) bool ResourceManager::setWriteDir(const std::string &path) { - return (bool)PHYSFS_setWriteDir(path.c_str()); + return (bool) PHYSFS_setWriteDir(path.c_str()); } void @@ -96,7 +115,7 @@ ResourceManager::addToSearchPath(const std::string &path, bool append) bool ResourceManager::mkdir(const std::string &path) { - return (bool)PHYSFS_mkdir(path.c_str()); + return (bool) PHYSFS_mkdir(path.c_str()); } bool @@ -158,9 +177,9 @@ ResourceManager::get(const E_RESOURCE_TYPE &type, const std::string &idPath) free(buffer); - if (resource) { + if (resource) + { resource->incRef(); - mResources[idPath] = resource; } @@ -215,6 +234,27 @@ ResourceManager::getSpriteset(const std::string &imagePath, int w, int h) return spriteset; } +SpriteDef* +ResourceManager::getSprite(const std::string &path, int variant) +{ + std::stringstream ss; + ss << path << "[" << variant << "]"; + const std::string idPath = ss.str(); + + ResourceIterator resIter = mResources.find(idPath); + + if (resIter != mResources.end()) { + resIter->second->incRef(); + return dynamic_cast(resIter->second); + } + + SpriteDef *sprite = new SpriteDef(idPath, path, variant); + sprite->incRef(); + mResources[idPath] = sprite; + + return sprite; +} + void ResourceManager::release(const std::string &idPath) { @@ -246,18 +286,13 @@ ResourceManager::deleteInstance() void* ResourceManager::loadFile(const std::string &fileName, int &fileSize) { - // If the file doesn't exist indicate failure - if (!PHYSFS_exists(fileName.c_str())) { - logger->log("Warning: %s not found!", fileName.c_str()); - return NULL; - } - // Attempt to open the specified file using PhysicsFS PHYSFS_file *file = PHYSFS_openRead(fileName.c_str()); // If the handler is an invalid pointer indicate failure if (file == NULL) { - logger->log("Warning: %s failed to load!", fileName.c_str()); + logger->log("Warning: Failed to load %s: %s", + fileName.c_str(), PHYSFS_getLastError()); return NULL; } diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h index 0086b167..d458f96e 100644 --- a/src/resources/resourcemanager.h +++ b/src/resources/resourcemanager.h @@ -34,6 +34,7 @@ class Image; class Music; class SoundEffect; class Spriteset; +class SpriteDef; /** * A class for loading and managing resources. @@ -113,21 +114,21 @@ class ResourceManager get(const E_RESOURCE_TYPE &type, const std::string &idPath); /** - * Convenience wrapper around ResourceManager::create for loading + * Convenience wrapper around ResourceManager::get for loading * images. */ Image* getImage(const std::string &idPath); /** - * Convenience wrapper around ResourceManager::create for loading + * Convenience wrapper around ResourceManager::get for loading * songs. */ Music* getMusic(const std::string &idPath); /** - * Convenience wrapper around ResourceManager::create for loading + * Convenience wrapper around ResourceManager::get for loading * samples. */ SoundEffect* @@ -137,7 +138,15 @@ class ResourceManager * Creates a spriteset based on the image referenced by the given * path and the supplied sprite sizes */ - Spriteset* getSpriteset(const std::string &imagePath, int w, int h); + Spriteset* + getSpriteset(const std::string &imagePath, int w, int h); + + /** + * Creates a sprite definition based on a given path and the supplied + * variant. + */ + SpriteDef* + getSprite(const std::string &path, int variant = 0); /** * Releases a resource, removing it from the set of loaded resources. diff --git a/src/resources/soundeffect.cpp b/src/resources/soundeffect.cpp index 3340e5ea..bb35218e 100644 --- a/src/resources/soundeffect.cpp +++ b/src/resources/soundeffect.cpp @@ -23,6 +23,8 @@ #include "soundeffect.h" +#include "../log.h" + SoundEffect::SoundEffect(const std::string &idPath, Mix_Chunk *soundEffect): Resource(idPath), mChunk(soundEffect) @@ -41,13 +43,18 @@ SoundEffect::load(void *buffer, unsigned int bufferSize, // Load the raw file data from the buffer in an RWops structure SDL_RWops *rw = SDL_RWFromMem(buffer, bufferSize); - // Use Mix_LoadWAV_RW to load the raw music data - Mix_Chunk *tmpSoundEffect = Mix_LoadWAV_RW(rw, 0); - - // Now free the SDL_RWops data - SDL_FreeRW(rw); + // Load the music data and free the RWops structure + Mix_Chunk *tmpSoundEffect = Mix_LoadWAV_RW(rw, 1); - return new SoundEffect(idPath, tmpSoundEffect); + if (tmpSoundEffect) + { + return new SoundEffect(idPath, tmpSoundEffect); + } + else + { + logger->log("Error while loading sound effect (%s)", idPath.c_str()); + return NULL; + } } bool diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp new file mode 100644 index 00000000..bd273b3b --- /dev/null +++ b/src/resources/spritedef.cpp @@ -0,0 +1,381 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "spritedef.h" + +#include "../animation.h" +#include "../action.h" +#include "../graphics.h" +#include "../log.h" + +#include "resourcemanager.h" +#include "spriteset.h" +#include "image.h" + +#include "../utils/xml.h" + +SpriteDef::SpriteDef(const std::string &idPath, + const std::string &file, int variant): + Resource(idPath), + mAction(NULL), + mDirection(DIRECTION_DOWN), + mLastTime(0) +{ + load(file, variant); +} + +Action* +SpriteDef::getAction(SpriteAction action) const +{ + Actions::const_iterator i = mActions.find(action); + + if (i == mActions.end()) + { + logger->log("Warning: no action \"%u\" defined!", action); + return NULL; + } + + return i->second; +} + +void +SpriteDef::load(const std::string &animationFile, int variant) +{ + int size; + ResourceManager *resman = ResourceManager::getInstance(); + char *data = (char*) resman->loadFile(animationFile.c_str(), size); + + if (!data) { + logger->error("Animation: Could not find " + animationFile + "!"); + } + + xmlDocPtr doc = xmlParseMemory(data, size); + free(data); + + if (!doc) { + logger->error( + "Animation: Error while parsing animation definition file!"); + } + + xmlNodePtr node = xmlDocGetRootElement(doc); + if (!node || !xmlStrEqual(node->name, BAD_CAST "sprite")) { + logger->error( + "Animation: this is not a valid animation definition file!"); + } + + // Get the variant + int variant_num = XML::getProperty(node, "variants", 0); + int variant_offset = 0; + + if (variant_num > 0 && variant < variant_num) + { + variant_offset = variant * XML::getProperty(node, "variant_offset", 0); + } + + for (node = node->xmlChildrenNode; node != NULL; node = node->next) + { + if (xmlStrEqual(node->name, BAD_CAST "imageset")) + { + loadImageSet(node); + } + else if (xmlStrEqual(node->name, BAD_CAST "action")) + { + loadAction(node, variant_offset); + } + else if (xmlStrEqual(node->name, BAD_CAST "include")) + { + includeSprite(node); + } + } + + xmlFreeDoc(doc); + + // Complete missing actions + substituteAction(ACTION_STAND, ACTION_DEFAULT); + substituteAction(ACTION_WALK, ACTION_STAND); + substituteAction(ACTION_WALK, ACTION_RUN); + substituteAction(ACTION_ATTACK, ACTION_STAND); + substituteAction(ACTION_ATTACK_SWING, ACTION_ATTACK); + substituteAction(ACTION_ATTACK_STAB, ACTION_ATTACK_SWING); + substituteAction(ACTION_ATTACK_BOW, ACTION_ATTACK_STAB); + substituteAction(ACTION_ATTACK_THROW, ACTION_ATTACK_SWING); + substituteAction(ACTION_CAST_MAGIC, ACTION_ATTACK_SWING); + substituteAction(ACTION_USE_ITEM, ACTION_CAST_MAGIC); + substituteAction(ACTION_SIT, ACTION_STAND); + substituteAction(ACTION_SLEEP, ACTION_SIT); + substituteAction(ACTION_HURT, ACTION_STAND); + substituteAction(ACTION_DEAD, ACTION_HURT); +} + +void +SpriteDef::loadImageSet(xmlNodePtr node) +{ + int width = XML::getProperty(node, "width", 0); + int height = XML::getProperty(node, "height", 0); + std::string name = XML::getProperty(node, "name", ""); + std::string imageSrc = XML::getProperty(node, "src", ""); + + ResourceManager *resman = ResourceManager::getInstance(); + Spriteset *spriteset = resman->getSpriteset(imageSrc, width, height); + + if (!spriteset) + { + logger->error("Couldn't load imageset!"); + } + + mSpritesets[name] = spriteset; +} + +void +SpriteDef::loadAction(xmlNodePtr node, int variant_offset) +{ + const std::string actionName = XML::getProperty(node, "name", ""); + const std::string imagesetName = XML::getProperty(node, "imageset", ""); + + SpritesetIterator si = mSpritesets.find(imagesetName); + if (si == mSpritesets.end()) + { + logger->log("Warning: imageset \"%s\" not defined in %s", + imagesetName.c_str(), getIdPath().c_str()); + return; + } + Spriteset *imageset = si->second; + + SpriteAction actionType = makeSpriteAction(actionName); + if (actionType == ACTION_INVALID) + { + logger->log("Warning: Unknown action \"%s\" defined in %s", + actionName.c_str(), getIdPath().c_str()); + return; + } + Action *action = new Action(); + mActions[actionType] = action; + + // When first action set it as default direction + if (mActions.empty()) + { + mActions[ACTION_DEFAULT] = action; + } + + // Load animations + for (xmlNodePtr animationNode = node->xmlChildrenNode; + animationNode != NULL; + animationNode = animationNode->next) + { + if (xmlStrEqual(animationNode->name, BAD_CAST "animation")) + { + loadAnimation(animationNode, action, imageset, variant_offset); + } + } +} + +void +SpriteDef::loadAnimation(xmlNodePtr animationNode, + Action *action, Spriteset *imageset, + int variant_offset) +{ + std::string directionName = + XML::getProperty(animationNode, "direction", ""); + SpriteDirection directionType = makeSpriteDirection(directionName); + + if (directionType == DIRECTION_INVALID) + { + logger->log("Warning: Unknown direction \"%s\" used in %s", + directionName.c_str(), getIdPath().c_str()); + return; + } + + Animation *animation = new Animation(); + action->setAnimation(directionType, animation); + + // Get animation phases + for (xmlNodePtr phaseNode = animationNode->xmlChildrenNode; + phaseNode != NULL; + phaseNode = phaseNode->next) + { + int delay = XML::getProperty(phaseNode, "delay", 0); + int offsetX = XML::getProperty(phaseNode, "offsetX", 0); + int offsetY = XML::getProperty(phaseNode, "offsetY", 0); + offsetY -= imageset->getHeight() - 32; + offsetX -= imageset->getWidth() / 2 - 16; + + if (xmlStrEqual(phaseNode->name, BAD_CAST "frame")) + { + int index = XML::getProperty(phaseNode, "index", -1); + + if (index < 0) + { + logger->log("No valid value for 'index'"); + continue; + } + + Image *img = imageset->get(index + variant_offset); + + if (!img) + { + logger->log("No image at index " + (index + variant_offset)); + continue; + } + + animation->addPhase(img, delay, offsetX, offsetY); + } + else if (xmlStrEqual(phaseNode->name, BAD_CAST "sequence")) + { + int start = XML::getProperty(phaseNode, "start", -1); + int end = XML::getProperty(phaseNode, "end", -1); + + if (start < 0 || end < 0) + { + logger->log("No valid value for 'start' or 'end'"); + continue; + } + + while (end >= start) + { + Image *img = imageset->get(start + variant_offset); + + if (!img) + { + logger->log("No image at index " + + (start + variant_offset)); + continue; + } + + animation->addPhase(img, delay, offsetX, offsetY); + start++; + } + } + else if (xmlStrEqual(phaseNode->name, BAD_CAST "end")) + { + animation->addTerminator(); + } + } // for phaseNode +} + +void +SpriteDef::includeSprite(xmlNodePtr includeNode) +{ + std::string filename = XML::getProperty(includeNode, "file", ""); + ResourceManager *resman = ResourceManager::getInstance(); + SpriteDef *sprite = resman->getSprite("graphics/sprites/" + filename); + + // TODO: Somehow implement actually including it + sprite->decRef(); +} + +void +SpriteDef::substituteAction(SpriteAction complete, SpriteAction with) +{ + if (mActions.find(complete) == mActions.end()) + { + Actions::iterator i = mActions.find(with); + if (i != mActions.end()) { + mActions[complete] = i->second; + } + } +} + +SpriteDef::~SpriteDef() +{ + for (SpritesetIterator i = mSpritesets.begin(); + i != mSpritesets.end(); ++i) + { + i->second->decRef(); + } +} + +SpriteAction +SpriteDef::makeSpriteAction(const std::string& action) +{ + if (action == "" || action == "default") { + return ACTION_DEFAULT; + } + if (action == "stand") { + return ACTION_STAND; + } + else if (action == "walk") { + return ACTION_WALK; + } + else if (action == "run") { + return ACTION_RUN; + } + else if (action == "attack") { + return ACTION_ATTACK; + } + else if (action == "attack_swing") { + return ACTION_ATTACK_SWING; + } + else if (action == "attack_stab") { + return ACTION_ATTACK_STAB; + } + else if (action == "attack_bow") { + return ACTION_ATTACK_BOW; + } + else if (action == "attack_throw") { + return ACTION_ATTACK_THROW; + } + else if (action == "cast_magic") { + return ACTION_CAST_MAGIC; + } + else if (action == "use_item") { + return ACTION_USE_ITEM; + } + else if (action == "sit") { + return ACTION_SIT; + } + else if (action == "sleep") { + return ACTION_SLEEP; + } + else if (action == "hurt") { + return ACTION_HURT; + } + else if (action == "dead") { + return ACTION_DEAD; + } + else { + return ACTION_INVALID; + } +} + +SpriteDirection +SpriteDef::makeSpriteDirection(const std::string& direction) +{ + if (direction == "" || direction == "default") { + return DIRECTION_DEFAULT; + } + else if (direction == "up") { + return DIRECTION_UP; + } + else if (direction == "left") { + return DIRECTION_LEFT; + } + else if (direction == "right") { + return DIRECTION_RIGHT; + } + else if (direction == "down") { + return DIRECTION_DOWN; + } + else { + return DIRECTION_INVALID; + }; +} diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h new file mode 100644 index 00000000..64414259 --- /dev/null +++ b/src/resources/spritedef.h @@ -0,0 +1,158 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_SPRITEDEF_H +#define _TMW_SPRITEDEF_H + +#include "resource.h" + +#include +#include + +#include + +class Action; +class Graphics; +class Spriteset; +struct AnimationPhase; +class Animation; + +enum SpriteAction +{ + ACTION_DEFAULT = 0, + ACTION_STAND, + ACTION_WALK, + ACTION_RUN, + ACTION_ATTACK, + ACTION_ATTACK_SWING, + ACTION_ATTACK_STAB, + ACTION_ATTACK_BOW, + ACTION_ATTACK_THROW, + ACTION_CAST_MAGIC, + ACTION_USE_ITEM, + ACTION_SIT, + ACTION_SLEEP, + ACTION_HURT, + ACTION_DEAD, + ACTION_INVALID +}; + +enum SpriteDirection +{ + DIRECTION_DEFAULT = 0, + DIRECTION_DOWN, + DIRECTION_UP, + DIRECTION_LEFT, + DIRECTION_RIGHT, + DIRECTION_INVALID +}; + +/** + * Defines a class to load an animation. + */ +class SpriteDef : public Resource +{ + public: + /** + * Constructor. + */ + SpriteDef(const std::string &idPath, + const std::string &file, int variant); + + /** + * Destructor. + */ + ~SpriteDef(); + + /** + * Returns the specified action. + */ + Action* + getAction(SpriteAction action) const; + + private: + /** + * Loads a sprite definition file. + */ + void + load(const std::string &file, int variant); + + /** + * Loads an imageset element. + */ + void + loadImageSet(xmlNodePtr node); + + /** + * Loads an action element. + */ + void + loadAction(xmlNodePtr node, int variant_offset); + + /** + * Loads an animation element. + */ + void + loadAnimation(xmlNodePtr animationNode, + Action *action, Spriteset *imageset, + int variant_offset); + + /** + * Include another sprite into this one. + */ + void + includeSprite(xmlNodePtr includeNode); + + /** + * When there are no animations defined for the action "complete", its + * animations become a copy of those of the action "with". + */ + void + substituteAction(SpriteAction complete, SpriteAction with); + + /** + * Converts a string into a SpriteAction enum. + */ + static SpriteAction + makeSpriteAction(const std::string &action); + + /** + * Converts a string into a SpriteDirection enum. + */ + static SpriteDirection + makeSpriteDirection(const std::string &direction); + + + typedef std::map Spritesets; + typedef Spritesets::iterator SpritesetIterator; + + typedef std::map Actions; + + Spritesets mSpritesets; + Actions mActions; + Action *mAction; + SpriteDirection mDirection; + int mLastTime; +}; + +#endif diff --git a/src/resources/spriteset.h b/src/resources/spriteset.h index c51e6a75..7f6b42df 100644 --- a/src/resources/spriteset.h +++ b/src/resources/spriteset.h @@ -32,7 +32,9 @@ class Image; /** - * Stores a complete set of sprites. + * Stores a set of subimages originating from a single image. + * + * TODO: Should probably be renamed to ImageSet or TileSet. */ class Spriteset : public Resource { @@ -40,7 +42,7 @@ class Spriteset : public Resource /* * Cuts the passed image in a grid of sub images. */ - Spriteset(const std::string& idPath, Image *img, int w, int h); + Spriteset(const std::string &idPath, Image *img, int w, int h); /** * Destructor. diff --git a/src/sound.cpp b/src/sound.cpp index 182be3d6..8ba8fe99 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -191,15 +191,15 @@ void Sound::fadeOutMusic(int ms) } } -void Sound::playSfx(const char *path) +void Sound::playSfx(const std::string &path) { - if (!mInstalled) return; + if (!mInstalled || path.length() == 0) return; ResourceManager *resman = ResourceManager::getInstance(); SoundEffect *sample = resman->getSoundEffect(path); if (sample) { + logger->log("Sound::playSfx() Playing: %s", path.c_str()); sample->play(0, 120); - logger->log("Sound::playSfx() Playing: %s", path); } } diff --git a/src/sound.h b/src/sound.h index 39901121..07db0587 100644 --- a/src/sound.h +++ b/src/sound.h @@ -26,6 +26,8 @@ #include +#include + /** Sound engine * * \ingroup CORE @@ -105,7 +107,7 @@ class Sound { * * \param path Full path to file */ - void playSfx(const char *path); + void playSfx(const std::string &path); private: bool mInstalled; diff --git a/src/sprite.h b/src/sprite.h index 282091cc..51811149 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -47,7 +47,7 @@ class Sprite * partly with the clipping rectangle support. */ virtual void - draw(Graphics *graphics, int offsetX, int offsetY) = 0; + draw(Graphics *graphics, int offsetX, int offsetY) const = 0; /** * Returns the pixel Y coordinate of the sprite. diff --git a/src/utils/wingettimeofday.h b/src/utils/wingettimeofday.h new file mode 100644 index 00000000..0f8b767a --- /dev/null +++ b/src/utils/wingettimeofday.h @@ -0,0 +1,111 @@ +/* + * The Mana World Server + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _TMWSERV_WINGETTIMEOFDAY_H_ +#define _TMWSERV_WINGETTIMEOFDAY_H_ + +#ifdef WIN32 + +#include + +/* + * the function gettimeofday() is available on UNIX but not on windows. + * this header defines a windows implementation as a + * GetSystemTimeAsFileTime() wrapper. + */ + +int gettimeofday(struct timeval* tv, void *tz) +/*--------------------------------------------------------------- + * Copyright (c) 1999,2000,2001,2002,2003 + * The Board of Trustees of the University of Illinois + * All Rights Reserved. + *--------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software (Iperf) and associated + * documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and + * the following disclaimers. + * + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimers in the documentation and/or other materials + * provided with the distribution. + * + * + * Neither the names of the University of Illinois, NCSA, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without + * specific prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * ________________________________________________________________ + * National Laboratory for Applied Network Research + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * http://www.ncsa.uiuc.edu + * ________________________________________________________________ + * + * gettimeofday.c + * by Mark Gates + * ------------------------------------------------------------------- + * A (hack) implementation of gettimeofday for Windows. + * Since I send sec/usec in UDP packets, this made the most sense. + * ------------------------------------------------------------------- */ +{ + FILETIME time; + double timed; + + GetSystemTimeAsFileTime( &time ); + + // Apparently Win32 has units of 1e-7 sec (tenths of microsecs) + // 4294967296 is 2^32, to shift high word over + // 11644473600 is the number of seconds between + // the Win32 epoch 1601-Jan-01 and the Unix epoch 1970-Jan-01 + // Tests found floating point to be 10x faster than 64bit int math. + + timed = ((time.dwHighDateTime * 4294967296e-7) - 11644473600.0) + + (time.dwLowDateTime * 1e-7); + + tv->tv_sec = (long) timed; + tv->tv_usec = (long) ((timed - tv->tv_sec) * 1e6); + + return 0; +} + + +#endif // WIN32 +#endif diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp new file mode 100644 index 00000000..7c917dc0 --- /dev/null +++ b/src/utils/xml.cpp @@ -0,0 +1,54 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "xml.h" + +namespace XML +{ + int + getProperty(xmlNodePtr node, const char* name, int def) + { + int &ret = def; + + xmlChar *prop = xmlGetProp(node, BAD_CAST name); + if (prop) { + ret = atoi((char*)prop); + xmlFree(prop); + } + + return ret; + } + + std::string + getProperty(xmlNodePtr node, const char *name, const std::string &def) + { + xmlChar *prop = xmlGetProp(node, BAD_CAST name); + if (prop) { + std::string val = (char*)prop; + xmlFree(prop); + return val; + } + + return def; + } +} diff --git a/src/utils/xml.h b/src/utils/xml.h new file mode 100644 index 00000000..54ed9951 --- /dev/null +++ b/src/utils/xml.h @@ -0,0 +1,46 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_XML_H +#define _TMW_XML_H + +#include + +#include + +namespace XML +{ + /** + * Gets an integer property from an xmlNodePtr. + */ + int + getProperty(xmlNodePtr node, const char *name, int def); + + /** + * Gets a string property from an xmlNodePtr. + */ + std::string + getProperty(xmlNodePtr node, const char *name, const std::string &def); +} + +#endif diff --git a/tmw.cbp b/tmw.cbp index b8931cf6..d36a8bd0 100644 --- a/tmw.cbp +++ b/tmw.cbp @@ -21,31 +21,35 @@ - - - - - - + + + + + - + - - - - - + + + + + + + + + + + + + + - + - + - + - + + + + + + + + + + + + + + + + + -- cgit v1.2.3-70-g09d2 From b2ef30efb59c8aa4df3bbaab376d46c583a40d98 Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Wed, 27 Dec 2006 20:39:21 +0000 Subject: Client-sided implementation of attacks --- ChangeLog | 13 +++++++++- src/game.cpp | 43 +++++++++------------------------ src/gui/popupmenu.cpp | 8 ------- src/gui/viewport.cpp | 23 +----------------- src/localplayer.cpp | 55 +++++++------------------------------------ src/localplayer.h | 3 +-- src/net/beinghandler.cpp | 17 +++++++++---- src/net/beinghandler.h | 1 + src/net/connection.cpp | 4 ++-- src/net/connection.h | 3 ++- src/net/gameserver/player.cpp | 7 ++++++ src/net/gameserver/player.h | 1 + src/net/playerhandler.cpp | 1 - src/net/protocol.h | 2 ++ 14 files changed, 61 insertions(+), 120 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index c67d6cd6..6174fbe1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2006-12-06 Philipp Sehmisch + + * src/game.cpp, src/gui/popupmenu.cpp, src/gui/viewport.cpp, + src/localplayer.cpp, src/localplayer.h, src/net/beinghandler.cpp, + src/net/beinghandler.h, src/net/connection.cpp, src/net/connection.h, + src/net/gameserver/player.cpp, src/net/gameserver/player.h, + src/net/playerhandler.cpp, src/net/protocol.h: + Attacks are now targetless one-time events. The server is informed when the + client performs an attack and attack messages from the server are received + and displayed. + 2006-12-09 Eugenio Favalli * data/graphics/sprites/npcs.png: Added pirate NPC. @@ -1672,7 +1683,7 @@ passing a NULL pointer as image argument. * data/graphics/sprites/player_male_base.xml: Animation file now has the syntax described on the wiki. - + 2006-06-27 Eugenio Favalli * data/graphics/sprites/Makefile.am, diff --git a/src/game.cpp b/src/game.cpp index 15298ec6..21b6008e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -509,6 +509,17 @@ void Game::handleInput() } break; + // attacking + // TODO: Reimplement attacking with joystick buttons + // (old code allowed permanent attacking and not 1 attack + // with each button push) + // I would like to do this but i don't own a joystick. + case SDLK_LCTRL: + case SDLK_RCTRL: + player_node->attack(); + used = true; + break; + // Quitting confirmation dialog case SDLK_ESCAPE: if (!exitConfirm) { @@ -651,38 +662,6 @@ void Game::handleInput() player_node->walk(direction); - // Attacking monsters - if (keys[SDLK_LCTRL] || keys[SDLK_RCTRL] || - joystick && joystick->buttonPressed(0)) - { - Being *target = NULL; - bool newTarget = keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]; - - // A set target has highest priority - if (newTarget || !player_node->getTarget()) - { - Uint16 targetX = x, targetY = y; - - if (player_node->getDirection() & Being::UP) - targetY--; - if (player_node->getDirection() & Being::DOWN) - targetY++; - if (player_node->getDirection() & Being::LEFT) - targetX--; - if (player_node->getDirection() & Being::RIGHT) - targetX++; - - // Attack priority is: Monster, Player, auto target - target = beingManager->findBeing( - targetX, targetY, Being::MONSTER); - if (!target) - target = beingManager->findBeing( - targetX, targetY, Being::PLAYER); - } - - player_node->attack(target, newTarget); - } - // Target the nearest monster if 'a' pressed if (keys[SDLK_a]) { diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index c2959e1d..c7c77ef4 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -136,14 +136,6 @@ void PopupMenu::handleLink(const std::string& link) tradePartnerName = mBeing->getName(); } - // Attack action - else if (link == "attack" && - mBeing != NULL && - mBeing->getType() == Being::PLAYER) - { - player_node->attack(mBeing, true); - } - /* // Follow Player action else if (link == "follow") diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index d0525a2f..f26d8d70 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -291,29 +291,9 @@ Viewport::mousePress(int mx, int my, int button) Being *being; FloorItem *item; - // Interact with some being - if ((being = beingManager->findBeing(tilex, tiley))) - { - switch (being->getType()) - { - case Being::NPC: - dynamic_cast(being)->talk(); - break; - - case Being::MONSTER: - case Being::PLAYER: - if (being->mAction == Being::DEAD) - break; - player_node->attack(being, true); - break; - - default: - break; - } - } // Pick up some item - else if ((item = floorItemManager->findByCoordinates(tilex, tiley))) + if ((item = floorItemManager->findByCoordinates(tilex, tiley))) { player_node->pickUp(item); } @@ -325,7 +305,6 @@ Viewport::mousePress(int mx, int my, int button) if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT])) { player_node->setDestination(mx + mCameraX, my + mCameraY); - player_node->stopAttack(); } mPlayerFollowMouse = true; } diff --git a/src/localplayer.cpp b/src/localplayer.cpp index c887dd1c..6918fa60 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -51,11 +51,6 @@ LocalPlayer::~LocalPlayer() void LocalPlayer::logic() { - if (mAction == ATTACK && get_elapsed_time(mWalkTime) >= mAttackSpeed) - { - attack(); - } - // Actions are allowed once per second if (get_elapsed_time(mLastAction) >= 1000) { mLastAction = -1; @@ -166,7 +161,6 @@ void LocalPlayer::pickUp(FloorItem *item) } else { setDestination(item->getX() * 32 + 16, item->getY() * 32 + 16); mPickUpTarget = item; - stopAttack(); } } @@ -352,59 +346,26 @@ bool LocalPlayer::tradeRequestOk() const return !mTrading; } -void LocalPlayer::attack(Being *target, bool keep) +void LocalPlayer::attack() { - // Can only attack when standing still - if (mAction != STAND) + if (mLastAction != -1) return; - if (keep && target) - mTarget = target; - else if (mTarget) - target = mTarget; - - if (!target) + // Can only attack when standing still + if (mAction != STAND && mAction != ATTACK) return; - int dist_x = target->mX - mX; - int dist_y = target->mY - mY; - - if (abs(dist_y) >= abs(dist_x)) - { - if (dist_y > 0) - setDirection(DOWN); - else - setDirection(UP); - } - else - { - if (dist_x > 0) - setDirection(RIGHT); - else - setDirection(LEFT); - } - - // Implement charging attacks here - mLastAttackTime = 0; + mLastAction = tick_time; + mWalkTime = tick_time; setAction(ATTACK); - mWalkTime = tick_time; + if (getWeapon() == 2) sound.playSfx("sfx/bow_shoot_1.ogg"); else sound.playSfx("sfx/fist-swish.ogg"); - // XXX Convert for new server - /* - MessageOut outMsg(0x0089); - outMsg.writeLong(target->getId()); - outMsg.writeByte(0); - */ -} - -void LocalPlayer::stopAttack() -{ - mTarget = NULL; + Net::GameServer::Player::attack(); } Being* LocalPlayer::getTarget() const diff --git a/src/localplayer.h b/src/localplayer.h index f632b1b9..59b59812 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -103,8 +103,7 @@ class LocalPlayer : public Player */ void setTrading(bool trading) { mTrading = trading; } - void attack(Being *target=NULL, bool keep=false); - void stopAttack(); + void attack(); Being* getTarget() const; /** diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 6d8ff6c6..c6db8e33 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -53,6 +53,7 @@ BeingHandler::BeingHandler() //SMSG_PLAYER_UPDATE_2, //SMSG_PLAYER_MOVE, //0x0119, + GPMSG_BEING_ATTACK, GPMSG_BEING_ENTER, GPMSG_BEING_LEAVE, GPMSG_BEINGS_MOVE, @@ -85,6 +86,9 @@ void BeingHandler::handleMessage(MessageIn &msg) case GPMSG_BEINGS_MOVE: handleBeingsMoveMessage(msg); break; + case GPMSG_BEING_ATTACK: + handleBeingAttackMessage(msg); + break; /* case SMSG_BEING_VISIBLE: @@ -432,10 +436,7 @@ void BeingHandler::handleBeingLeaveMessage(MessageIn &msg) { Being *being = beingManager->findBeing(msg.readShort()); if (!being) return; - if (being == player_node->getTarget()) - { - player_node->stopAttack(); - } + beingManager->destroyBeing(being); } @@ -489,3 +490,11 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) } } } + +void BeingHandler::handleBeingAttackMessage(MessageIn &msg) +{ + Being *being = beingManager->findBeing(msg.readShort()); + if (!being) return; + + being->setAction(Being::ATTACK); +} diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h index 59539ffe..ca6ad1b6 100644 --- a/src/net/beinghandler.h +++ b/src/net/beinghandler.h @@ -34,6 +34,7 @@ class BeingHandler : public MessageHandler void handleMessage(MessageIn &msg); private: + void handleBeingAttackMessage(MessageIn &msg); void handleBeingEnterMessage(MessageIn &msg); void handleBeingLeaveMessage(MessageIn &msg); void handleBeingsMoveMessage(MessageIn &msg); diff --git a/src/net/connection.cpp b/src/net/connection.cpp index a17bc727..4ce05d4a 100644 --- a/src/net/connection.cpp +++ b/src/net/connection.cpp @@ -48,7 +48,7 @@ bool Net::Connection::connect(const std::string &address, short port) if (address.empty()) { logger->log("Net::Connection::connect() got empty address!"); - mState = ERROR; + mState = NET_ERROR; return false; } @@ -63,7 +63,7 @@ bool Net::Connection::connect(const std::string &address, short port) if (!mConnection) { logger->log("Unable to initiate connection to the server."); - mState = ERROR; + mState = NET_ERROR; return false; } diff --git a/src/net/connection.h b/src/net/connection.h index 179367c6..d8ea3124 100644 --- a/src/net/connection.h +++ b/src/net/connection.h @@ -36,7 +36,8 @@ namespace Net { public: enum State { - OK, ERROR + OK, + NET_ERROR }; ~Connection(); diff --git a/src/net/gameserver/player.cpp b/src/net/gameserver/player.cpp index 1f27276a..46cee230 100644 --- a/src/net/gameserver/player.cpp +++ b/src/net/gameserver/player.cpp @@ -66,3 +66,10 @@ void Net::GameServer::Player::equip(int itemId, char slot) Net::GameServer::connection->send(msg); } + +void Net::GameServer::Player::attack() +{ + MessageOut msg(PGMSG_ATTACK); + + Net::GameServer::connection->send(msg); +} diff --git a/src/net/gameserver/player.h b/src/net/gameserver/player.h index 34d5bb45..3fb21516 100644 --- a/src/net/gameserver/player.h +++ b/src/net/gameserver/player.h @@ -39,6 +39,7 @@ namespace Net // void pickUp(...); void useItem(int itemId); void equip(int itemId, char slot); + void attack(); } } } diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp index 37291c0a..79875d1c 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/playerhandler.cpp @@ -309,7 +309,6 @@ PlayerHandler::handleMapChangeMessage(MessageIn &msg) current_npc = 0; player_node->setAction(Being::STAND); - player_node->stopAttack(); player_node->mX = x; player_node->mY = y; diff --git a/src/net/protocol.h b/src/net/protocol.h index 07b5c926..081a70fc 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -159,6 +159,8 @@ enum { GPMSG_BEING_LEAVE = 0x0201, // W being id PGMSG_WALK = 0x0260, // W*2 destination GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, C position] [, W*2 destination] }* + PGMSG_ATTACK = 0x0290, // - + GPMSG_BEING_ATTACK = 0x0291, // W being id PGMSG_SAY = 0x02A0, // S text GPMSG_SAY = 0x02A1, // W being id, S text PGMSG_USE_ITEM = 0x0300, // L item id -- cgit v1.2.3-70-g09d2 From f50453791d237120f1ded69323fb914d6069f6be Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Fri, 29 Dec 2006 12:22:33 +0000 Subject: Implemented catching and displaying of damage notifications. --- ChangeLog | 9 ++++++++- src/localplayer.cpp | 2 +- src/net/beinghandler.cpp | 17 +++++++++++++++++ src/net/beinghandler.h | 1 + src/net/gameserver/player.cpp | 4 ++-- src/net/gameserver/player.h | 2 +- src/net/protocol.h | 3 ++- 7 files changed, 32 insertions(+), 6 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 6174fbe1..66586396 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,11 @@ -2006-12-06 Philipp Sehmisch +2006-12-29 Philipp Sehmisch + + * src/localplayer.h, src/net/beinghandler.cpp, src/net/beinghandler.h, + src/net/gameserver/player.cpp, src/net/gameserver/player.h, + src/net/protocol.h: + Implemented catching and displaying of damage notifications. + +2006-12-27 Philipp Sehmisch * src/game.cpp, src/gui/popupmenu.cpp, src/gui/viewport.cpp, src/localplayer.cpp, src/localplayer.h, src/net/beinghandler.cpp, diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 6918fa60..68f5d7d9 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -365,7 +365,7 @@ void LocalPlayer::attack() else sound.playSfx("sfx/fist-swish.ogg"); - Net::GameServer::Player::attack(); + Net::GameServer::Player::attack(mDirection); } Being* LocalPlayer::getTarget() const diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index c6db8e33..08d47f01 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -57,6 +57,7 @@ BeingHandler::BeingHandler() GPMSG_BEING_ENTER, GPMSG_BEING_LEAVE, GPMSG_BEINGS_MOVE, + GPMSG_BEINGS_DAMAGE, 0 }; handledMessages = _messages; @@ -89,6 +90,9 @@ void BeingHandler::handleMessage(MessageIn &msg) case GPMSG_BEING_ATTACK: handleBeingAttackMessage(msg); break; + case GPMSG_BEINGS_DAMAGE: + handleBeingsDamageMessage(msg); + break; /* case SMSG_BEING_VISIBLE: @@ -498,3 +502,16 @@ void BeingHandler::handleBeingAttackMessage(MessageIn &msg) being->setAction(Being::ATTACK); } + +void BeingHandler::handleBeingsDamageMessage(MessageIn &msg) +{ + while (msg.getUnreadLength()) + { + Being *being = beingManager->findBeing(msg.readShort()); + int damage = msg.readShort(); + if (being) + { + being->setDamage(damage, 0); + } + } +} diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h index ca6ad1b6..2cf0e743 100644 --- a/src/net/beinghandler.h +++ b/src/net/beinghandler.h @@ -38,6 +38,7 @@ class BeingHandler : public MessageHandler void handleBeingEnterMessage(MessageIn &msg); void handleBeingLeaveMessage(MessageIn &msg); void handleBeingsMoveMessage(MessageIn &msg); + void handleBeingsDamageMessage(MessageIn &msg); }; #endif diff --git a/src/net/gameserver/player.cpp b/src/net/gameserver/player.cpp index 46cee230..0a47a6bc 100644 --- a/src/net/gameserver/player.cpp +++ b/src/net/gameserver/player.cpp @@ -67,9 +67,9 @@ void Net::GameServer::Player::equip(int itemId, char slot) Net::GameServer::connection->send(msg); } -void Net::GameServer::Player::attack() +void Net::GameServer::Player::attack(unsigned char direction) { MessageOut msg(PGMSG_ATTACK); - + msg.writeByte(direction); Net::GameServer::connection->send(msg); } diff --git a/src/net/gameserver/player.h b/src/net/gameserver/player.h index 3fb21516..d8f572ae 100644 --- a/src/net/gameserver/player.h +++ b/src/net/gameserver/player.h @@ -39,7 +39,7 @@ namespace Net // void pickUp(...); void useItem(int itemId); void equip(int itemId, char slot); - void attack(); + void attack(unsigned char direction); } } } diff --git a/src/net/protocol.h b/src/net/protocol.h index 081a70fc..80ad48af 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -159,7 +159,7 @@ enum { GPMSG_BEING_LEAVE = 0x0201, // W being id PGMSG_WALK = 0x0260, // W*2 destination GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, C position] [, W*2 destination] }* - PGMSG_ATTACK = 0x0290, // - + PGMSG_ATTACK = 0x0290, // B direction GPMSG_BEING_ATTACK = 0x0291, // W being id PGMSG_SAY = 0x02A0, // S text GPMSG_SAY = 0x02A1, // W being id, S text @@ -167,6 +167,7 @@ enum { GPMSG_USE_RESPONSE = 0x0301, // B error PGMSG_EQUIP = 0x0302, // L item id, B slot GPMSG_EQUIP_RESPONSE = 0x0303, // B error + GPMSG_BEINGS_DAMAGE = 0x0310, // { W being id, W ammount }* // Chat CPMSG_ERROR = 0x0401, // B error -- cgit v1.2.3-70-g09d2 From 58771baadb7529b0b20ca85566ab2790ca5dcd90 Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Fri, 2 Mar 2007 23:29:28 +0000 Subject: Implemented communication of being action changes. --- ChangeLog | 9 +++++- src/being.cpp | 2 +- src/being.h | 9 ++++-- src/localplayer.cpp | 14 +++------ src/monster.cpp | 4 ++- src/monster.h | 2 +- src/net/beinghandler.cpp | 72 ++++++++++++++++++++++++++++--------------- src/net/beinghandler.h | 1 + src/net/gameserver/player.cpp | 7 +++++ src/net/gameserver/player.h | 3 ++ src/net/protocol.h | 5 +-- 11 files changed, 86 insertions(+), 42 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 92f41866..bd752762 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,11 @@ -2007-02-27 Philipp Sehmisch +2007-03-01 Philipp Sehmisch + + * src/being.cpp, src/being.h, src/localplayer.cpp, src/monster.cpp, + src/monster.h, src/net/beinghandler.cpp, src/net/beinghandler.h, + src/net/gameserver/player.cpp, src/net/gameserver/player.h, + src/net/protocol.h: Implemented communication of being action changes. + +2007-02-27 Philipp Sehmisch * gui/button.cpp, src/guibutton.h, src/gui/tabbedcontainer.cpp, src/gui/tabbedcontainer.h:: Tabbed diff --git a/src/being.cpp b/src/being.cpp index 68b85832..33ee7e7a 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -300,7 +300,7 @@ Being::setMap(Map *map) } void -Being::setAction(Uint8 action) +Being::setAction(Action action) { SpriteAction currentAction = ACTION_INVALID; switch (action) diff --git a/src/being.h b/src/being.h index b87cacbe..3c6b14c6 100644 --- a/src/being.h +++ b/src/being.h @@ -67,6 +67,11 @@ class Being : public Sprite MONSTER }; + /** + * Action the being is currently performing + * WARNING: Has to be in sync with the same enum in the Being class + * of the server! + */ enum Action { STAND, WALK, @@ -96,7 +101,7 @@ class Being : public Sprite std::string mName; /**< Name of character */ Uint16 mJob; /**< Job (player job, npc, monster, ) */ Uint16 mX, mY; /**< Pixel coordinates (tile center) */ - Uint8 mAction; /**< Action the being is performing */ + Action mAction; /**< Action the being is performing */ Uint16 mWalkTime; Uint8 mEmotion; /**< Currently showing emotion */ Uint8 mEmotionTime; /**< Time until emotion disappears */ @@ -296,7 +301,7 @@ class Being : public Sprite * Sets the current action. */ virtual void - setAction(Uint8 action); + setAction(Action action); /** * Returns the direction the being is facing. diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 1dd8bdf2..16d5b191 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -289,20 +289,16 @@ void LocalPlayer::toggleSit() return; mLastAction = tick_time; - char type; + Being::Action newAction; switch (mAction) { - case STAND: type = 2; break; - case SIT: type = 3; break; + case Being::STAND: newAction = Being::SIT; break; + case Being::SIT: newAction = Being::STAND; break; default: return; } - // XXX Convert for new server - /* - MessageOut outMsg(0x0089); - outMsg.writeLong(0); - outMsg.writeByte(type); - */ + setAction(newAction); + Net::GameServer::Player::changeAction(newAction); } void LocalPlayer::emote(Uint8 emotion) diff --git a/src/monster.cpp b/src/monster.cpp index f2e4d93d..dd4a321c 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -46,7 +46,7 @@ Monster::getType() const } void -Monster::setAction(Uint8 action) +Monster::setAction(Action action) { SpriteAction currentAction = ACTION_INVALID; @@ -70,6 +70,8 @@ Monster::setAction(Uint8 action) case HURT: // Not implemented yet break; + default: + break; } if (currentAction != ACTION_INVALID) diff --git a/src/monster.h b/src/monster.h index 7f129e14..3e9cdb05 100644 --- a/src/monster.h +++ b/src/monster.h @@ -31,7 +31,7 @@ class Monster : public Being public: Monster(Uint16 id, Uint16 job, Map *map); - virtual void setAction(Uint8 action); + virtual void setAction(Action action); virtual Type getType() const; }; diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 08d47f01..32c78b39 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -58,6 +58,7 @@ BeingHandler::BeingHandler() GPMSG_BEING_LEAVE, GPMSG_BEINGS_MOVE, GPMSG_BEINGS_DAMAGE, + GPMSG_BEING_ACTION_CHANGE, 0 }; handledMessages = _messages; @@ -79,11 +80,9 @@ void BeingHandler::handleMessage(MessageIn &msg) case GPMSG_BEING_ENTER: handleBeingEnterMessage(msg); break; - case GPMSG_BEING_LEAVE: handleBeingLeaveMessage(msg); break; - case GPMSG_BEINGS_MOVE: handleBeingsMoveMessage(msg); break; @@ -93,6 +92,9 @@ void BeingHandler::handleMessage(MessageIn &msg) case GPMSG_BEINGS_DAMAGE: handleBeingsDamageMessage(msg); break; + case GPMSG_BEING_ACTION_CHANGE: + handleBeingActionChangeMessage(msg); + break; /* case SMSG_BEING_VISIBLE: @@ -406,33 +408,45 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) { int type = msg.readByte(); // type int id = msg.readShort(); + Being::Action action = (Being::Action)msg.readByte(); + Uint16 px = msg.readShort(); + Uint16 py = msg.readShort(); - switch (type) { - case OBJECT_PLAYER: + switch (type) { - std::string name = msg.readString(); - Being *being; - if (player_node->getName() == name) + case OBJECT_PLAYER: { - being = player_node; - being->setId(id); - } - else + std::string name = msg.readString(); + Being *being; + if (player_node->getName() == name) + { + being = player_node; + being->setId(id); + } + else + { + being = beingManager->createBeing(id, 0); + being->setName(name); + } + being->setHairStyle(msg.readByte()); + being->setHairColor(msg.readByte()); + being->setSex(msg.readByte()); + being->mX = px; + being->mY = py; + being->setDestination(px, py); + being->setAction(action); + } break; + case OBJECT_MONSTER: { - being = beingManager->createBeing(id, 0); - being->setName(name); - } - being->setHairStyle(msg.readByte()); - being->setHairColor(msg.readByte()); - being->setSex(msg.readByte()); - } break; - case OBJECT_MONSTER: - { - int monsterId = msg.readShort(); - Being *being; - being = beingManager->createBeing(id, 1002 + monsterId); - being->setWalkSpeed(150); // TODO - } break; + int monsterId = msg.readShort(); + Being *being; + being = beingManager->createBeing(id, 1002 + monsterId); + being->setWalkSpeed(150); // TODO + being->mX = px; + being->mY = py; + being->setDestination(px, py); + being->setAction(action); + } break; } } @@ -515,3 +529,11 @@ void BeingHandler::handleBeingsDamageMessage(MessageIn &msg) } } } + +void BeingHandler::handleBeingActionChangeMessage(MessageIn &msg) +{ + Being* being = beingManager->findBeing(msg.readShort()); + if (!being) return; + + being->setAction((Being::Action)msg.readByte()); +} diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h index 2cf0e743..7a018950 100644 --- a/src/net/beinghandler.h +++ b/src/net/beinghandler.h @@ -39,6 +39,7 @@ class BeingHandler : public MessageHandler void handleBeingLeaveMessage(MessageIn &msg); void handleBeingsMoveMessage(MessageIn &msg); void handleBeingsDamageMessage(MessageIn &msg); + void handleBeingActionChangeMessage(MessageIn &msg); }; #endif diff --git a/src/net/gameserver/player.cpp b/src/net/gameserver/player.cpp index 033327c9..9af0c238 100644 --- a/src/net/gameserver/player.cpp +++ b/src/net/gameserver/player.cpp @@ -73,3 +73,10 @@ void Net::GameServer::Player::attack(unsigned char direction) msg.writeByte(direction); Net::GameServer::connection->send(msg); } + +void Net::GameServer::Player::changeAction(Being::Action action) +{ + MessageOut msg(PGMSG_ACTION_CHANGE); + msg.writeByte(action); + Net::GameServer::connection->send(msg); +} diff --git a/src/net/gameserver/player.h b/src/net/gameserver/player.h index 73a533d5..7cc45486 100644 --- a/src/net/gameserver/player.h +++ b/src/net/gameserver/player.h @@ -24,6 +24,8 @@ #ifndef _TMW_NET_GAMESERVER_PLAYER_H #define _TMW_NET_GAMESERVER_PLAYER_H +#include "../../being.h" + #include namespace Net @@ -38,6 +40,7 @@ namespace Net void drop(int slot, int amount); void equip(int slot); void attack(unsigned char direction); + void changeAction(Being::Action action); } } } diff --git a/src/net/protocol.h b/src/net/protocol.h index eb27af7d..a5205dba 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -160,12 +160,14 @@ enum { PGMSG_EQUIP = 0x0112, // B slot GPMSG_INVENTORY = 0x0120, // { B slot, W item id [, B amount] }* GPMSG_INVENTORY_FULL = 0x0121, // { B slot, W item id [, B amount] }* - GPMSG_BEING_ENTER = 0x0200, // B type, W being id + GPMSG_BEING_ENTER = 0x0200, // B type, W being id, B action, W*2 position // player: S name, B hair style, B hair color, B gender // monster: W type id GPMSG_BEING_LEAVE = 0x0201, // W being id GPMSG_ITEM_APPEAR = 0x0202, // W item id, W*2 position PGMSG_WALK = 0x0260, // W*2 destination + PGMSG_ACTION_CHANGE = 0x0270, // B Action + GPMSG_BEING_ACTION_CHANGE = 0x0271, // W being id, B action GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, C position] [, W*2 destination] }* GPMSG_ITEMS = 0x0281, // { W item id, W*2 position }* PGMSG_ATTACK = 0x0290, // B direction @@ -175,7 +177,6 @@ enum { PGMSG_USE_ITEM = 0x0300, // L item id GPMSG_USE_RESPONSE = 0x0301, // B error GPMSG_BEINGS_DAMAGE = 0x0310, // { W being id, W amount }* - GPMSG_BEING_DEAD = 0xDEAD, // W being id // Chat CPMSG_ERROR = 0x0401, // B error -- cgit v1.2.3-70-g09d2 From fc63e88f869919a8b035a5c41db8d05626526bde Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Sun, 11 Mar 2007 19:59:55 +0000 Subject: Merged 0.0 changes from revision 3065 to 3177 to trunk. --- ChangeLog | 150 ++++++++++++++++++++++++++++++- INSTALL | 2 +- NEWS | 6 +- README | 2 +- configure.ac | 9 +- data/graphics/CMakeLists.txt | 1 - data/graphics/Makefile.am | 2 +- data/graphics/gui/mouse.png | Bin 449 -> 984 bytes data/graphics/gui/target-cursor-blue.png | Bin 0 -> 8353 bytes data/graphics/gui/target-cursor-red.png | Bin 0 -> 8361 bytes data/help/header.txt | 2 +- src/being.cpp | 35 ++++++-- src/being.h | 24 +++-- src/engine.cpp | 11 --- src/engine.h | 7 +- src/gui/menuwindow.cpp | 25 ++++-- src/gui/register.cpp | 1 + src/gui/updatewindow.cpp | 131 ++++++++++++++++----------- src/gui/updatewindow.h | 64 ++++--------- src/gui/viewport.cpp | 14 +-- src/localplayer.h | 11 +++ src/log.cpp | 17 ++-- src/logindata.h | 1 + src/main.cpp | 56 +++++++++--- src/main.h | 1 + src/map.cpp | 4 +- src/monster.cpp | 22 ++++- src/monster.h | 15 ++++ src/net/beinghandler.cpp | 33 ++++--- src/resources/resourcemanager.cpp | 27 ++++++ src/resources/resourcemanager.h | 8 ++ 31 files changed, 490 insertions(+), 191 deletions(-) create mode 100644 data/graphics/gui/target-cursor-blue.png create mode 100644 data/graphics/gui/target-cursor-red.png (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index b90c35ad..4357e837 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,20 @@ -2007-03-03 Rogier Polak +2007-03-11 Philipp Sehmisch - * src/main.cpp: Fixed a minor annoyance regarding - auto-character-select and switch_character. + * src/map.cpp, src/gui/viewport.cpp: Fixed a bug that made the engine + not draw the last row and column of the map. + +2007-03-09 Bjørn Lindeijer + + * data/graphics/gui/target-cursor-blue.png, + data/graphics/gui/target-cursor-red.png: Added targeting cursors by Pauan. + * data/graphics/sprites/chest-cotton-male.png, + data/graphics/sprites/chest-cotton-female.png: Replaced cotton shirt with + improved version by Pauan. + +2007-03-03 Rogier Polak + + * src/main.cpp: Fixed a minor annoyance regarding + auto-character-select and switch_character. 2007-03-03 Bjørn Lindeijer @@ -28,6 +41,17 @@ channels by Trapdoor. * src/graphics.h: MSVC Compilation fix by Trapdoor. +2007-02-26 Bjørn Lindeijer + + * configure.ac: Made OpenGL enabled by default. + +2007-02-26 Philipp Sehmisch + + * data/sfx/maggot-dying1.ogg, data/sfx/maggot-hit1.ogg, + data/sfx/maggot-hit2.ogg, data/sfx/maggot-miss1.ogg, + data/sfx/pinkie-hit1.ogg, data/sfx/pinkie-miss1.ogg, + data/monsters.xml: New sound effects by Cosmostrator. + 2007-02-25 Bjørn Lindeijer * src/CMakeLists.txt: Updated CMake file. @@ -54,8 +78,126 @@ size and data type. * src/logindata.h: Added a clear function. +2007-02-21 Philipp Sehmisch + + * src/gui/char-server.cpp, src/gui/updatewindow.cpp, src/gui/main.cpp, + src/gui/main.h: Added a new state "LOADDATA_STATE" that loads the XML + databases. + * src/resourcemanager.cpp, src/resourcemanager.h, src/main.cpp, + customdata/: Added a customdata dir that allows to add custom user + data easily. Just create a zip file with the same structure like the + update archives and drop it in the customdata folder and the files in + it override the default data and the updates. + +2007-02-20 Bjørn Lindeijer + + * src/log.cpp: Applied patch by trapdoor to fix the usage of a + deprecated function on MacOS X 10.4 and later. + * src/being.cpp, src/monster.cpp, src/net/beinghandler.cpp, + src/localplayer.h, src/being.h, src/monster.h: Now different sounds + can play when a monster misses the player. + * src/main.cpp: Applied patch by trapdoor which makes TMW use a more + standard location for the data on MacOS X. + +2007-02-17 Bjørn Lindeijer + + * data/help/header.txt, NEWS, README: Updated release date. + * data/graphics/sprites/Makefile.am, + data/graphics/sprites/CMakeLists.txt, data/graphics/CMakeLists.txt: + Excluded sprites directory from installed files. + +2007-02-16 Rogier Polak + + * src/gui/updatewindow.cpp: Fixed the update bug (hopefully), by + modifying the usage of the synchronisation between threads. Added a + check for existence of the updated file. + +2007-02-15 Bjørn Lindeijer + + * src/winver.h, README, configure.ac, data/help/header.txt, NEWS, + CMakeLists.txt: Changed version to 0.0.22.2. + +2007-02-13 Philipp Sehmisch + + * src/gui/register.cpp, src/logindata.h, src/main.cpp: Fixed the _M/_F + username bug. + +2007-02-11 Philipp Sehmisch + + * data/maps/new_1-9.tmx.gz, data/maps/new_1-14.tmx.gz, + data/maps/new_1-16.tmx.gz: Restored the cloud shadow overlays in the + woodland that got lost somehow during the halloween and christmas chaos. + +2007-02-11 Bjørn Lindeijer + + * data/graphics/sprites/chest_cotton_female.png: Removed this strange + duplicate. + * data/graphics/sprites/Makefile.am, + data/graphics/sprites/CMakeLists.txt: Some updates. + +2007-02-10 Philipp Sehmisch + + * src/gui/viewport.cpp: Fixed the bug in the scrolling limitation that made + it possible to scroll outside of the map in the south and east. + +2007-02-04 Bjørn Lindeijer + + * src/gui/menuwindow.cpp: Fixed a small glitch when dragging the menu + window. + +2007-02-03 Philipp Sehmisch + + * data/graphics/sprites/player-female-base.png: Made the standing and + walking of the female characters more feminine. + * data/equipment.xml, data/graphics/sprites/leg-cotton-male.png, + data/graphics/sprites/leg-cotton-male.xml, + data/graphics/sprites/leg-cotton-female.png, + data/graphics/sprites/leg-cotton-female.xml, + data/graphics/sprites/leg-jeans-male.png, + data/graphics/sprites/leg-jeans-male.xml, + data/graphics/sprites/leg-jeans-female.png, + data/graphics/sprites/leg-jeans-female.xml: Added different sprites + for male and female pants. + +2007-02-02 Bjørn Lindeijer + + * src/engine.h, src/engine.cpp, src/being.h, src/being.cpp: Moved + responsibility of loading emoticons to the Being class. + +2007-02-01 Eugenio Favalli + + * src/gui/updatewindow.cpp: File handle should be closed before + attempting to remove/rename files. + * src/gui/button.h: Fixed buttons loosing focus. + +2007-02-01 Bjørn Lindeijer + + * src/gui/updatewindow.cpp, src/gui/updatewindow.h: A bit of cleanup + and defined a helper function for calculating the alder32 checksum of + a file. Probably not fixing any bug though. + +2007-02-01 Philipp Sehmisch + + * data/equipment.xml, data/items.xml, + data/graphics/items/armor-chest-chainmail.png, + data/graphics/sprites/chest-chainmail-female.png, + data/graphics/sprites/chest-chainmail-female.xml, + data/graphics/sprites/chest-chainmail-male.png, + data/graphics/sprites/chest-chainmail-male.xml: Added chainmail by + "The Judge". The proposed values are: Item ID: 625, Sprite ID: 25, + Defence: 12, Weight: 120. + * data/graphics/sprites/chest-cotton-female.png: Huh? Shouldn't this + be on svn for ages? + +2007-01-30 Eugenio Favalli + + * tmw.cbp: Updated Code::blocks project. + 2007-01-30 Bjørn Lindeijer + * src/CMakeLists.txt, src/Makefile.am, src/net/packet.h, + src/net/packet.cpp, src/net/messageout.cpp: Removed unused Packet + class. * src/properties.h, src/being.cpp, src/beingmanager.h, src/sound.h, src/gui/window.h, src/sound.cpp, src/main.h, src/being.h, src/resources/soundeffect.h, src/resources/image.h, @@ -69,6 +211,8 @@ src/net/messageout.h, src/utils/xml.h, src/main.h, src/resources/monsterdb.h, src/resources/itemdb.h, src/resources/equipmentdb.h: Some work on documentation. + * data/maps/new_8-1.tmx.gz, data/maps/new_11-1.tmx.gz: Map fixes by + Pauan. 2007-01-23 Bjørn Lindeijer diff --git a/INSTALL b/INSTALL index 0f5d53f0..fb168106 100644 --- a/INSTALL +++ b/INSTALL @@ -19,7 +19,7 @@ and some libraries. The required libraries are: * SDL http://www.libsdl.org/ * SDL_mixer http://www.libsdl.org/projects/SDL_mixer/ * SDL_image http://www.libsdl.org/projects/SDL_image/ -* SDL_net http://www.libsdl.org/projects/SDL_net/ +* ENet 1.0 http://enet.bespin.org/ * Guichan 0.6.x http://guichan.sourceforge.net/ * libxml2 http://www.xmlsoft.org/ * physfs 1.0.x http://icculus.org/physfs/ diff --git a/NEWS b/NEWS index adeca670..5281cf78 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,9 @@ -0.0.22.2 (...) +0.0.22.2 (17 February 2007) - Updated to work with Guichan 0.6.1 +- Changed to new default server (server.themanaworld.org) +- Changed custom mouse cursor +- Fixed the issue where _M or _F is appended to the username +- Fixed problem with Cancel button in update dialog 0.0.22.1 (15 January 2007) - Updated to work with Guichan 0.6.0 (older versions no longer supported) diff --git a/README b/README index bf128182..2d6f07b1 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ THE MANA WORLD ============== - Version: 0.0.22.1 Date: 15/01/2007 + Version: 0.0.22.2 Date: 17/02/2007 Development team: diff --git a/configure.ac b/configure.ac index ca31930e..21d9ef56 100755 --- a/configure.ac +++ b/configure.ac @@ -94,15 +94,15 @@ AC_HEADER_STDC AC_CHECK_HEADERS([arpa/inet.h fcntl.h malloc.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h]) # Option to enable OpenGL -AC_ARG_WITH(opengl, AS_HELP_STRING([--with-opengl],[use OpenGL (default is no)])) -if test "x$with_opengl" == "xyes"; then +AC_ARG_WITH(opengl,[ --without-opengl don't use OpenGL ] ) +if test "x$with_opengl" == "xno"; then + with_opengl=no +else AC_CHECK_LIB([GL], [glBegin], , AC_MSG_ERROR([ *** Unable to find OpenGL library])) AC_CHECK_LIB([guichan_opengl], [gcnOpenGL], , AC_MSG_ERROR([ *** Unable to find Guichan OpenGL library (guichan.sf.net)])) AC_DEFINE(USE_OPENGL, 1, [Defines if tmw should use an OpenGL display]) -else - with_opengl=no fi AC_CONFIG_FILES([ @@ -113,7 +113,6 @@ data/graphics/Makefile data/graphics/gui/Makefile data/graphics/images/Makefile data/graphics/images/ambient/Makefile -data/graphics/sprites/Makefile data/graphics/tiles/Makefile data/help/Makefile data/icons/Makefile diff --git a/data/graphics/CMakeLists.txt b/data/graphics/CMakeLists.txt index 0fa9a7be..9a916db3 100644 --- a/data/graphics/CMakeLists.txt +++ b/data/graphics/CMakeLists.txt @@ -1,4 +1,3 @@ ADD_SUBDIRECTORY(gui) ADD_SUBDIRECTORY(images) -ADD_SUBDIRECTORY(sprites) ADD_SUBDIRECTORY(tiles) diff --git a/data/graphics/Makefile.am b/data/graphics/Makefile.am index 43354894..8cda8fa3 100644 --- a/data/graphics/Makefile.am +++ b/data/graphics/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = gui images sprites tiles +SUBDIRS = gui images tiles diff --git a/data/graphics/gui/mouse.png b/data/graphics/gui/mouse.png index e6a84021..9276fc7c 100644 Binary files a/data/graphics/gui/mouse.png and b/data/graphics/gui/mouse.png differ diff --git a/data/graphics/gui/target-cursor-blue.png b/data/graphics/gui/target-cursor-blue.png new file mode 100644 index 00000000..3e81c75d Binary files /dev/null and b/data/graphics/gui/target-cursor-blue.png differ diff --git a/data/graphics/gui/target-cursor-red.png b/data/graphics/gui/target-cursor-red.png new file mode 100644 index 00000000..09195f44 Binary files /dev/null and b/data/graphics/gui/target-cursor-red.png differ diff --git a/data/help/header.txt b/data/help/header.txt index aef87a45..7311c111 100644 --- a/data/help/header.txt +++ b/data/help/header.txt @@ -2,7 +2,7 @@ ##1 T H E M A N A W O R L D ##1 ========================================== - ##2Version:##6 0.0.22.1 ##2Date:##315 January 2007 + ##2Version:##6 0.0.22.2 ##2Date:##317 February 2007 ##2 Website: http://themanaworld.org diff --git a/src/being.cpp b/src/being.cpp index 33ee7e7a..e4a1e9fc 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -33,6 +33,7 @@ #include "log.h" #include "map.h" +#include "resources/resourcemanager.h" #include "resources/spriteset.h" #include "gui/gui.h" @@ -40,12 +41,8 @@ #include "utils/dtor.h" #include "utils/tostring.h" -extern Spriteset *emotionset; - -PATH_NODE::PATH_NODE(unsigned short x, unsigned short y): - x(x), y(y) -{ -} +int Being::instances = 0; +Spriteset *Being::emotionset = NULL; Being::Being(Uint16 id, Uint16 job, Map *map): mJob(job), @@ -70,6 +67,16 @@ Being::Being(Uint16 id, Uint16 job, Map *map): mEquipmentSpriteIDs(VECTOREND_SPRITE, 0) { setMap(map); + + if (instances == 0) + { + // Load the emotion set + ResourceManager *rm = ResourceManager::getInstance(); + emotionset = rm->getSpriteset("graphics/sprites/emotions.png", 30, 32); + if (!emotionset) logger->error("Unable to load emotions spriteset!"); + } + + instances++; } Being::~Being() @@ -77,6 +84,14 @@ Being::~Being() std::for_each(mSprites.begin(), mSprites.end(), make_dtor(mSprites)); clearPath(); setMap(NULL); + + instances--; + + if (instances == 0) + { + emotionset->decRef(); + emotionset = NULL; + } } void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY) @@ -275,12 +290,18 @@ Being::setSpeech(const std::string &text, Uint32 time) } void -Being::setDamage(Sint16 amount, Uint32 time) +Being::takeDamage(int amount) { mDamage = amount ? toString(amount) : "miss"; mDamageTime = 300; } +void +Being::handleAttack() +{ + setAction(Being::ATTACK); +} + void Being::setMap(Map *map) { diff --git a/src/being.h b/src/being.h index 3c6b14c6..c3cba247 100644 --- a/src/being.h +++ b/src/being.h @@ -43,12 +43,17 @@ class Map; class Graphics; class Spriteset; +/** + * A position along a being's path. + */ struct PATH_NODE { /** * Constructor. */ - PATH_NODE(unsigned short x, unsigned short y); + PATH_NODE(unsigned short x, unsigned short y): + x(x), y(y) + { } unsigned short x; unsigned short y; @@ -148,13 +153,19 @@ class Being : public Sprite void setSpeech(const std::string &text, Uint32 time); /** - * Puts a damage bubble above this being for the specified amount - * of time. + * Puts a damage bubble above this being for the specified amount of + * time. * * @param amount The amount of damage. - * @param time The amount of time the text should stay in milliseconds. */ - void setDamage(Sint16 amount, Uint32 time); + virtual void + takeDamage(int amount); + + /** + * Handles an attack of another being by this being. + */ + virtual void + handleAttack(); /** * Returns the name of the being. @@ -384,6 +395,9 @@ class Being : public Sprite Sint16 mStepX, mStepY; Uint16 mStepTime; + + static int instances; /**< Number of Being instances */ + static Spriteset *emotionset; /**< Emoticons used by beings */ }; #endif diff --git a/src/engine.cpp b/src/engine.cpp index d2ce6d6f..a3097d49 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -53,20 +53,9 @@ extern Minimap *minimap; char itemCurrenyQ[10] = "0"; -Spriteset *emotionset; - Engine::Engine(): mCurrentMap(NULL) { - // Load the emotion set - ResourceManager *resman = ResourceManager::getInstance(); - emotionset = resman->getSpriteset("graphics/sprites/emotions.png", 30, 32); - if (!emotionset) logger->error("Unable to load emotions spriteset!"); -} - -Engine::~Engine() -{ - emotionset->decRef(); } void Engine::changeMap(const std::string &mapPath) diff --git a/src/engine.h b/src/engine.h index b16b7c13..161a1e63 100644 --- a/src/engine.h +++ b/src/engine.h @@ -30,7 +30,7 @@ class Map; /** * Game engine. Actually hardly does anything anymore except keeping track of - * the current map and loading the emotes. + * the current map. */ class Engine { @@ -40,11 +40,6 @@ class Engine */ Engine(); - /** - * Destructor. - */ - ~Engine(); - /** * Returns the currently active map. */ diff --git a/src/gui/menuwindow.cpp b/src/gui/menuwindow.cpp index a5b5c99e..943cc6f0 100644 --- a/src/gui/menuwindow.cpp +++ b/src/gui/menuwindow.cpp @@ -30,8 +30,11 @@ #include "button.h" #include "windowcontainer.h" -extern Window *setupWindow, *inventoryWindow, *equipmentWindow, - *skillDialog, *statusWindow; +extern Window *setupWindow; +extern Window *inventoryWindow; +extern Window *equipmentWindow; +extern Window *skillDialog; +extern Window *statusWindow; namespace { struct MenuWindowListener : public gcn::ActionListener @@ -52,9 +55,14 @@ MenuWindow::MenuWindow(): setTitleBarHeight(0); // Buttons - // ------------ - const char *buttonNames[] = { - "Status", "Equipment", "Inventory", "Skills", "Setup", 0 + const char *buttonNames[] = + { + "Status", + "Equipment", + "Inventory", + "Skills", + "Setup", + 0 }; int x = 0, y = 3, h = 0; @@ -67,7 +75,11 @@ MenuWindow::MenuWindow(): h = btn->getHeight(); } - setDefaultSize((windowContainer->getWidth() - x - 2), 0, x, (y + h)); + setContentSize(x - 3, h); + setDefaultSize(windowContainer->getWidth() - getWidth() - 1, + 0, + x - 3, + y + h); } void MenuWindow::draw(gcn::Graphics *graphics) @@ -79,6 +91,7 @@ void MenuWindow::draw(gcn::Graphics *graphics) void MenuWindowListener::action(const gcn::ActionEvent &event) { Window *window = NULL; + if (event.getId() == "Status") { window = statusWindow; diff --git a/src/gui/register.cpp b/src/gui/register.cpp index 4539e48e..be15747d 100644 --- a/src/gui/register.cpp +++ b/src/gui/register.cpp @@ -195,6 +195,7 @@ RegisterDialog::action(const gcn::ActionEvent &event) mLoginData->username = mUserField->getText(); mLoginData->password = mPasswordField->getText(); mLoginData->email = mEmailField->getText(); + mLoginData->registerLogin = true; state = STATE_REGISTER_ATTEMPT; } diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index fe78a27b..d8130cd3 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -46,13 +46,41 @@ #include "../resources/resourcemanager.h" +/** + * Calculates the Alder-32 checksum for the given file. + */ +unsigned long fadler32(FILE *file) +{ + // Obtain file size + fseek(file, 0, SEEK_END); + long fileSize = ftell(file); + rewind(file); + + // Calculate Adler-32 checksum + char *buffer = (char*) malloc(fileSize); + fread(buffer, 1, fileSize, file); + unsigned long adler = adler32(0L, Z_NULL, 0); + adler = adler32(adler, (Bytef*) buffer, fileSize); + free(buffer); + + return adler; +} + UpdaterWindow::UpdaterWindow(): Window("Updating..."), - mThread(NULL), mMutex(NULL), mDownloadStatus(UPDATE_NEWS), - mUpdateHost(""), mCurrentFile("news.txt"), mBasePath(""), - mStoreInMemory(true), mDownloadComplete(true), mUserCancel(false), - mDownloadedBytes(0), mMemoryBuffer(NULL), - mCurlError(new char[CURL_ERROR_SIZE]), mLineIndex(0) + mThread(NULL), + mDownloadStatus(UPDATE_NEWS), + mUpdateHost(""), + mCurrentFile("news.txt"), + mCurrentChecksum(0), + mBasePath(""), + mStoreInMemory(true), + mDownloadComplete(true), + mUserCancel(false), + mDownloadedBytes(0), + mMemoryBuffer(NULL), + mCurlError(new char[CURL_ERROR_SIZE]), + mLineIndex(0) { mCurlError[0] = 0; @@ -151,7 +179,7 @@ void UpdaterWindow::action(const gcn::ActionEvent &event) } else if (event.getId() == "play") { - state = STATE_LOGIN; + state = STATE_LOADDATA; } } @@ -206,22 +234,17 @@ int UpdaterWindow::updateProgress(void *ptr, return 0; } -size_t UpdaterWindow::memoryWrite(void *ptr, - size_t size, size_t nmemb, FILE *stream) +size_t +UpdaterWindow::memoryWrite(void *ptr, size_t size, size_t nmemb, FILE *stream) { UpdaterWindow *uw = reinterpret_cast(stream); size_t totalMem = size * nmemb; - uw->mMemoryBuffer = (char*)realloc(uw->mMemoryBuffer, - uw->mDownloadedBytes + totalMem + 1); + uw->mMemoryBuffer = (char*) realloc(uw->mMemoryBuffer, + uw->mDownloadedBytes + totalMem); if (uw->mMemoryBuffer) { memcpy(&(uw->mMemoryBuffer[uw->mDownloadedBytes]), ptr, totalMem); uw->mDownloadedBytes += totalMem; - - // Make sure the memory buffer is NULL terminated, because this - // function is used to download text files that are later parsed as a - // string. - uw->mMemoryBuffer[uw->mDownloadedBytes] = 0; } return totalMem; @@ -236,8 +259,10 @@ int UpdaterWindow::downloadThread(void *ptr) std::string outFilename; std::string url(uw->mUpdateHost + "/" + uw->mCurrentFile); - while (attempts < 3 && !uw->mDownloadComplete) { + while (attempts < 3 && !uw->mDownloadComplete) + { FILE *outfile = NULL; + FILE *newfile = NULL; uw->setLabel(uw->mCurrentFile + " (0%)"); curl = curl_easy_init(); @@ -282,61 +307,67 @@ int UpdaterWindow::downloadThread(void *ptr) uw->mDownloadStatus = UPDATE_ERROR; switch (res) { - case CURLE_COULDNT_CONNECT: // give more debug info on that error - std::cerr << "curl error " << res << " : " << uw->mCurlError << " " << url.c_str() - << std::endl; + case CURLE_COULDNT_CONNECT: + // give more debug info on that error + std::cerr << "curl error " << res << ": " + << uw->mCurlError << " " << url.c_str() + << std::endl; break; default: - std::cerr << "curl error " << res << " : " << uw->mCurlError << " host: " << url.c_str() - << std::endl; + std::cerr << "curl error " << res << ": " + << uw->mCurlError << " host: " << url.c_str() + << std::endl; } } curl_easy_cleanup(curl); - uw->mDownloadComplete = true; - if (!uw->mStoreInMemory) { - long fileSize; - char *buffer; - // Obtain file size. - fseek(outfile, 0, SEEK_END); - fileSize = ftell(outfile); - rewind(outfile); - buffer = (char*)malloc(fileSize); - fread(buffer, 1, fileSize, outfile); - fclose(outfile); - - // Give the file the proper name - std::string newName(uw->mBasePath + "/updates/" + - uw->mCurrentFile.c_str()); - - // Any existing file with this name is deleted first, otherwise the - // rename will fail on Windows. - ::remove(newName.c_str()); - ::rename(outFilename.c_str(), newName.c_str()); - // Don't check resources2.txt checksum if (uw->mDownloadStatus == UPDATE_RESOURCES) { - // Calculate Adler-32 checksum - unsigned long adler = adler32(0L, Z_NULL, 0); - adler = adler32(adler, (Bytef *)buffer, fileSize); - free(buffer); + unsigned long adler = fadler32(outfile); + + if (uw->mCurrentChecksum != adler) + { + fclose(outfile); - if (uw->mCurrentChecksum != adler) { - uw->mDownloadComplete = false; // Remove the corrupted file - ::remove(newName.c_str()); + ::remove(outFilename.c_str()); logger->log( "Checksum for file %s failed: (%lx/%lx)", uw->mCurrentFile.c_str(), adler, uw->mCurrentChecksum); + attempts++; + continue; // Bail out here to avoid the renaming } } + fclose(outfile); + + // Give the file the proper name + std::string newName(uw->mBasePath + "/updates/" + + uw->mCurrentFile.c_str()); + // Any existing file with this name is deleted first, otherwise + // the rename will fail on Windows. + ::remove(newName.c_str()); + ::rename(outFilename.c_str(), newName.c_str()); + + // Check if we can open it and no errors were encountered + // during renaming + newfile = fopen(newName.c_str(), "rb"); + if (newfile) + { + fclose(newfile); + uw->mDownloadComplete = true; + } + } + else + { + // It's stored in memory, we're done + uw->mDownloadComplete = true; } } attempts++; @@ -398,8 +429,8 @@ void UpdaterWindow::logic() mCurrentFile = "resources2.txt"; mStoreInMemory = false; - download(); mDownloadStatus = UPDATE_LIST; + download(); // download() changes mDownloadComplete to false } break; case UPDATE_LIST: diff --git a/src/gui/updatewindow.h b/src/gui/updatewindow.h index 8c54be27..b5f6a6df 100644 --- a/src/gui/updatewindow.h +++ b/src/gui/updatewindow.h @@ -89,7 +89,7 @@ class UpdaterWindow : public Window, public gcn::ActionListener void download(); /** - * The tread function that download the files. + * The thread function that download the files. */ static int downloadThread(void *ptr); @@ -115,80 +115,46 @@ class UpdaterWindow : public Window, public gcn::ActionListener UPDATE_RESOURCES }; - /** - * A thread that use libcurl to download updates. - */ + /** A thread that use libcurl to download updates. */ SDL_Thread *mThread; - /** - * A mutex to protect shared data between the threads. - */ - SDL_mutex *mMutex; - - /** - * Status of the current download. - */ + /** Status of the current download. */ DownloadStatus mDownloadStatus; - /** - * Host where we get the updated files. - */ + /** Host where we get the updated files. */ std::string mUpdateHost; - /** - * The file currently downloading. - */ + /** The file currently downloading. */ std::string mCurrentFile; - /** - * The Adler32 checksum of the file currently downloading. - */ + /** The Adler32 checksum of the file currently downloading. */ unsigned long mCurrentChecksum; - /** - * Absolute path to locally save downloaded files. - */ + /** Absolute path to locally save downloaded files. */ std::string mBasePath; - /** - * A flag to know if we must write the downloaded file to a memory buffer - * instead of a regular file. - */ + /** A flag to indicate whether to use a memory buffer or a regular file. */ bool mStoreInMemory; - /** - * Flag that show if current download is complete. - */ + /** Flag that show if current download is complete. */ bool mDownloadComplete; - /** - * Flag that show if the user has canceled the update - */ + /** Flag that show if the user has canceled the update. */ bool mUserCancel; - /** - * Byte count currently downloaded in mMemoryBuffer. - */ + /** Byte count currently downloaded in mMemoryBuffer. */ int mDownloadedBytes; - /** - * Buffer where to put downloaded file which are not stored in file system. - */ + /** Buffer for files downloaded to memory. */ char *mMemoryBuffer; - /** - * Buffer to handler human readable error provided by curl. - */ + /** Buffer to handler human readable error provided by curl. */ char *mCurlError; - /** - * List of files to download - */ + /** List of files to download. */ std::vector mLines; - /** - * Index of the file to be downloaded - */ + /** Index of the file to be downloaded. */ unsigned int mLineIndex; gcn::Label *mLabel; /**< Progress bar caption. */ diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index 5f316aea..bc635cce 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -132,18 +132,22 @@ Viewport::draw(gcn::Graphics *gcnGraphics) mViewY = player_y; }; - if (mMap) { + // Don't move camera so that the end of the map is on screen + int viewXmax = mMap->getWidth() * 32 - graphics->getWidth(); + int viewYmax = mMap->getHeight() * 32 - graphics->getHeight(); + if (mMap) + { if (mViewX < 0) { mViewX = 0; } if (mViewY < 0) { mViewY = 0; } - if (mViewX > mMap->getWidth() * 32 - midTileX) { - mViewX = mMap->getWidth() * 32 - midTileX; + if (mViewX > viewXmax) { + mViewX = viewXmax; } - if (mViewY > mMap->getHeight() * 32 - midTileY) { - mViewY = mMap->getHeight() * 32 - midTileY; + if (mViewY > viewYmax) { + mViewY = viewYmax; } } diff --git a/src/localplayer.h b/src/localplayer.h index 980b1aff..9ce67d13 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -35,6 +35,9 @@ class FloorItem; class Inventory; class Item; +/** + * The local player character. + */ class LocalPlayer : public Player { public: @@ -110,8 +113,16 @@ class LocalPlayer : public Player void setTrading(bool trading) { mTrading = trading; } void attack(); + Being* getTarget() const; + /** + * Overridden to do nothing. The attacks of the local player are + * displayed as soon as the player attacks, not when the server says + * the player does. + */ + virtual void handleAttack() {} + /** * Sets the target being of the player. */ diff --git a/src/log.cpp b/src/log.cpp index 3a3c91b8..224736bd 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -20,11 +20,13 @@ */ #include "log.h" + #ifdef WIN32 - #include "utils/wingettimeofday.h" +#include "utils/wingettimeofday.h" #else - #include +#include #endif + #ifdef __APPLE__ #include #endif @@ -110,9 +112,14 @@ void Logger::error(const std::string &error_text) MessageBox(NULL, error_text.c_str(), "Error", MB_ICONERROR | MB_OK); #elif defined __APPLE__ Str255 msg; - c2pstrcpy(msg, error_text.c_str()); - StandardAlert(kAlertStopAlert, "\pError", - (ConstStr255Param)msg, NULL, NULL); + CFStringRef error; + error = CFStringCreateWithCString(NULL, + error_text.c_str(), + kCFStringEncodingMacRoman); + CFStringGetPascalString(error, msg, 255, kCFStringEncodingMacRoman); + StandardAlert(kAlertStopAlert, + "\pError", + (ConstStr255Param) msg, NULL, NULL); #else std::cerr << "Error: " << error_text << std::endl; #endif diff --git a/src/logindata.h b/src/logindata.h index f9b520eb..0a01331c 100644 --- a/src/logindata.h +++ b/src/logindata.h @@ -37,6 +37,7 @@ struct LoginData int session_ID2; bool remember; + bool registerLogin; void clear() { diff --git a/src/main.cpp b/src/main.cpp index 1e7ae32d..aad6a68c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,10 +36,13 @@ #include -#if (defined __USE_UNIX98 || defined __FreeBSD__) +#if (defined __USE_UNIX98 || defined __FreeBSD__ || defined __APPLE__) #include #include #endif +#if defined __APPLE__ +#include +#endif #include "configuration.h" #include "game.h" @@ -150,7 +153,7 @@ struct Options */ void initHomeDir() { -#if !(defined __USE_UNIX98 || defined __FreeBSD__) +#if !(defined __USE_UNIX98 || defined __FreeBSD__ || defined __APPLE__) homeDir = "."; #else homeDir = std::string(PHYSFS_getUserDir()) + "/.tmw"; @@ -160,7 +163,7 @@ void initHomeDir() (errno != EEXIST)) { std::cout << homeDir - << " can't be made, but it doesn't exist! Exitting." + << " can't be made, but it doesn't exist! Exiting." << std::endl; exit(1); } @@ -259,7 +262,21 @@ void initEngine() // Add the main data directory to our PhysicsFS search path resman->addToSearchPath("data", true); +#if defined __APPLE__ + CFBundleRef mainBundle = CFBundleGetMainBundle(); + CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle); + char path[PATH_MAX]; + if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, + PATH_MAX)) + { + fprintf(stderr, "Can't find Resources directory\n"); + } + CFRelease(resourcesURL); + strncat(path, "/data", PATH_MAX - 1); + resman->addToSearchPath(path, true); +#else resman->addToSearchPath(TMW_DATADIR "data", true); +#endif #ifdef USE_OPENGL bool useOpenGL = (config.getValue("opengl", 0) == 1); @@ -449,6 +466,12 @@ void accountLogin(LoginData *loginData) // Clear the password, avoids auto login when returning to login loginData->password = ""; + //remove _M or _F from username after a login for registration purpose + if (loginData->registerLogin) + { + loginData->registerLogin = false; + loginData->username = loginData->username.substr(0, loginData->username.length() - 2); + } // TODO This is not the best place to save the config, but at least better // than the login gui window if (loginData->remember) { @@ -657,6 +680,7 @@ int main(int argc, char *argv[]) } loginData.remember = config.getValue("remember", 0); + loginData.registerLogin = false; Net::initialize(); accountServerConnection = Net::getConnection(); @@ -717,7 +741,7 @@ int main(int argc, char *argv[]) accountServerConnection->isConnected()) { if (options.skipUpdate) { - state = STATE_LOGIN; + state = STATE_LOADDATA; } else { state = STATE_UPDATE; } @@ -794,17 +818,11 @@ int main(int argc, char *argv[]) logger->log("State: UPDATE"); // TODO: Revive later //currentDialog = new UpdaterWindow(); - state = STATE_LOGIN; + state = STATE_LOADDATA; break; case STATE_LOGIN: logger->log("State: LOGIN"); - - // Load XML databases - EquipmentDB::load(); - ItemDB::load(); - MonsterDB::load(); - currentDialog = new LoginDialog(&loginData); // TODO: Restore autologin //if (!loginData.password.empty()) { @@ -812,6 +830,22 @@ int main(int argc, char *argv[]) //} break; + case STATE_LOADDATA: + logger->log("State: LOADDATA"); + + // Add customdata directory + ResourceManager::getInstance()->searchAndAddArchives( + "customdata/", + "zip", + false); + + // Load XML databases + EquipmentDB::load(); + ItemDB::load(); + MonsterDB::load(); + state = STATE_LOGIN; + break; + case STATE_LOGIN_ATTEMPT: accountLogin(&loginData); break; diff --git a/src/main.h b/src/main.h index 4dd93ae8..1e9f8c09 100644 --- a/src/main.h +++ b/src/main.h @@ -72,6 +72,7 @@ enum { STATE_CHOOSE_SERVER, STATE_CONNECT_ACCOUNT, STATE_UPDATE, + STATE_LOADDATA, STATE_LOGIN, STATE_LOGIN_ATTEMPT, STATE_REGISTER, diff --git a/src/map.cpp b/src/map.cpp index a88926d7..a6beb951 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -147,8 +147,8 @@ Map::draw(Graphics *graphics, int scrollX, int scrollY, int layer) if (startX < 0) startX = 0; if (startY < 0) startY = 0; - if (endX >= mWidth) endX = mWidth - 1; - if (endY >= mHeight) endY = mHeight - 1; + if (endX > mWidth) endX = mWidth; + if (endY > mHeight) endY = mHeight; for (int y = startY; y < endY; y++) { diff --git a/src/monster.cpp b/src/monster.cpp index dd4a321c..bea5b7a5 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -57,11 +57,10 @@ Monster::setAction(Action action) break; case DEAD: currentAction = ACTION_DEAD; - sound.playSfx(MonsterDB::get(mJob - 1002).getSound(EVENT_DIE)); + sound.playSfx(getInfo().getSound(EVENT_DIE)); break; case ATTACK: currentAction = ACTION_ATTACK; - sound.playSfx(MonsterDB::get(mJob - 1002).getSound(EVENT_HIT)); mSprites[BASE_SPRITE]->reset(); break; case STAND: @@ -80,3 +79,22 @@ Monster::setAction(Action action) mAction = action; } } + +void +Monster::handleAttack() +{ + Being::handleAttack(); + + const MonsterInfo &mi = getInfo(); + + // TODO: It's not possible to determine hit or miss here, so this stuff probably needs + // to be moved somewhere else. We may lose synchronization between attack animation and + // the sound, unless we adapt the protocol... + sound.playSfx(mi.getSound(EVENT_HIT)); +} + +const MonsterInfo& +Monster::getInfo() const +{ + return MonsterDB::get(mJob - 1002); +} diff --git a/src/monster.h b/src/monster.h index 3e9cdb05..18fa703e 100644 --- a/src/monster.h +++ b/src/monster.h @@ -26,6 +26,8 @@ #include "being.h" +class MonsterInfo; + class Monster : public Being { public: @@ -34,6 +36,19 @@ class Monster : public Being virtual void setAction(Action action); virtual Type getType() const; + + /** + * Handles an attack of another being by this monster. Plays a hit or + * miss sound when appropriate. + */ + virtual void handleAttack(); + + protected: + /** + * Returns the MonsterInfo, with static data about this monster. + */ + const MonsterInfo& + getInfo() const; }; #endif diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 32c78b39..53746671 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -215,29 +215,26 @@ void BeingHandler::handleMessage(MessageIn &msg) switch (type) { case 0: // Damage - if (dstBeing == NULL) break; - - dstBeing->setDamage(param1, SPEECH_TIME); - - if (srcBeing != NULL && - srcBeing != player_node) - { - srcBeing->setAction(Being::ATTACK); - srcBeing->mFrame = 0; - srcBeing->mWalkTime = tick_time; + if (dstBeing) { + dstBeing->takeDamage(param1); + } + if (srcBeing) { + srcBeing->handleAttack(dstBeing, param1); } break; case 2: // Sit - if (srcBeing == NULL) break; - srcBeing->mFrame = 0; - srcBeing->setAction(Being::SIT); + if (srcBeing) { + srcBeing->mFrame = 0; + srcBeing->setAction(Being::SIT); + } break; case 3: // Stand up - if (srcBeing == NULL) break; - srcBeing->mFrame = 0; - srcBeing->setAction(Being::STAND); + if (srcBeing) { + srcBeing->mFrame = 0; + srcBeing->setAction(Being::STAND); + } break; } break; @@ -525,7 +522,7 @@ void BeingHandler::handleBeingsDamageMessage(MessageIn &msg) int damage = msg.readShort(); if (being) { - being->setDamage(damage, 0); + being->takeDamage(damage); } } } @@ -535,5 +532,5 @@ void BeingHandler::handleBeingActionChangeMessage(MessageIn &msg) Being* being = beingManager->findBeing(msg.readShort()); if (!being) return; - being->setAction((Being::Action)msg.readByte()); + being->setAction((Being::Action) msg.readByte()); } diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index 45067302..2059a5c3 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -112,6 +112,33 @@ ResourceManager::addToSearchPath(const std::string &path, bool append) PHYSFS_addToSearchPath(path.c_str(), append ? 1 : 0); } +void +ResourceManager::searchAndAddArchives(const std::string &path, + const std::string &ext, + bool append) +{ + const char *dirSep = PHYSFS_getDirSeparator(); + char **list = PHYSFS_enumerateFiles(path.c_str()); + + for (char **i = list; *i != NULL; i++) + { + size_t len = strlen(*i); + + if (len > ext.length() && !ext.compare((*i)+(len - ext.length()))) + { + std::string file, realPath, archive; + + file = path + (*i); + realPath = std::string(PHYSFS_getRealDir(file.c_str())); + archive = realPath + dirSep + file; + + addToSearchPath(archive, append); + } + } + + PHYSFS_freeList(list); +} + bool ResourceManager::mkdir(const std::string &path) { diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h index d458f96e..e176e337 100644 --- a/src/resources/resourcemanager.h +++ b/src/resources/resourcemanager.h @@ -82,6 +82,14 @@ class ResourceManager void addToSearchPath(const std::string &path, bool append); + /** + * Searches for zip files and adds them to the search path. + */ + void + searchAndAddArchives(const std::string &path, + const std::string &ext, + bool append); + /** * Creates a directory in the write path */ -- cgit v1.2.3-70-g09d2 From a353543dd4da3c489a84f6f17125fdd0e1be2349 Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Mon, 4 Jun 2007 21:48:47 +0000 Subject: Merged 0.0 changes from revision 3234 to 3317 to trunk. --- ChangeLog | 465 ++++++++++++++++++++++++++++- NEWS | 16 + README | 3 +- data/graphics/gui/CMakeLists.txt | 8 +- data/graphics/gui/Makefile.am | 6 + data/graphics/gui/target-cursor-blue-l.png | Bin 0 -> 23803 bytes data/graphics/gui/target-cursor-blue-m.png | Bin 0 -> 18439 bytes data/graphics/gui/target-cursor-blue-s.png | Bin 0 -> 8353 bytes data/graphics/gui/target-cursor-blue.png | Bin 8353 -> 0 bytes data/graphics/gui/target-cursor-red-l.png | Bin 0 -> 25586 bytes data/graphics/gui/target-cursor-red-m.png | Bin 0 -> 17950 bytes data/graphics/gui/target-cursor-red-s.png | Bin 0 -> 8361 bytes data/graphics/gui/target-cursor-red.png | Bin 8361 -> 0 bytes data/help/changes.txt | 147 ++++----- data/help/header.txt | 2 +- docs/Makefile.am | 3 +- src/CMakeLists.txt | 14 + src/Makefile.am | 16 +- src/animatedsprite.cpp | 24 ++ src/animatedsprite.h | 12 + src/animationparticle.cpp | 51 ++++ src/animationparticle.h | 49 +++ src/being.cpp | 122 +++++--- src/being.h | 36 ++- src/engine.cpp | 7 + src/game.cpp | 24 +- src/graphics.cpp | 2 - src/gui/buy.cpp | 117 +++----- src/gui/buy.h | 6 + src/gui/chat.cpp | 4 +- src/gui/chat.h | 4 +- src/gui/debugwindow.cpp | 10 + src/gui/debugwindow.h | 1 + src/gui/inventorywindow.cpp | 7 +- src/gui/sell.cpp | 159 +++++----- src/gui/sell.h | 6 + src/gui/updatewindow.cpp | 7 +- src/gui/viewport.cpp | 108 ++++--- src/gui/viewport.h | 20 +- src/gui/widgets/resizegrip.cpp | 65 ++++ src/gui/widgets/resizegrip.h | 61 ++++ src/gui/window.cpp | 185 ++++++++---- src/gui/window.h | 66 ++-- src/imageparticle.cpp | 69 +++++ src/imageparticle.h | 61 ++++ src/main.cpp | 26 +- src/map.cpp | 23 ++ src/map.h | 25 +- src/monster.cpp | 6 + src/monster.h | 3 + src/net/beinghandler.cpp | 17 +- src/openglgraphics.cpp | 24 +- src/particle.cpp | 370 +++++++++++++++++++++++ src/particle.h | 288 ++++++++++++++++++ src/particleemitter.cpp | 327 ++++++++++++++++++++ src/particleemitter.h | 120 ++++++++ src/resources/animation.h | 2 +- src/resources/image.cpp | 25 +- src/resources/mapreader.cpp | 24 ++ src/resources/monsterdb.cpp | 21 ++ src/resources/monsterinfo.h | 14 +- src/simpleanimation.cpp | 85 ++++++ src/simpleanimation.h | 15 +- src/sprite.h | 16 + src/textparticle.cpp | 64 ++++ src/textparticle.h | 53 ++++ src/utils/fastsqrt.h | 24 ++ src/utils/minmax.h | 47 +++ src/utils/wingettimeofday.h | 226 +++++++------- src/utils/xml.cpp | 23 ++ src/utils/xml.h | 11 + 71 files changed, 3240 insertions(+), 602 deletions(-) create mode 100644 data/graphics/gui/target-cursor-blue-l.png create mode 100644 data/graphics/gui/target-cursor-blue-m.png create mode 100644 data/graphics/gui/target-cursor-blue-s.png delete mode 100644 data/graphics/gui/target-cursor-blue.png create mode 100644 data/graphics/gui/target-cursor-red-l.png create mode 100644 data/graphics/gui/target-cursor-red-m.png create mode 100644 data/graphics/gui/target-cursor-red-s.png delete mode 100644 data/graphics/gui/target-cursor-red.png create mode 100644 src/animationparticle.cpp create mode 100644 src/animationparticle.h create mode 100644 src/gui/widgets/resizegrip.cpp create mode 100644 src/gui/widgets/resizegrip.h create mode 100644 src/imageparticle.cpp create mode 100644 src/imageparticle.h create mode 100644 src/particle.cpp create mode 100644 src/particle.h create mode 100644 src/particleemitter.cpp create mode 100644 src/particleemitter.h create mode 100644 src/textparticle.cpp create mode 100644 src/textparticle.h create mode 100644 src/utils/fastsqrt.h create mode 100644 src/utils/minmax.h (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 61aef963..63aaa1eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,162 @@ +2007-06-03 David Athay + + * src/main.cpp, src/game.cpp: Fixed screenshot taking on OSX. + +2007-06-03 Bjørn Lindeijer + + * src/CMakeLists.txt, src/Makefile.am, docs/Makefile.am: Added some + files to be included with the release. + * src/utils/fastsqrt.h: Fixed warning about strict-aliasing rules. + * src/Makefile.am: Don't die on warnings by default. + * src/resources/image.cpp: Fixed image loading in software mode to not + check for alpha layer when images aren't 32-bit. + * src/graphics.cpp, src/graphics.h, src/imageparticle.cpp: Removed + drawImageTransparent from Graphics class, should be set on image. + * src/imageparticle.h, src/particleemitter.h, src/particle.h, + src/particleemitter.cpp, src/particle.cpp, src/imageparticle.cpp: Have + ParticleEmitter load a possible particle image early on and don't + cause a crash when the image can't be found. + +2007-06-02 Bjørn Lindeijer + + * src/winver.h, README, NEWS, CMakeLists.txt, configure.ac, + data/help/changes.txt, data/help/header.txt: Updated version and + release date and summarized changes. + * src/gui/chat.h, src/gui/chat.cpp: Changed color of chat messages in + OpenGL mode from orange to black. + * src/gui/sell.cpp, src/gui/buy.h, src/gui/buy.cpp, src/gui/sell.h: + Some cleanup of buy/sell dialog code. + +2007-06-01 Bjørn Lindeijer + + * data/graphics/gui/CMakeLists.txt, data/graphics/gui/Makefile.am: + Added target cursors to installed files. + +2007-05-31 Philipp Sehmisch + + * data/maps/new_16-1.tmx.gz: Fixed an inconsistency with the neighbor + map (no new walkmap required). + +2007-05-23 Bjørn Lindeijer + + * src/gui/sell.cpp, src/gui/buy.cpp, src/being.cpp: A bunch of + lingering syntactical changes. + * src/gui/viewport.cpp: Added a missing include and fixed a bug with + cleaning up target cursor animations. + +2007-05-23 Philipp Sehmisch + + * src/gui/viewport.cpp, + data/graphics/gui/target-cursor-blue-s.png, + data/graphics/gui/target-cursor-blue-m.png, + data/graphics/gui/target-cursor-blue-l.png, + data/graphics/gui/target-cursor-red-s.png, + data/graphics/gui/target-cursor-red-m.png, + data/graphics/gui/target-cursor-red-l.png: Replaced target cursor + graphics with higher quality ones by Pauan. + * src/particle.cpp: Made bouncing particles immune against death by + ground contact and removed a nonsensical debugging log message. Made + text splash effects fade out. + * src/textparticle.cpp: Implemented fading in and out for text + particles. + * src/being.cpp, src/particle.cpp, src/particle.h, + src/textparticle.cpp, src/textparticle.h: The color values of text + particles are now stored in 3 integers instead of a Guichan color + structure. + +2007-05-20 Eugenio Favalli + + * tmw.cbp: Updated Code::Blocks project file. + +2007-05-20 Philipp Sehmisch + + * src/gui/buy.cpp, src/gui/sell.cpp: Unified some differences between + buy and sell dialog. Money label now shows money after transaction + instead of current money. + * src/gui/sell.cpp: Fixed the amount-not-reset-when-using-scrollwheel + bug. + * src/being.h, src/gui/viewport.cpp, src/gui/viewport.h: Added 3 + different target cursor sizes. + * src/monster.h, src/monster.cpp, src/resources/monsterdb.cpp, + scr/resources/monsterinfo.h, data/monsters.xml: Target cursor size for + monster is read from the monsters.xml. + * data/graphics/gui/target-cursor-blue-s.png, + data/graphics/gui/target-cursor-blue-m.png, + data/graphics/gui/target-cursor-blue-l.png, + data/graphics/gui/target-cursor-red-s.png, + data/graphics/gui/target-cursor-red-m.png, + data/graphics/gui/target-cursor-red-l.png: Added temporary + placeholders for small and large target cursors until better versions + based on the original SVG are available. + +2007-05-08 Philipp Sehmisch + + * data/graphics/sprites/monster-bat.png, + data/graphics/sprites/monster-bat.xml, + data/graphics/sprites/monster-flower.xml, + data/graphics/sprites/monster-fluffy.xml, + data/graphics/sprites/monster-fluffy.png, + data/graphics/sprites/monster-goblin-fire.xml, + data/graphics/sprites/monster-maggot-giant.xml, + data/graphics/sprites/monster-maggot.xml, + data/graphics/sprites/monster-mountsnake.xml, + data/graphics/sprites/monster-mushroom-red.xml, + data/graphics/sprites/monster-mushroom-spiky.xml, + data/graphics/sprites/monster-pinkie.xml, + data/graphics/sprites/monster-scorpion-black.xml, + data/graphics/sprites/monster-scorpion-red.png, + data/graphics/sprites/monster-scorpion-red.xml, + data/graphics/sprites/monster-skull-poison.xml, + data/graphics/sprites/monster-slime-green.xml, + data/graphics/sprites/monster-slime-red.xml, + data/graphics/sprites/monster-slime-rudolph.xml, + data/graphics/sprites/monster-slime-santa.png, + data/graphics/sprites/monster-slime-santa.xml, + data/graphics/sprites/monster-slime-yellow.xml, + data/graphics/sprites/monster-snake-cave.png, + data/graphics/sprites/monster-snake-cave.xml, + data/graphics/sprites/monster-snake.xml, + data/graphics/sprites/monster-spider.xml: + Adjusted offsets of monster sprites (thanks to Pauan for finding out + the correct offsets - I just subtracted 6 of all x offsets to take the + new position of the target circle in account) and committed some + modifications at some monster graphics by Pauan. + +2007-05-02 Philipp Sehmisch + + * src/sprite.h, src/being.cpp, src/being.h, src/animatedsprite.cpp, + src/animatedsprite.h: Added methods to get the width and height of the + graphical representation of a sprite. + * src/gui/viewport.cpp: Fixed positioning of monster names and target + circles. + +2007-05-02 Philipp Sehmisch + + * src/particle.cpp: Fixed a compiler warning. + +2007-05-02 Björn Steinbrink + + * src/Makefile.am: Add the new particle subclasses to the automake + configuration. + * src/imageparticle.h, src/textparticle.h, src/particle.h, + src/animationparticle.h, src/CMakeLists.txt, src/particleemitter.cpp, + src/animationparticle.cpp, src/particle.cpp, src/imageparticle.cpp, + src/textparticle.cpp, src/utils/xml.cpp, src/utils/xml.h: Split the + particle class into subclasses based on their appearance. + +2007-04-24 Philipp Sehmisch + + * src/particle.cpp, src/particle.h: Some minor code cleanups, speed + optimizations and a bit of documentation. + +2007-04-23 Philipp Sehmisch + + * data/graphics/particles/flame.particle.xml, + data/graphics/particles/blaze.png: Added two files I forgot with the + last commit. + * src/resources/mapreader.cpp, src/particle.cpp, + src/particleemitter.cpp: Using XML child node iteration macro. + 2007-04-22 Björn Steinbrink * CMake/Modules/FindENet.cmake: Fixed ENet status always being set to @@ -10,11 +169,74 @@ * src/resources/itemdb.cpp: Made the parameter checks more terse and manageable. +2007-04-19 Philipp Sehmisch + + * src/resources/mapreader.cpp: Emitter positions are now read from map + files. + * src/engine.cpp: Removed the player follow effect used for testing. + * data/maps/new_4-1.tmx.gz, data/maps/new_5-1.tmx.gz: Added flame + effect to all lamps on the cave maps + * data/maps/new_9-1.tmx.gz: Added waterfall effect to the upper right + corner of NW woodland map. + +2007-04-15 Bjørn Lindeijer + + * src/openglgraphics.cpp: Rely on default 0 value for z axis. + * src/CMakeLists.txt, src/gui/window.cpp, src/gui/widgets, + src/gui/widgets/resizegrip.cpp, src/gui/widgets/resizegrip.h, + src/gui/inventorywindow.cpp, src/gui/window.h, src/Makefile.am: + Reimplemented window resizing. It is now once again possible to resize + windows using their borders (except for the top one, since that's the + title bar for Guichan) and the resize grip in the bottom right is much + easier to grab. + * src/gui/window.cpp: Increased minimum window height and fixed a + problem with setting window content size which was introduced with the + new resize grip. + 2007-04-13 Björn Steinbrink * data/graphics/gui/CMakeLists.txt: Added target cursor graphics to the set of files to be installed. +2007-04-05 Eugenio Favalli + + * src/main.cpp: Unified storage of configuration, updates and + screenshots in home directory. + +2007-04-03 Philipp Sehmisch + + * data/graphics/items/generic-easteregg-blue.png, + data/graphics/items/generic-easteregg-green.png, + data/graphics/items/generic-easteregg-pink.png, + data/graphics/items/generic-easteregg-red.png, + data/graphics/items/generic-easteregg-teal.png, + data/graphics/items/generic-easteregg-yellow.png, + data/items.xml: Added six different easter egg item graphics for the + easter event. Item IDs are 1208 - 1213. + * data/graphics/sprites/npcs.png: Added bunny girl npc for the easter + event. + +2007-04-01 Philipp Sehmisch + + * src/game.cpp: Screenshots are no longer saved directly in the users + home directory on UNIX systems but in the sub folder /.tmw/. A chatlog + message about the success of the screenshot saving does appear now. + Based on a patch by Patrick "the-me" Matthäi. + +2007-03-27 Bjørn Lindeijer + + * src/main.cpp: Icon loading doesn't necessarily succeed, so better + not crash when it doesn't. + +2007-03-25 Philipp Sehmisch + + * src/particle.cpp, src/particle.h, src/particleemitter.cpp, + src/particleemitter.h: Improved programming style and documentation + and added some small tweaks. + * src/engine.cpp, src/map.cpp, src/map.h, src/resources/mapreader.cpp: + Prepared getting the emitter positions from the map file by storing + them in the Map class and setting them up from the MapReader. + 2007-03-24 Bjørn Lindeijer * src/main.cpp: Changed the order of network message handling and @@ -49,6 +271,16 @@ src/net/charserverhandler.h, src/net/charserverhandler.cpp: Made sure the character creation dialog doesn't close when creation failed. +2007-03-22 Philipp Sehmisch + + * src/simpleanimation.cpp, src/simpleanimation.h: Added new + constructor for simple animation that allows to build the animation + based on an xmlNodePtr pointing to an node. + * src/particle.cpp, src/particle.h: Added support for and + childtags for effect root particles. + * data/graphics/particles/playerglow.particle.xml: New player follow + effect that demonstrates an animated root particle with an emitter. + 2007-03-22 Bjørn Lindeijer * src/gui/login.cpp, src/gui/login.h, src/gui/register.h, @@ -84,6 +316,11 @@ src/resources/resourcemanager.cpp, src/resources/spriteset.cpp, src/resources/spritedef.h: Renamed Spriteset to ImageSet. +2007-03-20 Philipp Sehmisch + + * src/gui/updatewindow.cpp: Cancel button is now disabled after + downloading is finished. + 2007-03-20 David Athay * src/gui/viewport.cpp: Fixed target cursor animation, and changed @@ -160,6 +397,8 @@ * src/simpleanimation.cpp, src/simpleanimation.h, src/CmakeLists.txt, src/Makefile.am: Added a simple animation class that hosts a looping animation without the action and direction stuff from AnimatedSprite. + * src/particle.cpp, src/particle.h, src/particleemitter.cpp: Used said + simple animation class for animated particles. 2007-03-12 Bjørn Lindeijer @@ -171,6 +410,14 @@ * src/map.cpp, src/gui/viewport.cpp: Fixed a bug that made the engine not draw the last row and column of the map. +2007-03-09 Philipp Sehmisch + + * src/particle.cpp: Reimplemented physics mode that uses the default + square root function as fallback for systems where the fastInvSqrt + function doesn't work properly. + * src/particle.cpp, src/particle.h: Some performance optimizations + suggested by Rogier "Avaniel" Polak. + 2007-03-09 Bjørn Lindeijer * data/graphics/gui/target-cursor-blue.png, @@ -221,6 +468,10 @@ data/sfx/pinkie-hit1.ogg, data/sfx/pinkie-miss1.ogg, data/monsters.xml: New sound effects by Cosmostrator. +2007-02-25 Philipp Sehmisch + + * src/particle.h, src/particleemitter.h: Just some documentation work. + 2007-02-25 Bjørn Lindeijer * src/CMakeLists.txt: Updated CMake file. @@ -247,6 +498,12 @@ size and data type. * src/logindata.h: Added a clear function. +2007-02-22 Philipp Sehmisch + + * src/particle.cpp, src/particle.h, src/particleemitter.cpp, + src/particleemitter.h: Added new particle property "bounce" that makes + particles bounce off the ground and use it with the damage numbers. + 2007-02-21 Philipp Sehmisch * src/gui/char-server.cpp, src/gui/updatewindow.cpp, src/gui/main.cpp, @@ -286,6 +543,16 @@ * src/winver.h, README, configure.ac, data/help/header.txt, NEWS, CMakeLists.txt: Changed version to 0.0.22.2. +2007-02-15 Philipp Sehmisch + + * src/engine.cpp: The name conflict problem with Guichan seems to be + solved with version 0.6.1. + * src/particle.cpp, src/particle.h, src/particleemitter.cpp, + src/particleemitter.h: Added support for animated particles. + * data/graphics/particles/playerglow.particle.xml: Created a new + player follow particle that spawns a swarm of animated bats that + follow the player. + 2007-02-13 Philipp Sehmisch * src/gui/register.cpp, src/logindata.h, src/main.cpp: Fixed the _M/_F @@ -306,8 +573,36 @@ 2007-02-10 Philipp Sehmisch - * src/gui/viewport.cpp: Fixed the bug in the scrolling limitation that made - it possible to scroll outside of the map in the south and east. + * src/gui/viewport.cpp: Fixed the bug in the scrolling limitation that + made it possible to scroll outside of the map in the south and east. + +2007-02-09 Philipp Sehmisch + + * src/particle.cpp: Fixed a misspelled include and another + optimisation at the vector calculation. + +2007-02-08 Philipp Sehmisch + + * src/particle.cpp, src/utils/fastsqrt.h: Added a faster function to + calculate square roots and using it for hypotenuse calculations. + Thanks to Rogier aka Avaniel for finding the function. + +2007-02-07 Philipp Sehmisch + + * src/particle.cpp, src/particle.h, src/particleemitter.cpp: Renamed + Particle::MAX_PARTICLES to Particle::maxCount and read the value from + config ("particleMaxCount") + * src/particle.cpp: Added fast physics mode that replaces the + trigonometric calculations made for calculating the acceleration by + much less cpu intense but also less accurate formulas. To enable it + set the config option "particleFastPhysics" to "1". + * src/particle.cpp: Added the config option "particleEmitterSkip" that + allows to reduces the output of the emitters by making them spawn + particles only every n-th game tick. + * src/graphics.cpp, src/graphics.h: Added a new method + "drawImageTransparent" to the graphic engine that blits an image with + an alpha factor. + * src/particle.cpp: Using new drawImageTransparent method. 2007-02-04 Bjørn Lindeijer @@ -357,6 +652,35 @@ Defence: 12, Weight: 120. * data/graphics/sprites/chest-cotton-female.png: Huh? Shouldn't this be on svn for ages? + * src/particle.cpp, src/particle.h, src/particleemitter.cpp, + src/particleemitter.h: Implemented die-distance (particles are deleted + when they reached a certain proximity to their target) + * src/particle.cpp: Fixed a bug in the acceleration vector calculation. + * src/particle.cpp, src/particle.h: Fixed a problem with particles with + unlimited lifetime and fade-in. + * data/graphics/particles/playerglow.particle.xml: And again a new + player follow particle. This time it demonstrates die-distance and the + fixed acceleration vector calculation. + * src/engine.cpp, data/graphics/particles/snow.particle.xml, + data/graphics/particles/snowflake.png: I can't stand the begging + anymore. Now it snows in the snow area... and the forest... and the + desert... and under the earth... and indoors... Are you happy now, + Rotonen and Elven? ;-) + * src/particle.cpp: Removed some debug log messages. + * src/being.cpp: Avoided crash when attempting to control an invalid + particle. + * src/particle.cpp, src/particle.h, src/particleemitter.cpp, + src/particleemitter.h: Cleaned the includes up. + +2007-01-31 Philipp Sehmisch + + * src/particle.cpp, src/particle.h, src/particleemitter.cpp, + src/particleemitter.h: Changed some variable names. + * data/graphics/particles/waterfall.particle.xml, + data/graphics/particles/waterfall-a.png: New waterfall with Modanungs + waterfall particle. + * src/particle.cpp: forgot to remove a svn conflict marker and changed + the order of initialisations to fix some compiler warnings. 2007-01-30 Eugenio Favalli @@ -373,6 +697,54 @@ src/resources/mapreader.h, src/resources/music.h: Some trivial documentation work. Fixes all Doxygen warnings. +2007-01-30 Philipp Sehmisch + + * src/net/beinghandler.cpp, + data/graphics/particles/skillup.particle.xml: Added different particle + effect for job levelup. + * src/particle.cpp, src/particle.h, src/particleemitter.cpp, + src/particleemitter.h: Renamed "alphafade" to "fade-out", added new + property "fade-in". + * data/graphics/particles/playerglow.particle.xml: Added a new player + effect (a fire) demonstrating how to use fade-in and fade-out to fade + one color into another. + +2007-01-29 Philipp Sehmisch + + * src/particle.cpp, src/particle.h, src/particleemitter.cpp, + src/particleemitter.h: Added a new particle property "alphafade" that + makes the particles fade into alpha before their lifetime ends. + * src/particle.cpp, src/particle.h: fixed an issue with particles that + have a lifetime of 0 and an issue with the momentum property. + * data/graphics/particles/waterfall.particle.xml, + data/graphics/particles/fog-medium-white-a.png, + data/graphics/particles/fog-medium-white-b.png, + data/graphics/particles/fog-medium-white-c.png: Added fog to the + waterfall effect demonstrating the new alphafade feature. + +2007-01-28 Philipp Sehmisch + + * src/utils/xml.cpp, src/utils/xml.h, src/particleemitter.cpp: Most + values are now read as floating point values from the emitter files. + * data/graphics/particles/fountain.particle.xml, + data/graphics/particles/hit.particle.xml, + data/graphics/particles/playerglow.particle.xml: Changed some values + as floating point values. Made the player follow effect magenta to + improve the visibility of the hit effects. + * src/engine.cpp, data/graphics/particles/waterfall.particle.xml: + Removed the fountain and added a waterfall instead. + * src/particle.h: Corrected the drawing order of the particles in + relation to the other sprites. + * src/gui/debugwindow.cpp, src/gui/debugwindow.h: Added particle count + to debug window. + * src/particle.cpp: Allowed momentum without acceleration and + implement the acceleration properly. + * src/utils/minmax.h, src/particleemitter.cpp, src/particleemitter.h: + Added a structure to hold a pair of numeric minimum and maximum values + and used it to store all numeric emitter properties. + * src/utils/randbetween.h: Removed (the functionality is now in struct + MinMax) + 2007-01-28 Bjørn Lindeijer * src/gui/char_select.h, src/net/messagein.h, @@ -383,6 +755,39 @@ * data/maps/new_8-1.tmx.gz, data/maps/new_11-1.tmx.gz: Map fixes by Pauan. +2007-01-27 Bjørn Lindeijer + + * src/gui/shoplistbox.cpp: Fixed compilation against Guichan 0.6.1. + * src/utils/randbetween.h: Fixed integer overflow causing the + randBetween function not to work properly on Linux. + +2007-01-27 Philipp Sehmisch + + * src/net/beinghandler.cpp: Fixed a compiler issue. + * src/particle.cpp, src/particle.h, src/particleemitter.cpp, + src/particleemitter.h, src/engine.cpp: Emitter data is read from + external xml files. Reimplemented target-based particles with the + difference that they don't target beings or locations but other + particles (at the moment the host particle of the effect). + * src/being.cpp: Beings now move controlled particles to their center + instead of their upper left corner. + * data/graphics/particles/orb*: Added a bunch of new particles. + * data/graphics/particles/fountain.particle.xml: Reimplementation of + the fountain effect in XML. + * data/graphics/particles/playerglow.particle.xml: New effect that + spawns orbs that orbit around the origin. + * src/being.cpp, data/graphics/particles/hit.particle.xml: Added + particle effect on hit. + * src/net/beinghandler.cpp, + data/graphics/particles/levelup.particle.xml: Added particle effect on + levelup (own or other player). + +2007-01-24 Philipp Sehmisch + + * src/particle.cpp: Initialized all variables of the particles in the + constructor. + * src/particleemitter.cpp, src/particleemitter.h: minor cleanups. + 2007-01-23 Bjørn Lindeijer * src/gui/shoplistbox.cpp, docs/INSTALL/win32.txt, INSTALL, NEWS: @@ -393,6 +798,39 @@ * src/gui/updatewindow.cpp: Identify ourselves when requesting files from the update server. +2007-01-22 Philipp Sehmisch + + * src/being.cpp, src/being.h, src/particle.cpp, src/particle.h + src/particleemitter.cpp, src/particleemitter.h, src/engine.cpp: + Particle effects are now created in child particles of the root + particle. Particle emitters have no longer a being they check every + frame. Instead beings have the ability to take control of particles. + +2007-01-19 Philipp Sehmisch + + * src/particle.cpp, src/particle.h, src/particleemitter.cpp, + src/particleemitter.h: Implemented emitters that follow a being. + * src/engine.cpp: Added an emitter that follows the local player. + * src/particle.cpp: Fixed the crash on exit (reason was that the + mSpriteIterator wasn't initialized in every case) + +2007-01-18 Bjørn Lindeijer + + * src/properties.h, src/being.cpp, src/beingmanager.h, src/sound.h, + src/gui/window.h, src/sound.cpp, src/main.h, src/being.h, + src/resources/soundeffect.h, src/resources/image.h, + src/resources/mapreader.h, src/resources/music.h: Some trivial + documentation work. Fixes all Doxygen warnings. + * src/particle.h, src/particle.cpp, src/CMakeLists.txt, + src/Makefile.am: Fixed compilation issues on Linux. + * src/gui/char_select.h, src/net/messagein.h, + src/net/messagehandler.h, src/net/network.h, src/net/connection.h, + src/net/messageout.h, src/utils/xml.h, src/main.h, + src/resources/monsterdb.h, src/resources/itemdb.h, + src/resources/equipmentdb.h: Some work on documentation. + * data/maps/new_8-1.tmx.gz, data/maps/new_11-1.tmx.gz: Map fixes by + Pauan. + 2007-01-17 Eugenio Favalli * docs/win32-release.txt, src/gui/register.cpp, src/main.cpp: Changed @@ -408,6 +846,12 @@ * data/help/header.txt, NEWS, README: Updated release date. +2007-01-15 Philipp Sehmisch + + * src/game.cpp, src/particle.cpp, src/particle.h, + src/particleemitter.h: Made the particle count global and more + performant. + 2007-01-14 Eugenio Favalli * src/gui/updatewindow.cpp, src/main.cpp, tmw.cbp: Fixed windows @@ -448,6 +892,17 @@ * src/winver.h, configure.ac, data/help/header.txt, NEWS, README, CMakeLists.txt: Updated version to 0.0.22.1. +2007-01-14 Philipp Sehmisch + + * src/particle.cpp, src/particle.h; src/particleemitter.cpp, + src/particleemitter.h, src/utils/randbetween.h: + Implemented particle engine. + * src/engine.cpp, src/game.cpp: added calls to the particle engine + * data/graphics/particles/*: added a bunch of particle graphics for + testing purpose. + * particleengine-todo.txt: Added particle engine todo list (please + omit when merging) + 2007-01-13 Bjørn Lindeijer * data/graphics/sprites/Makefile.am, @@ -1298,7 +1753,7 @@ 2006-10-12 Yohann Ferreira * debian/rules, debian/tmw-data.install, debian/tmw-data.dirs, - debian/tmw-music.install, debian/changelog: Updating debian files for + debian/tmw-music.install, debian/changelog: Updating Debian files for bug fixing. 2006-10-12 Frode Lindeijer @@ -1473,7 +1928,7 @@ * src/animation.h, src/animatedsprite.h, data/graphics/sprites/weapon.xml: Some modifications at the animation system. No more "undefined action foo" warnings in the tmw.log. Not - visible actions must now be declared explicitely. + visible actions must now be declared explicitly. * data/graphics/images/ambient/sandstorm.png, data/graphics/images/ambient/clouds.png: Improved quality of the overlay graphics. @@ -1892,7 +2347,7 @@ with more distinctive names. (no, i won't list all 114) * src/itemmanager.cpp, data/items.xml: Replaced indices on the item spriteset with filenames. added names and descriptions for all missing - items. Changed names and dascriptions of some items. + items. Changed names and descriptions of some items. * src/engine.cpp: Removed global item spriteset. * src/floor_item.cpp, src/floor_item.h, src/iteminfo.cpp, src/iteminfo.h, src/equipmentwindow.cpp, src/equipmentwindow.h, diff --git a/NEWS b/NEWS index 5281cf78..9529ae1b 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,19 @@ +0.0.23 (3 June 2007) +- Added a particle engine along with some particle effects +- Added a cursor to indicate targeted enemy +- Added new program icon +- Added a man page for UNIX like systems +- Added the --version command line parameter +- Improved MacOS X release +- Screenshots are now saved in the .tmw directory on UNIX like systems +- Magic pink is no longer used for transparency (fixes issues with that on Mac) +- Fixed difficulties with resizing windows +- Fixed misleading error message when connecting fails +- Fixed wrong error message when account name already exists +- Fixed crash when deleting a character +- Fixed error message when creating a new character fails +- Fixed updating problem when using scrollwheel to change shop selection + 0.0.22.2 (17 February 2007) - Updated to work with Guichan 0.6.1 - Changed to new default server (server.themanaworld.org) diff --git a/README b/README index 2d6f07b1..39677e1e 100644 --- a/README +++ b/README @@ -1,8 +1,7 @@ THE MANA WORLD ============== - Version: 0.0.22.2 Date: 17/02/2007 - + Version: 0.1.0 Date: XX/XX/2007 Development team: - See AUTHORS file for a list diff --git a/data/graphics/gui/CMakeLists.txt b/data/graphics/gui/CMakeLists.txt index 1549b2b4..5a02d7f1 100644 --- a/data/graphics/gui/CMakeLists.txt +++ b/data/graphics/gui/CMakeLists.txt @@ -30,8 +30,12 @@ SET (FILES sansserif8.png selection.png slider.png - target-cursor-blue.png - target-cursor-red.png + target-cursor-blue-l.png + target-cursor-blue-m.png + target-cursor-blue-s.png + target-cursor-red-l.png + target-cursor-red-m.png + target-cursor-red-s.png thickborder.png vscroll_blue.png vscroll_down_default.png diff --git a/data/graphics/gui/Makefile.am b/data/graphics/gui/Makefile.am index c0e0655b..a37e1196 100644 --- a/data/graphics/gui/Makefile.am +++ b/data/graphics/gui/Makefile.am @@ -33,6 +33,12 @@ gui_DATA = \ sansserif8.png \ selection.png \ slider.png \ + target-cursor-blue-l.png \ + target-cursor-blue-m.png \ + target-cursor-blue-s.png \ + target-cursor-red-l.png \ + target-cursor-red-m.png \ + target-cursor-red-s.png \ thickborder.png \ vscroll_blue.png \ vscroll_down_default.png \ diff --git a/data/graphics/gui/target-cursor-blue-l.png b/data/graphics/gui/target-cursor-blue-l.png new file mode 100644 index 00000000..77cdf4b6 Binary files /dev/null and b/data/graphics/gui/target-cursor-blue-l.png differ diff --git a/data/graphics/gui/target-cursor-blue-m.png b/data/graphics/gui/target-cursor-blue-m.png new file mode 100644 index 00000000..c0107357 Binary files /dev/null and b/data/graphics/gui/target-cursor-blue-m.png differ diff --git a/data/graphics/gui/target-cursor-blue-s.png b/data/graphics/gui/target-cursor-blue-s.png new file mode 100644 index 00000000..3e81c75d Binary files /dev/null and b/data/graphics/gui/target-cursor-blue-s.png differ diff --git a/data/graphics/gui/target-cursor-blue.png b/data/graphics/gui/target-cursor-blue.png deleted file mode 100644 index 3e81c75d..00000000 Binary files a/data/graphics/gui/target-cursor-blue.png and /dev/null differ diff --git a/data/graphics/gui/target-cursor-red-l.png b/data/graphics/gui/target-cursor-red-l.png new file mode 100644 index 00000000..76d2101b Binary files /dev/null and b/data/graphics/gui/target-cursor-red-l.png differ diff --git a/data/graphics/gui/target-cursor-red-m.png b/data/graphics/gui/target-cursor-red-m.png new file mode 100644 index 00000000..e2ab79c2 Binary files /dev/null and b/data/graphics/gui/target-cursor-red-m.png differ diff --git a/data/graphics/gui/target-cursor-red-s.png b/data/graphics/gui/target-cursor-red-s.png new file mode 100644 index 00000000..09195f44 Binary files /dev/null and b/data/graphics/gui/target-cursor-red-s.png differ diff --git a/data/graphics/gui/target-cursor-red.png b/data/graphics/gui/target-cursor-red.png deleted file mode 100644 index 09195f44..00000000 Binary files a/data/graphics/gui/target-cursor-red.png and /dev/null differ diff --git a/data/help/changes.txt b/data/help/changes.txt index f8a3eb67..dd062e49 100644 --- a/data/help/changes.txt +++ b/data/help/changes.txt @@ -3,99 +3,56 @@ ##3 === RECENT CHANGES === - 0.0.21 (17 September 2006) - - Added item pickup messages to the chat dialog - - Added XP bar to ministatus in the top left - - Added configurable smooth and lazy scrolling - - Added option to turn off the joystick - - Added --playername option for automatic character picking - - Added --configfile option for specifying which configuration file to use - - Added shortcut and middle mouse button for targetting nearest monster - - Added support for map effect overlays - - Fixed FPS limiter - - Fixed updating system on Windows - - Fixed player animations going out of sync on changing equipment or hairstyle - - Fixed SDL_image configure check on some systems by first checking for libpng - - Fixed big memory leak when using OpenGL - - Updated to work with Guichan 0.5.0 (older versions no longer supported) - - 0.0.20 (24 July 2006) - - Added new hairstyle, and some fixes to the old ones - - Added slider to set FPS limit - - Added visible equipments - - Added new maps and monsters - - Added female characters - - Implemented a new animation system - - Updated the updating system - - Reduced size of textures to stay within the limits of some OpenGL drivers - - Fixed connection not being shut down completely in case of an error - - Fixed min size of a window when resizing - - Fixed some maps issues - - Some fixes to monsters and player graphics - - Minor bug fixes and lots of code cleanups - - 0.0.19 (6 March 2006) - - - Added --username, --password and --defaults command line options - - Improved login sequence - - Enabled 3 slots to create players - - Improved setup window and added a joystick calibration tool - - Some maps fixes - - Reorganized and improved network code - - Fixed some bugs - - Made the player walk to items prior to picking them up - - Added new playerset - - Lots of cleanups and code re-roganization - - 0.0.18.1 (30 December 2005) - - - Fixed a drawing glitch with high tiles at the bottom of the screen - - Fixed glitches caused by fading out the damage display - - 0.0.18 (20 December 2005) - - - Added new items, npcs, tilesets, maps and monsters - - Non blocking connection at startup - - Enabled monster emotions - - Client version is now displayed during login - - Fixed setup window behaviour - - Fixed a Windows crash issue - - Fixed ScrollArea and BrowserBox behaviour - - Code cleanups - - 0.0.17 (10 October 2005) - - - Added remembering of window position and sizes - - Added taking screenshot with Alt+P - - Added notice about the player being overweight - - Added time to chat messages - - Added messagebox on error for MacOS X - - Added new network layer based on SDL_net - - Added proper error message for when the map server goes offline - - Added more international characters to fixed and rpg fonts - - Improved damage text font, shadow is now translucent - - Improved GUI layout, new profile window - - Improved support for building on FreeBSD and MacOS X - - Improved tile engine to fix graphics glitches and make mapping easier - - Rearranged keyboard shortcuts - - Fixed items on map to be removed on map switch - - Fixed OpenGL checkbox in the setup window to be usable - - Cleaned up a lot of code - - 0.0.16 (04 September 2005) - - - Added inn and casino - - Improved status window - - Improved OpenGL support - - Removed lot of bugs - - Code cleanups - - 0.0.15 (31 July 2005) - - - Added dynamic updating of client data - - Added much better font for chat and names - - Added option not to use the custom mouse cursor - - Added joystick support - - Improved mouse attack by not walking while pressing shift - - Fixed items being shown as equipped in inventory although they are not + 0.0.23 (3 June 2007) + - Added a particle engine along with some particle effects + - Added a cursor to indicate targeted enemy + - Added new program icon + - Added a man page for UNIX like systems + - Added the --version command line parameter + - Improved MacOS X release + - Screenshots are now saved in the .tmw directory on UNIX like systems + - Magic pink is no longer used for transparency (fixes issues with that on Mac) + - Fixed difficulties with resizing windows + - Fixed misleading error message when connecting fails + - Fixed wrong error message when account name already exists + - Fixed crash when deleting a character + - Fixed error message when creating a new character fails + - Fixed updating problem when using scrollwheel to change shop selection + + 0.0.22.2 (17 February 2007) + - Updated to work with Guichan 0.6.1 + - Changed to new default server (server.themanaworld.org) + - Changed custom mouse cursor + - Fixed the issue where _M or _F is appended to the username + - Fixed problem with Cancel button in update dialog + + 0.0.22.1 (15 January 2007) + - Updated to work with Guichan 0.6.0 (older versions no longer supported) + - Fixed mouse coordinates in debug window + - Fixed clicking on GUI to cause the player to start walking sometimes + + 0.0.22 (24 December 2006) + - Added support for female-specific equipment graphics + - Added support for monster sounds + - Added item icons to buy/sell dialogs + - Enhanced character select dialog to show equipment + - Changed to new update host (http://updates.themanaworld.org) + - Worked around a Guichan exception thrown for mice with many buttons + - Changed mouse walk to keep following mouse while button is held down + - Extended font support for Ã¥ and Ã… + - Disabled RLE compression on all surfaces in software mode + - Fixed joystick setting not to show disabled when it's actually enabled + - Fixed money field to no longer hide below the bottom of the window + - Fixed pathfinding to allow walking through beings when they block your path + - Fixed an issue with NPC dialogs staying open after player respawn + + 0.0.21.1 (30 October 2006) + - Reload wallpaper after loading updates + - Added support for gzip compressed map layer data + - Added support for building with CMake + - Added slider to setup dialog for configuring overlay effect + - Fixed excessive unnecessary reloading of sprites + - Fixed problem with OpenGL related redefinition + - Fixed problems with hiding windows using h + - Fixed trade window positioning diff --git a/data/help/header.txt b/data/help/header.txt index 7311c111..b10ed991 100644 --- a/data/help/header.txt +++ b/data/help/header.txt @@ -2,7 +2,7 @@ ##1 T H E M A N A W O R L D ##1 ========================================== - ##2Version:##6 0.0.22.2 ##2Date:##317 February 2007 + ##2Version:##6 0.0.23 ##2Date:##33 June 2007 ##2 Website: http://themanaworld.org diff --git a/docs/Makefile.am b/docs/Makefile.am index 8b57d5bb..1ee9a9a6 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -1,6 +1,7 @@ man6_MANS = tmw.6 -EXTRA_DIST = packages.txt \ +EXTRA_DIST = $(man6_MANS) \ + packages.txt \ FAQ.txt \ HACKING.txt \ SOURCE/tmwdox.sh \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e28e235e..7a4da70d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,6 +47,8 @@ MARK_AS_ADVANCED(SDL_INCLUDE_DIR) MARK_AS_ADVANCED(SDL_LIBRARY) SET(SRCS + gui/widgets/resizegrip.cpp + gui/widgets/resizegrip.h gui/box.cpp gui/box.h gui/browserbox.cpp @@ -275,11 +277,15 @@ SET(SRCS utils/base64.cpp utils/base64.h utils/dtor.h + utils/fastsqrt.h + utils/minmax.h utils/tostring.h utils/xml.cpp utils/xml.h animatedsprite.cpp animatedsprite.h + animationparticle.cpp + animationparticle.h being.cpp being.h beingmanager.cpp @@ -304,6 +310,8 @@ SET(SRCS graphics.cpp graphics.h guichanfwd.h + imageparticle.cpp + imageparticle.h inventory.cpp inventory.h item.cpp @@ -326,6 +334,10 @@ SET(SRCS npc.h openglgraphics.cpp openglgraphics.h + particle.cpp + particle.h + particleemitter.cpp + particleemitter.h player.cpp player.h properties.h @@ -335,6 +347,8 @@ SET(SRCS sound.cpp sound.h sprite.h + textparticle.cpp + textparticle.h tileset.h ) diff --git a/src/Makefile.am b/src/Makefile.am index f1f51b79..92c1b1b2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,6 +3,8 @@ AUTOMAKE_OPTIONS = subdir-objects bin_PROGRAMS = tmw tmw_SOURCES = gui/widgets/dropdown.cpp \ gui/widgets/dropdown.h \ + gui/widgets/resizegrip.cpp \ + gui/widgets/resizegrip.h \ gui/browserbox.cpp \ gui/browserbox.h \ gui/buddywindow.cpp \ @@ -229,11 +231,15 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ utils/base64.cpp \ utils/base64.h \ utils/dtor.h \ + utils/fastsqrt.h \ + utils/minmax.h \ utils/tostring.h \ utils/xml.cpp \ utils/xml.h \ animatedsprite.cpp \ animatedsprite.h \ + animationparticle.cpp \ + animationparticle.h \ being.cpp \ being.h \ beingmanager.cpp \ @@ -258,6 +264,8 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ graphics.cpp \ graphics.h \ guichanfwd.h \ + imageparticle.cpp \ + imageparticle.h \ inventory.cpp \ inventory.h \ item.cpp \ @@ -280,15 +288,21 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ npc.h \ openglgraphics.cpp\ openglgraphics.h \ + particle.cpp \ + particle.h \ + particleemitter.cpp \ + particleemitter.h \ player.cpp \ player.h \ properties.h \ serverinfo.h \ simpleanimation.cpp \ - simpleanimation.h \ + simpleanimation.h \ sound.cpp \ sound.h \ sprite.h \ + textparticle.cpp \ + textparticle.h \ tileset.h # set the include path found by configure diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp index 7260a512..c1e89ff0 100644 --- a/src/animatedsprite.cpp +++ b/src/animatedsprite.cpp @@ -197,3 +197,27 @@ AnimatedSprite::setDirection(SpriteDirection direction) } } } + +int +AnimatedSprite::getWidth() const +{ + if (mFrame) + { + return mFrame->image->getWidth(); + } + else { + return 0; + } +} + +int +AnimatedSprite::getHeight() const +{ + if (mFrame) + { + return mFrame->image->getHeight(); + } + else { + return 0; + } +} diff --git a/src/animatedsprite.h b/src/animatedsprite.h index 2257c0f0..42c0a743 100644 --- a/src/animatedsprite.h +++ b/src/animatedsprite.h @@ -85,6 +85,18 @@ class AnimatedSprite bool draw(Graphics* graphics, int posX, int posY) const; + /** + * gets the width in pixels of the image of the current frame + */ + int + getWidth() const; + + /** + * gets the height in pixels of the image of the current frame + */ + int + getHeight() const; + /** * Sets the direction. */ diff --git a/src/animationparticle.cpp b/src/animationparticle.cpp new file mode 100644 index 00000000..30c33da7 --- /dev/null +++ b/src/animationparticle.cpp @@ -0,0 +1,51 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "animationparticle.h" + +#include "graphics.h" +#include "simpleanimation.h" + +AnimationParticle::AnimationParticle(Map *map, Animation *animation): + ImageParticle(map, 0), + mAnimation(new SimpleAnimation(animation)) +{ +} + +AnimationParticle::AnimationParticle(Map *map, xmlNodePtr animationNode): + ImageParticle(map, 0), + mAnimation(new SimpleAnimation(animationNode)) +{ +} + +AnimationParticle::~AnimationParticle() +{ + delete mAnimation; +} + +bool AnimationParticle::update() +{ + mAnimation->update(10); // particle engine is updated every 10ms + mImage = mAnimation->getCurrentImage(); + + return Particle::update(); +} diff --git a/src/animationparticle.h b/src/animationparticle.h new file mode 100644 index 00000000..054b1b73 --- /dev/null +++ b/src/animationparticle.h @@ -0,0 +1,49 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ANIMATION_PARTICLE +#define _ANIMATION_PARTICLE + +#include + +#include "imageparticle.h" + +class Animation; +class Map; +class SimpleAnimation; + +class AnimationParticle : public ImageParticle +{ + public: + AnimationParticle(Map *map, Animation *animation); + + AnimationParticle(Map *map, xmlNodePtr animationNode); + + ~AnimationParticle(); + + virtual bool update(); + + private: + SimpleAnimation *mAnimation; /**< Used animation for this particle */ +}; + +#endif diff --git a/src/being.cpp b/src/being.cpp index 682daddb..7ba9ddb9 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -32,12 +32,16 @@ #include "graphics.h" #include "log.h" #include "map.h" +#include "particle.h" #include "resources/resourcemanager.h" #include "resources/imageset.h" #include "gui/gui.h" +#include "resources/resourcemanager.h" +#include "resources/imageset.h" + #include "utils/dtor.h" #include "utils/tostring.h" @@ -61,7 +65,6 @@ Being::Being(Uint16 id, Uint16 job, Map *map): mMap(NULL), mHairStyle(0), mHairColor(0), mSpeechTime(0), - mDamageTime(0), mPx(0), mPy(0), mSprites(VECTOREND_SPRITE, NULL), mEquipmentSpriteIDs(VECTOREND_SPRITE, 0) @@ -85,6 +88,13 @@ Being::~Being() clearPath(); setMap(NULL); + for ( std::list::iterator i = mChildParticleEffects.begin(); + i != mChildParticleEffects.end(); + i++) + { + (*i)->kill(); + } + instances--; if (instances == 0) @@ -292,8 +302,32 @@ Being::setSpeech(const std::string &text, Uint32 time) void Being::takeDamage(int amount) { - mDamage = amount ? toString(amount) : "miss"; - mDamageTime = 300; + gcn::Font* font; + std::string damage = amount ? toString(amount) : "miss"; + + // Selecting the right color + if (damage == "miss") + { + font = hitYellowFont; + } + else + { + // hit particle effect + controlParticle(particleEngine->addEffect("graphics/particles/hit.particle.xml", 0, 0)); + + if (getType() == MONSTER) + { + font = hitBlueFont; + } + else + { + font = hitRedFont; + } + } + + // show damage number + particleEngine->addTextSplashEffect(damage, 255, 255, 255, font, + mPx + 16, mPy + 16); } void @@ -318,6 +352,19 @@ Being::setMap(Map *map) { mSpriteIterator = mMap->addSprite(this); } + + //clear particle effect list because child particles became invalid + mChildParticleEffects.clear(); +} + +void +Being::controlParticle(Particle *particle) +{ + if (particle) + { + particle->disableAutoDelete(); //the effect may not die without the beings permission or we segvault + mChildParticleEffects.push_back(particle); + } } void @@ -465,10 +512,6 @@ Being::logic() if (mSpeechTime > 0) mSpeechTime--; - // Reduce the time that damage is still displayed - if (mDamageTime > 0) - mDamageTime--; - // Update pixel coordinates mPx = mX - 16 + getXOffset(); mPy = mY - 16 + getYOffset(); @@ -489,6 +532,14 @@ Being::logic() mSprites[i]->update(tick_time * 10); } } + + //Update particle effects + for ( std::list::iterator i = mChildParticleEffects.begin(); + i != mChildParticleEffects.end(); + i++) + { + (*i)->setPosition((float)mPx + 16.0f, (float)mPy + 32.0f); + } } void @@ -531,37 +582,6 @@ Being::drawSpeech(Graphics *graphics, int offsetX, int offsetY) graphics->setColor(gcn::Color(255, 255, 255)); graphics->drawText(mSpeech, px + 18, py - 60, gcn::Graphics::CENTER); } - - // Draw damage above this being - if (mDamageTime > 0 && mDamageTime < 275) - { - // Selecting the right color - if (mDamage == "miss") - { - graphics->setFont(hitYellowFont); - } - else if (getType() == MONSTER) - { - graphics->setFont(hitBlueFont); - } - else - { - graphics->setFont(hitRedFont); - } - - int textY = (getType() == MONSTER) ? 32 : 70; - int ft = 150 - mDamageTime; - float a = (ft > 0) ? 1.0 - ft / 150.0 : 1.0; - - graphics->setColor(gcn::Color(255, 255, 255, (int)(255 * a))); - graphics->drawText(mDamage, - px + 16, - py - textY - (300 - mDamageTime) / 10, - gcn::Graphics::CENTER); - - // Reset alpha value - graphics->setColor(gcn::Color(255, 255, 255)); - } } Being::Type @@ -632,3 +652,29 @@ int Being::getOffset(int step) const return offset; } + + +int +Being::getWidth() const +{ + if (mSprites[BASE_SPRITE]) + { + return mSprites[BASE_SPRITE]->getWidth(); + } + else { + return 0; + } +} + + +int +Being::getHeight() const +{ + if (mSprites[BASE_SPRITE]) + { + return mSprites[BASE_SPRITE]->getHeight(); + } + else { + return 0; + } +} diff --git a/src/being.h b/src/being.h index 332f1b4a..8820c30a 100644 --- a/src/being.h +++ b/src/being.h @@ -42,6 +42,7 @@ class Item; class Map; class Graphics; class ImageSet; +class Particle; /** * A position along a being's path. @@ -97,6 +98,13 @@ class Being : public Sprite VECTOREND_SPRITE }; + enum TargetCursorSize { + TC_SMALL = 0, + TC_MEDIUM, + TC_LARGE, + NUM_TC + }; + /** * Directions, to be used as bitmask values @@ -359,8 +367,33 @@ class Being : public Sprite int getYOffset() const { return getOffset(mStepY); } + /** + * Returns the horizontal size of the current base sprite of the being + */ + virtual int + getWidth() const; + + /** + * Returns the vertical size of the current base sprite of the being + */ + virtual int + getHeight() const; + + /** + * Returns the required size of a target cursor for this being + */ + virtual Being::TargetCursorSize + getTargetCursorSize() const + { return TC_MEDIUM; } + std::auto_ptr mEquipment; + /** + * Take control of a particle + */ + void + controlParticle(Particle *particle); + protected: /** * Sets the new path for this being. @@ -380,14 +413,13 @@ class Being : public Sprite Path mPath; std::string mSpeech; - std::string mDamage; Uint16 mHairStyle, mHairColor; Uint32 mSpeechTime; - Uint32 mDamageTime; Sint32 mPx, mPy; /**< Pixel coordinates */ std::vector mSprites; std::vector mEquipmentSpriteIDs; + std::list mChildParticleEffects; private: int diff --git a/src/engine.cpp b/src/engine.cpp index 31bec9ff..3b5fb403 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -35,6 +35,7 @@ #include "localplayer.h" #include "log.h" #include "map.h" +#include "particle.h" #include "sound.h" #include "gui/gui.h" @@ -63,6 +64,7 @@ void Engine::changeMap(const std::string &mapPath) floorItemManager->clear(); beingManager->clear(); + particleEngine->clear(); // Store full map path in global var map_path = "maps/" + mapPath; @@ -83,8 +85,12 @@ void Engine::changeMap(const std::string &mapPath) } minimap->setMapImage(mapImage); beingManager->setMap(newMap); + particleEngine->setMap(newMap); viewport->setMap(newMap); + // Initialize map-based particle effects + newMap->initializeParticleEffects(particleEngine); + // Start playing new music file when necessary std::string oldMusic = ""; @@ -106,5 +112,6 @@ void Engine::changeMap(const std::string &mapPath) void Engine::logic() { beingManager->logic(); + particleEngine->update(); gui->logic(); } diff --git a/src/game.cpp b/src/game.cpp index ba4e2b9d..1afc530b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -41,6 +41,7 @@ #include "localplayer.h" #include "log.h" #include "npc.h" +#include "particle.h" #include "gui/buy.h" #include "gui/buysell.h" @@ -121,6 +122,8 @@ BeingManager *beingManager = NULL; FloorItemManager *floorItemManager = NULL; ChannelManager *channelManager = NULL; +Particle *particleEngine = NULL; + const int MAX_TIME = 10000; /** @@ -242,6 +245,9 @@ Game::Game(): floorItemManager = new FloorItemManager(); channelManager = new ChannelManager(); + particleEngine = new Particle(NULL); + particleEngine->setupEngine(); + // Initialize timers tick_time = 0; mLogicCounterId = SDL_AddTimer(10, nextTick, NULL); //Logic counter @@ -286,6 +292,7 @@ Game::~Game() delete floorItemManager; delete channelManager; delete joystick; + delete particleEngine; beingManager = NULL; floorItemManager = NULL; @@ -308,7 +315,9 @@ bool saveScreenshot(SDL_Surface *screenshot) screenshotCount++; filename.str(""); #if (defined __USE_UNIX98 || defined __FreeBSD__ || defined __APPLE__) - filename << PHYSFS_getUserDir() << "/"; + filename << PHYSFS_getUserDir() << ".tmw/"; +#elif defined __APPLE__ + filename << PHYSFS_getUserDir() << "Desktop/"; #endif filename << "TMW_Screenshot_" << screenshotCount << ".png"; testExists.open(filename.str().c_str(), std::ios::in); @@ -316,7 +325,18 @@ bool saveScreenshot(SDL_Surface *screenshot) testExists.close(); } while (!found); - return ImageWriter::writePNG(screenshot, filename.str()); + if (ImageWriter::writePNG(screenshot, filename.str())) + { + std::stringstream chatlogentry; + chatlogentry << "Screenshot saved to " << filename.str().c_str(); + chatWindow->chatLog(chatlogentry.str(), BY_SERVER); + return true; + } + else + { + chatWindow->chatLog("Saving screenshot failed!", BY_SERVER); + return false; + } } void Game::optionChanged(const std::string &name) diff --git a/src/graphics.cpp b/src/graphics.cpp index f007470a..1e31f903 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -136,8 +136,6 @@ bool Graphics::drawImage(Image *image, int srcX, int srcY, int dstX, int dstY, srcX += image->mBounds.x; srcY += image->mBounds.y; - - SDL_Rect dstRect; SDL_Rect srcRect; dstRect.x = dstX; dstRect.y = dstY; diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp index cb07da22..2a8616f8 100644 --- a/src/gui/buy.cpp +++ b/src/gui/buy.cpp @@ -111,27 +111,21 @@ void BuyDialog::setMoney(int amount) { mMoney = amount; mShopItemList->setPlayersMoney(amount); - mMoneyLabel->setCaption("Price: 0 GP / " + toString(mMoney) + " GP"); - mMoneyLabel->adjustSize(); + + updateButtonsAndLabels(); } void BuyDialog::reset() { mShopItems->clear(); + mShopItemList->adjustSize(); mMoney = 0; mSlider->setValue(0.0); - mAmountItems = 0; // Reset Previous Selected Items to prevent failing asserts mShopItemList->setSelected(-1); - mIncreaseButton->setEnabled(false); - mDecreaseButton->setEnabled(false); - mQuantityLabel->setCaption("0"); - mQuantityLabel->adjustSize(); - mMoneyLabel->setCaption("Price: 0 GP / " + toString(mMoney) + " GP"); - mMoneyLabel->adjustSize(); - mItemDescLabel->setCaption(""); - mItemEffectLabel->setCaption(""); + + updateButtonsAndLabels(); } void BuyDialog::addItem(short id, int price) @@ -151,45 +145,36 @@ void BuyDialog::action(const gcn::ActionEvent &event) } // The following actions require a valid selection - if (selectedItem < 0 || selectedItem >= int(mShopItems->getNumberOfElements())) + if (selectedItem < 0 || + selectedItem >= (int) mShopItems->getNumberOfElements()) { return; } - bool updateButtonsAndLabels = false; - if (event.getId() == "slider") { mAmountItems = (int)(mSlider->getValue() * mMaxItems); - updateButtonsAndLabels = true; + updateButtonsAndLabels(); } - else if (event.getId() == "+") + else if (event.getId() == "+" && mAmountItems < mMaxItems) { - if (mAmountItems < mMaxItems) { - mAmountItems++; - } else { - mAmountItems = mMaxItems; - } + mAmountItems++; - mSlider->setValue(double(mAmountItems)/double(mMaxItems)); - updateButtonsAndLabels = true; + mSlider->setValue((double) mAmountItems / (double) mMaxItems); + updateButtonsAndLabels(); } - else if (event.getId() == "-") + else if (event.getId() == "-" && mAmountItems > 0) { - if (mAmountItems > 0) { - mAmountItems--; - } else { - mAmountItems = 0; - } + mAmountItems--; - mSlider->setValue(double(mAmountItems)/double(mMaxItems)); - updateButtonsAndLabels = true; + mSlider->setValue((double) mAmountItems / (double) mMaxItems); + updateButtonsAndLabels(); } // TODO: Actually we'd have a bug elsewhere if this check for the number // of items to be bought ever fails, Bertram removed the assertions, is // there a better way to ensure this fails in an _obivous_ way in C++? - else if (event.getId() == "buy" && (mAmountItems > 0 && - mAmountItems <= mMaxItems)) + else if (event.getId() == "buy" && mAmountItems > 0 && + mAmountItems <= mMaxItems) { // XXX Convert for new server /* @@ -199,38 +184,15 @@ void BuyDialog::action(const gcn::ActionEvent &event) outMsg.writeShort(mShopItems->at(selectedItem).id); */ - // update money ! + // Update money and adjust the max number of items that can be bought mMoney -= mAmountItems * mShopItems->at(selectedItem).price; - // Update number of items that can be bought at max mMaxItems -= mAmountItems; - if (!mMaxItems) { - mSlider->setEnabled(false); - } - // Reset selection mAmountItems = 0; - mSlider->setValue(0); - - updateButtonsAndLabels = true; - } + mSlider->setValue(0.0); - // If anything has changed, we have to update the buttons and labels - if (updateButtonsAndLabels) - { - // Update buttons - mIncreaseButton->setEnabled(mAmountItems < mMaxItems); - mDecreaseButton->setEnabled(mAmountItems > 0); - mBuyButton->setEnabled(mAmountItems > 0); - - // Update labels - mQuantityLabel->setCaption(toString(mAmountItems)); - mQuantityLabel->adjustSize(); - - int price = mAmountItems * mShopItems->at(selectedItem).price; - mMoneyLabel->setCaption("Price: " + toString(price) + " GP / " - + toString(mMoney) + " GP" ); - mMoneyLabel->adjustSize(); + updateButtonsAndLabels(); } } @@ -238,17 +200,16 @@ void BuyDialog::selectionChanged(const SelectionEvent &event) { // Reset amount of items and update labels mAmountItems = 0; - mSlider->setValue(0); - mQuantityLabel->setCaption("0"); - mQuantityLabel->adjustSize(); - mMoneyLabel->setCaption("Price: 0 GP / " + toString(mMoney) + " GP"); - mMoneyLabel->adjustSize(); + mSlider->setValue(0.0); - // Disable buttons for buying and decreasing - mBuyButton->setEnabled(false); - mDecreaseButton->setEnabled(false); + updateButtonsAndLabels(); +} +void +BuyDialog::updateButtonsAndLabels() +{ int selectedItem = mShopItemList->getSelected(); + int price = 0; if (selectedItem > -1) { @@ -259,16 +220,32 @@ void BuyDialog::selectionChanged(const SelectionEvent &event) // Calculate how many the player can afford mMaxItems = mMoney / mShopItems->at(selectedItem).price; + if (mAmountItems > mMaxItems) + { + mAmountItems = mMaxItems; + } + + // Calculate price of pending purchase + price = mAmountItems * mShopItems->at(selectedItem).price; } else { mItemDescLabel->setCaption("Description:"); mItemEffectLabel->setCaption("Effect:"); mMaxItems = 0; + mAmountItems = 0; } - // When at least one item can be bought, enable the slider and the - // increase button - mIncreaseButton->setEnabled(mMaxItems > 0); + // Enable or disable buttons and slider + mIncreaseButton->setEnabled(mAmountItems < mMaxItems); + mDecreaseButton->setEnabled(mAmountItems > 0); + mBuyButton->setEnabled(mAmountItems > 0); mSlider->setEnabled(mMaxItems > 0); + + // Update quantity and money labels + mQuantityLabel->setCaption(toString(mAmountItems)); + mQuantityLabel->adjustSize(); + mMoneyLabel->setCaption("Price: " + toString(price) + " GP / " + + toString(mMoney - price) + " GP" ); + mMoneyLabel->adjustSize(); } diff --git a/src/gui/buy.h b/src/gui/buy.h index 13116b6e..7834a434 100644 --- a/src/gui/buy.h +++ b/src/gui/buy.h @@ -92,6 +92,12 @@ class BuyDialog : public Window, public gcn::ActionListener, SelectionListener */ std::string getElementAt(int i); + /** + * Updates the state of buttons and labels. + */ + void + updateButtonsAndLabels(); + private: gcn::Button *mBuyButton; gcn::Button *mQuitButton; diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp index eb6b7612..48df9efe 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -160,7 +160,7 @@ ChatWindow::chatLog(std::string line, int own, std::string channelName) break; case BY_OTHER: tmp.nick += CAT_NORMAL; - lineColor = "##4"; // Equiv. to BrowserBox::ORANGE + lineColor = "##0"; // Equiv. to BrowserBox::BLACK break; case BY_SERVER: tmp.nick += std::string("Server: "); @@ -195,7 +195,7 @@ ChatWindow::chatLog(std::string line, int own, std::string channelName) // We look if the Vertical Scroll Bar is set at the max before // adding a row, otherwise the max will always be a row higher // at comparison. - if (mScrollArea->getVerticalScrollAmount() == mScrollArea->getVerticalMaxScroll() ) + if (mScrollArea->getVerticalScrollAmount() == mScrollArea->getVerticalMaxScroll()) { mTextOutput->addRow(line); mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); diff --git a/src/gui/chat.h b/src/gui/chat.h index c7e51ebf..6f9b91fe 100644 --- a/src/gui/chat.h +++ b/src/gui/chat.h @@ -168,13 +168,13 @@ class ChatWindow : public Window, public gcn::ActionListener, /* * Determines whether to send a command or an ordinary message, then - * contructs packets & sends them + * contructs packets & sends them. * * @param nick The character's name to display in front. * @param msg The message text which is to be send. * * NOTE: - * the nickname is required by the server, if not specified + * The nickname is required by the server, if not specified * the message may not be sent unless a command was intended * which requires another packet to be constructed! you can * achieve this by putting a slash ("/") infront of the diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp index 563f380f..ebf7d974 100644 --- a/src/gui/debugwindow.cpp +++ b/src/gui/debugwindow.cpp @@ -33,6 +33,7 @@ #include "../game.h" #include "../engine.h" +#include "../particle.h" #include "../map.h" #include "../utils/tostring.h" @@ -58,6 +59,9 @@ DebugWindow::DebugWindow(): mTileMouseLabel = new gcn::Label("[Mouse: 0, 0]"); mTileMouseLabel->setPosition(100, 0); + mParticleCountLabel = new gcn::Label("[Particle count: 0]"); + mParticleCountLabel->setPosition(100, 60); + Button *closeButton = new Button("Close", "close", this); closeButton->setPosition(5, 60); @@ -65,6 +69,7 @@ DebugWindow::DebugWindow(): add(mMusicFileLabel); add(mMapFileLabel); add(mTileMouseLabel); + add(mParticleCountLabel); add(closeButton); } @@ -97,6 +102,11 @@ DebugWindow::logic() mMapFileLabel->setCaption(minimap); mMapFileLabel->adjustSize(); } + + mParticleCountLabel->setCaption("[Particle count: " + + toString(Particle::particleCount) + +"]"); + mParticleCountLabel->adjustSize(); } void diff --git a/src/gui/debugwindow.h b/src/gui/debugwindow.h index 4fd33d83..d082b2ca 100644 --- a/src/gui/debugwindow.h +++ b/src/gui/debugwindow.h @@ -58,6 +58,7 @@ class DebugWindow : public Window, public gcn::ActionListener private: gcn::Label *mMusicFileLabel, *mMapFileLabel; gcn::Label *mTileMouseLabel, *mFPSLabel; + gcn::Label *mParticleCountLabel; }; #endif diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index 44d042a6..2018c75a 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -165,8 +165,8 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event) if (!item) return; - /* Convert relative to the window coordinates to - * absolute screen coordinates. + /* Convert relative to the window coordinates to absolute screen + * coordinates. */ int mx = event.getX() + getX(); int my = event.getY() + getY(); @@ -178,7 +178,8 @@ void InventoryWindow::mouseDragged(gcn::MouseEvent &event) { int tmpWidth = getWidth(), tmpHeight = getHeight(); Window::mouseDragged(event); - if (getWidth() != tmpWidth || getHeight() != tmpHeight) { + if (getWidth() != tmpWidth || getHeight() != tmpHeight) + { updateWidgets(); } } diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index c9878c84..478371b1 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -88,7 +88,7 @@ SellDialog::SellDialog(): quitButton->setPosition(208, 186); mShopItemList->setActionEventId("item"); - mSlider->setActionEventId("mSlider"); + mSlider->setActionEventId("slider"); mShopItemList->setPriceCheck(false); @@ -119,20 +119,11 @@ void SellDialog::reset() { mShopItems->clear(); mSlider->setValue(0.0); - mAmountItems = 0; - - mQuantityLabel->setCaption("0"); - mQuantityLabel->adjustSize(); - mMoneyLabel->setCaption("Money: 0 GP / Total: " - + toString(mPlayerMoney) + " GP"); - mMoneyLabel->adjustSize(); - mItemDescLabel->setCaption(""); - mItemEffectLabel->setCaption(""); - // Reset Previous Selected Items to prevent failing asserts + // Reset previous selected item to prevent failing asserts mShopItemList->setSelected(-1); - mIncreaseButton->setEnabled(false); - mDecreaseButton->setEnabled(false); + + updateButtonsAndLabels(); } void SellDialog::addItem(Item *item, int price) @@ -162,25 +153,7 @@ void SellDialog::action(const gcn::ActionEvent &event) { mAmountItems = 0; mSlider->setValue(0); - mDecreaseButton->setEnabled(false); - mSellButton->setEnabled(false); - - mQuantityLabel->adjustSize(); - mMoneyLabel->setCaption("Money: 0 GP / Total: " - + toString(mPlayerMoney) + " GP"); - mMoneyLabel->adjustSize(); - - if (selectedItem > -1) { - mSlider->setEnabled(true); - mIncreaseButton->setEnabled(true); - mMaxItems = mShopItems->at(selectedItem).quantity; - mQuantityLabel->setCaption("0 / " + toString(mMaxItems)); - } else { - mSlider->setEnabled(false); - mIncreaseButton->setEnabled(false); - mQuantityLabel->setCaption("0"); - } - mQuantityLabel->adjustSize(); + updateButtonsAndLabels(); } else if (event.getId() == "quit") { @@ -189,40 +162,35 @@ void SellDialog::action(const gcn::ActionEvent &event) } // The following actions require a valid item selection - if (selectedItem == -1 || selectedItem >= int(mShopItems->getNumberOfElements())) { + if (selectedItem == -1 || + selectedItem >= (int) mShopItems->getNumberOfElements()) + { return; } - bool updateButtonsAndLabels = false; - - if (event.getId() == "mSlider") + if (event.getId() == "slider") { - mAmountItems = (int)(mSlider->getValue() * mMaxItems); - - updateButtonsAndLabels = true; + mAmountItems = (int) (mSlider->getValue() * mMaxItems); + updateButtonsAndLabels(); } - else if (event.getId() == "+") + else if (event.getId() == "+" && mAmountItems < mMaxItems) { - assert(mAmountItems < mMaxItems); mAmountItems++; - mSlider->setValue(double(mAmountItems)/double(mMaxItems)); - updateButtonsAndLabels = true; + mSlider->setValue((double) mAmountItems /(double) mMaxItems); + updateButtonsAndLabels(); } - else if (event.getId() == "-") + else if (event.getId() == "-" && mAmountItems > 0) { - assert(mAmountItems > 0); mAmountItems--; - mSlider->setValue(double(mAmountItems)/double(mMaxItems)); - - updateButtonsAndLabels = true; + mSlider->setValue((double) mAmountItems / (double) mMaxItems); + updateButtonsAndLabels(); } - else if (event.getId() == "sell") + else if (event.getId() == "sell" && mAmountItems > 0 + && mAmountItems <= mMaxItems) { // Attempt sell - assert(mAmountItems > 0 && mAmountItems <= mMaxItems); - // XXX Convert for new server /* MessageOut outMsg(CMSG_NPC_SELL_REQUEST); @@ -236,60 +204,77 @@ void SellDialog::action(const gcn::ActionEvent &event) mPlayerMoney += (mAmountItems * mShopItems->at(selectedItem).price); mAmountItems = 0; mSlider->setValue(0); - mSlider->setEnabled(mMaxItems != 0); - - // All were sold - if (!mMaxItems) { + if (!mMaxItems) + { + // All were sold mShopItemList->setSelected(-1); - mShopItems->getShop()->erase(mShopItems->getShop()->begin() + selectedItem); + mShopItems->getShop()->erase( + mShopItems->getShop()->begin() + selectedItem); + } + else + { + // Update only when there are items left, the entry doesn't exist + // otherwise and can't be updated + updateButtonsAndLabels(); } - - // Update only when there are items left, the entry doesn't exist - // otherwise and can't be updated - updateButtonsAndLabels = bool(mMaxItems); - } - - // If anything changed, we need to update the buttons and labels - if (updateButtonsAndLabels) - { - // Update labels - mQuantityLabel->setCaption(toString(mAmountItems) + " / " + toString(mMaxItems)); - mQuantityLabel->adjustSize(); - - int price = mAmountItems * mShopItems->at(selectedItem).price; - mMoneyLabel->setCaption("Money: " + toString(price) + " GP / Total: " - + toString(price + mPlayerMoney) + " GP"); - mMoneyLabel->adjustSize(); - - // Update Buttons - mSellButton->setEnabled(mAmountItems > 0); - mDecreaseButton->setEnabled(mAmountItems > 0); - mIncreaseButton->setEnabled(mAmountItems < mMaxItems); } } void SellDialog::selectionChanged(const SelectionEvent &event) +{ + // Reset amount of items and update labels + mAmountItems = 0; + mSlider->setValue(0); + + updateButtonsAndLabels(); +} + +void SellDialog::setMoney(int amount) +{ + mPlayerMoney = amount; + mShopItemList->setPlayersMoney(amount); +} + +void +SellDialog::updateButtonsAndLabels() { int selectedItem = mShopItemList->getSelected(); + int income = 0; if (selectedItem > -1) { - const ItemInfo &info = - ItemDB::get(mShopItems->at(selectedItem).id); + mMaxItems = mShopItems->at(selectedItem).quantity; + if (mAmountItems > mMaxItems) + { + mAmountItems = mMaxItems; + } + income = mAmountItems * mShopItems->at(selectedItem).price; + + const ItemInfo &info = ItemDB::get(mShopItems->at(selectedItem).id); mItemDescLabel->setCaption("Description: " + info.getDescription()); mItemEffectLabel->setCaption("Effect: " + info.getEffect()); } else { - mItemDescLabel->setCaption("Description"); - mItemEffectLabel->setCaption("Effect"); + mMaxItems = 0; + mAmountItems = 0; + mItemDescLabel->setCaption("Description:"); + mItemEffectLabel->setCaption("Effect:"); } -} -void SellDialog::setMoney(int amount) -{ - mPlayerMoney = amount; - mShopItemList->setPlayersMoney(amount); + // Update Buttons and slider + mSellButton->setEnabled(mAmountItems > 0); + mDecreaseButton->setEnabled(mAmountItems > 0); + mIncreaseButton->setEnabled(mAmountItems < mMaxItems); + mSlider->setEnabled(selectedItem > -1); + + // Update the quantity and money labels + mQuantityLabel->setCaption( + toString(mAmountItems) + " / " + toString(mMaxItems)); + mQuantityLabel->adjustSize(); + mMoneyLabel->setCaption("Money: " + toString(income) + " GP / Total: " + + toString(mPlayerMoney + income) + " GP"); + mMoneyLabel->adjustSize(); } diff --git a/src/gui/sell.h b/src/gui/sell.h index 68bd7b8b..b8385a6f 100644 --- a/src/gui/sell.h +++ b/src/gui/sell.h @@ -82,6 +82,12 @@ class SellDialog : public Window, gcn::ActionListener, SelectionListener */ void setMoney(int amount); + /** + * Updates the state of buttons and labels. + */ + void + updateButtonsAndLabels(); + private: gcn::Button *mSellButton; gcn::Button *mIncreaseButton; diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index d8130cd3..ed75e5b3 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -157,6 +157,7 @@ void UpdaterWindow::setLabel(const std::string &str) void UpdaterWindow::enable() { + mCancelButton->setEnabled(false); mPlayButton->setEnabled(true); mPlayButton->requestFocus(); } @@ -168,11 +169,7 @@ void UpdaterWindow::action(const gcn::ActionEvent &event) // Register the user cancel mUserCancel = true; // Skip the updating process - if (mDownloadStatus == UPDATE_COMPLETE) - { - state = STATE_EXIT; - } - else + if (mDownloadStatus != UPDATE_COMPLETE) { mDownloadStatus = UPDATE_ERROR; } diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index f3e9031c..2af1d960 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -41,10 +41,13 @@ #include "../resources/animation.h" #include "../resources/monsterinfo.h" #include "../resources/resourcemanager.h" +#include "../resources/image.h" #include "../resources/imageset.h" #include "../utils/tostring.h" +#include + Viewport::Viewport(): mMap(0), mViewX(0.0f), @@ -67,37 +70,62 @@ Viewport::Viewport(): mPopupMenu = new PopupMenu(); // Load target cursors + loadTargetCursor("graphics/gui/target-cursor-blue-s.png", 44, 35, + false, Being::TC_SMALL); + loadTargetCursor("graphics/gui/target-cursor-red-s.png", 44, 35, + true, Being::TC_SMALL); + loadTargetCursor("graphics/gui/target-cursor-blue-m.png", 62, 44, + false, Being::TC_MEDIUM); + loadTargetCursor("graphics/gui/target-cursor-red-m.png", 62, 44, + true, Being::TC_MEDIUM); + loadTargetCursor("graphics/gui/target-cursor-blue-l.png", 82, 60, + false, Being::TC_LARGE); + loadTargetCursor("graphics/gui/target-cursor-red-l.png", 82, 60, + true, Being::TC_LARGE); +} + +void +Viewport::loadTargetCursor(std::string filename, int width, int height, + bool outRange, Being::TargetCursorSize size) +{ + assert(size > -1); + assert(size < 3); + + ImageSet* currentImageSet; + SimpleAnimation* currentCursor; + ResourceManager *resman = ResourceManager::getInstance(); - mInRangeImages = resman->getImageSet( - "graphics/gui/target-cursor-blue.png", 44, 35); - mOutRangeImages = resman->getImageSet( - "graphics/gui/target-cursor-red.png", 44, 35); - Animation *animInRange = new Animation(); - Animation *animOutRange = new Animation(); - - for (unsigned int i = 0; i < mInRangeImages->size(); ++i) + + currentImageSet = resman->getImageSet(filename, width, height); + Animation *anim = new Animation(); + for (unsigned int i = 0; i < currentImageSet->size(); ++i) { - animInRange->addFrame(mInRangeImages->get(i), 75, 0, 0); + anim->addFrame(currentImageSet->get(i), 75, 0, 0); } + currentCursor = new SimpleAnimation(anim); - for (unsigned int j = 0; j < mOutRangeImages->size(); ++j) + if (outRange) { - animOutRange->addFrame(mOutRangeImages->get(j), 75, 0, 0); + mOutRangeImages[size] = currentImageSet; + mTargetCursorOutRange[size] = currentCursor; + } + else { + mInRangeImages[size] = currentImageSet; + mTargetCursorInRange[size] = currentCursor; } - - mTargetCursorInRange = new SimpleAnimation(animInRange); - mTargetCursorOutRange = new SimpleAnimation(animOutRange); } Viewport::~Viewport() { delete mPopupMenu; - delete mTargetCursorInRange; - delete mTargetCursorOutRange; - - mInRangeImages->decRef(); - mOutRangeImages->decRef(); + for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++) + { + delete mTargetCursorInRange[i]; + delete mTargetCursorOutRange[i]; + mInRangeImages[i]->decRef(); + mOutRangeImages[i]->decRef(); + } } void @@ -259,8 +287,11 @@ Viewport::logic() mWalkTime = player_node->mWalkTime; } - mTargetCursorInRange->update(10); - mTargetCursorOutRange->update(10); + for (int i = 0; i < 3; i++) + { + mTargetCursorInRange[i]->update(10); + mTargetCursorOutRange[i]->update(10); + } } void @@ -270,26 +301,31 @@ Viewport::drawTargetCursor(Graphics *graphics) Being *target = player_node->getTarget(); if (target) { + // Calculate target circle position + // Find whether target is in range int rangeX = abs(target->mX - player_node->mX); int rangeY = abs(target->mY - player_node->mY); int attackRange = player_node->getAttackRange(); - // Draw the target cursor, which one depends if the target is in range + // Get the correct target cursors graphic + Being::TargetCursorSize cursorSize = target->getTargetCursorSize(); + Image* targetCursor; if (rangeX > attackRange || rangeY > attackRange) { - // Draw the out of range cursor - graphics->drawImage(mTargetCursorOutRange->getCurrentImage(), - target->getPixelX() - mCameraX, - target->getPixelY() - mCameraY); + targetCursor = mTargetCursorOutRange[cursorSize]->getCurrentImage(); } - else - { - // Draw the in range cursor - graphics->drawImage(mTargetCursorInRange->getCurrentImage(), - target->getPixelX() - mCameraX, - target->getPixelY() - mCameraY); + else { + targetCursor = mTargetCursorInRange[cursorSize]->getCurrentImage(); } + + // Draw the target cursor at the correct position + int posX = target->getPixelX() + 16 - + targetCursor->getWidth() / 2 - mCameraX; + int posY = target->getPixelY() + 16 - + targetCursor->getHeight() / 2 - mCameraY; + + graphics->drawImage(targetCursor, posX, posY); } } @@ -304,10 +340,10 @@ Viewport::drawTargetName(Graphics *graphics) graphics->setColor(gcn::Color(255, 32, 32)); const MonsterInfo &mi = static_cast(target)->getInfo(); - graphics->drawText(mi.getName(), - target->getPixelX() - mCameraX + 15, - target->getPixelY() - mCameraY - 42, - gcn::Graphics::CENTER); + int posX = target->getPixelX() + 16 - mCameraX; + int posY = target->getPixelY() + 16 - target->getHeight() - mCameraY; + + graphics->drawText(mi.getName(), posX, posY, gcn::Graphics::CENTER); } } diff --git a/src/gui/viewport.h b/src/gui/viewport.h index 84efeff3..22d0f249 100644 --- a/src/gui/viewport.h +++ b/src/gui/viewport.h @@ -29,9 +29,9 @@ #include "windowcontainer.h" #include "../configlistener.h" +#include "../being.h" class Map; -class Being; class FloorItem; class ImageSet; class Item; @@ -141,6 +141,13 @@ class Viewport : public WindowContainer, public gcn::MouseListener, */ void showPopup(int x, int y, Being *being); + /** + * Helper function for loading target cursors + */ + void + loadTargetCursor(std::string filename, int width, int height, + bool outRange, Being::TargetCursorSize size); + /** * Draws range based target cursor */ @@ -164,14 +171,17 @@ class Viewport : public WindowContainer, public gcn::MouseListener, int mCameraY; /**< Current viewpoint in tiles. */ bool mShowDebugPath; /**< Show a path from player to pointer. */ - ImageSet *mInRangeImages; /**< Images of in range target cursor. */ - ImageSet *mOutRangeImages; /**< Images of out of range target cursor.*/ + /** Images of in range target cursor. */ + ImageSet *mInRangeImages[Being::NUM_TC]; + + /** Images of out of range target cursor. */ + ImageSet *mOutRangeImages[Being::NUM_TC]; /** Animated in range target cursor. */ - SimpleAnimation *mTargetCursorInRange; + SimpleAnimation *mTargetCursorInRange[Being::NUM_TC]; /** Animated out of range target cursor. */ - SimpleAnimation *mTargetCursorOutRange; + SimpleAnimation *mTargetCursorOutRange[Being::NUM_TC]; bool mPlayerFollowMouse; int mWalkTime; diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp new file mode 100644 index 00000000..50a6fce4 --- /dev/null +++ b/src/gui/widgets/resizegrip.cpp @@ -0,0 +1,65 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "resizegrip.h" + +#include + +#include "../../graphics.h" + +#include "../../resources/image.h" +#include "../../resources/resourcemanager.h" + +Image *ResizeGrip::gripImage = 0; +int ResizeGrip::mInstances = 0; + +ResizeGrip::ResizeGrip() +{ + if (mInstances == 0) + { + // Load the grip image + ResourceManager *resman = ResourceManager::getInstance(); + gripImage = resman->getImage("graphics/gui/resize.png"); + } + + mInstances++; + + setWidth(gripImage->getWidth() + 2); + setHeight(gripImage->getHeight() + 2); +} + +ResizeGrip::~ResizeGrip() +{ + mInstances--; + + if (mInstances == 0) + { + gripImage->decRef(); + } +} + +void +ResizeGrip::draw(gcn::Graphics *graphics) +{ + dynamic_cast(graphics)->drawImage(gripImage, 0, 0); +} diff --git a/src/gui/widgets/resizegrip.h b/src/gui/widgets/resizegrip.h new file mode 100644 index 00000000..04be3db3 --- /dev/null +++ b/src/gui/widgets/resizegrip.h @@ -0,0 +1,61 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_RESIZEGRIP_H +#define _TMW_RESIZEGRIP_H + +#include + +class Image; + +/** + * Resize grip. The resize grip is part of a resizable Window. It relies on the + * fact that uncaught mouse events are automatically routed to the parent + * window. + * + * \ingroup GUI + */ +class ResizeGrip : public gcn::Widget +{ + public: + /** + * Constructor. + */ + ResizeGrip(); + + /** + * Destructor. + */ + ~ResizeGrip(); + + /** + * Draws the resize grip. + */ + void draw(gcn::Graphics *graphics); + + private: + static Image *gripImage; /**< Resize grip image */ + static int mInstances; /**< Number of resize grip instances */ +}; + +#endif diff --git a/src/gui/window.cpp b/src/gui/window.cpp index bb60c6ff..8a052bba 100644 --- a/src/gui/window.cpp +++ b/src/gui/window.cpp @@ -24,10 +24,13 @@ #include "window.h" #include +#include #include "gccontainer.h" #include "windowcontainer.h" +#include "widgets/resizegrip.h" + #include "../configlistener.h" #include "../configuration.h" #include "../graphics.h" @@ -36,11 +39,10 @@ #include "../resources/image.h" #include "../resources/resourcemanager.h" -ConfigListener *Window::windowConfigListener = NULL; -WindowContainer *Window::windowContainer = NULL; +ConfigListener *Window::windowConfigListener = 0; +WindowContainer *Window::windowContainer = 0; int Window::instances = 0; ImageRect Window::border; -Image *Window::resizeGrip; class WindowConfigListener : public ConfigListener { @@ -54,16 +56,16 @@ class WindowConfigListener : public ConfigListener Window::Window(const std::string& caption, bool modal, Window *parent): gcn::Window(caption), + mGrip(0), mParent(parent), mWindowName("window"), - mSnapSize(8), mShowTitle(true), mModal(modal), mResizable(false), - mMouseResize(false), + mMouseResize(0), mSticky(false), mMinWinWidth(100), - mMinWinHeight(28), + mMinWinHeight(40), mMaxWinWidth(INT_MAX), mMaxWinHeight(INT_MAX) { @@ -87,7 +89,6 @@ Window::Window(const std::string& caption, bool modal, Window *parent): border.grid[6] = dBorders->getSubImage(0, 15, 4, 4); border.grid[7] = dBorders->getSubImage(4, 15, 3, 4); border.grid[8] = dBorders->getSubImage(7, 15, 4, 4); - resizeGrip = resman->getImage("graphics/gui/resize.png"); dBorders->decRef(); windowConfigListener = new WindowConfigListener(); // Send GUI alpha changed for initialization @@ -151,10 +152,10 @@ Window::~Window() delete border.grid[6]; delete border.grid[7]; delete border.grid[8]; - resizeGrip->decRef(); } delete mChrome; + delete mGrip; } void Window::setWindowContainer(WindowContainer *wc) @@ -162,22 +163,15 @@ void Window::setWindowContainer(WindowContainer *wc) windowContainer = wc; } -void Window::draw(gcn::Graphics* graphics) +void Window::draw(gcn::Graphics *graphics) { - Graphics *g = (Graphics*)graphics; + Graphics *g = static_cast(graphics); g->drawImageRect(0, 0, getWidth(), getHeight(), border); - // Draw grip - if (mResizable) - { - g->drawImage(Window::resizeGrip, - getWidth() - resizeGrip->getWidth(), - getHeight() - resizeGrip->getHeight()); - } - // Draw title - if (mShowTitle) { + if (mShowTitle) + { graphics->setFont(getFont()); graphics->drawText(getCaption(), 7, 5, gcn::Graphics::LEFT); } @@ -188,13 +182,13 @@ void Window::draw(gcn::Graphics* graphics) void Window::setContentWidth(int width) { mChrome->setWidth(width); - resizeToContent(); + setWidth(width + 2 * getPadding()); } void Window::setContentHeight(int height) { mChrome->setHeight(height); - resizeToContent(); + setHeight(height + getPadding() + getTitleBarHeight()); } void Window::setContentSize(int width, int height) @@ -203,6 +197,37 @@ void Window::setContentSize(int width, int height) setContentHeight(height); } +void Window::setWidth(int width) +{ + gcn::Window::setWidth(width); + + if (mGrip) + { + mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x); + } +} + +void Window::setHeight(int height) +{ + gcn::Window::setHeight(height); + + if (mGrip) + { + mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y); + } +} + +void Window::setDimension(const gcn::Rectangle &dimension) +{ + gcn::Window::setDimension(dimension); + + if (mGrip) + { + mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x); + mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y); + } +} + void Window::setLocationRelativeTo(gcn::Widget *widget) { int wx, wy; @@ -238,6 +263,19 @@ void Window::setMaxHeight(unsigned int height) void Window::setResizable(bool r) { mResizable = r; + + if (mResizable) + { + mGrip = new ResizeGrip(); + mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x); + mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y); + gcn::Window::add(mGrip); + } + else + { + delete mGrip; + mGrip = 0; + } } bool Window::isResizable() @@ -287,15 +325,27 @@ void Window::mousePressed(gcn::MouseEvent &event) // Let Guichan move window to top and figure out title bar drag gcn::Window::mousePressed(event); - int x = event.getX(); - int y = event.getY(); + const int x = event.getX(); + const int y = event.getY(); + mMouseResize = 0; - // Activate resizing if the left mouse button was pressed on the grip - mMouseResize = - isResizable() && - event.getButton() == gcn::MouseEvent::LEFT && - getGripDimension().isPointInRect(x, y) && - !getChildrenArea().isPointInRect(x, y); + // Activate resizing handles as appropriate + if (event.getSource() == this && isResizable() && + event.getButton() == gcn::MouseEvent::LEFT && + !getChildrenArea().isPointInRect(x, y)) + { + mMouseResize |= (x > getWidth() - resizeBorderWidth) ? RIGHT : + (x < resizeBorderWidth) ? LEFT : 0; + mMouseResize |= (y > getHeight() - resizeBorderWidth) ? BOTTOM : + (y < resizeBorderWidth) ? TOP : 0; + } + else if (event.getSource() == mGrip) + { + mDragOffsetX = x + mGrip->getX(); + mDragOffsetY = y + mGrip->getY(); + mMouseResize |= BOTTOM | RIGHT; + mIsMoving = false; + } } void Window::mouseDragged(gcn::MouseEvent &event) @@ -303,20 +353,47 @@ void Window::mouseDragged(gcn::MouseEvent &event) // Let Guichan handle title bar drag gcn::Window::mouseDragged(event); - // Keep guichan window inside screen - int newX = std::max(0, getX()); - int newY = std::max(0, getY()); - newX = std::min(windowContainer->getWidth() - getWidth(), newX); - newY = std::min(windowContainer->getHeight() - getHeight(), newY); - setPosition(newX, newY); + // Keep guichan window inside screen when it may be moved + if (isMovable() && mIsMoving) + { + int newX = std::max(0, getX()); + int newY = std::max(0, getY()); + newX = std::min(windowContainer->getWidth() - getWidth(), newX); + newY = std::min(windowContainer->getHeight() - getHeight(), newY); + setPosition(newX, newY); + } if (mMouseResize && !mIsMoving) { + const int dx = event.getX() - mDragOffsetX + + ((event.getSource() == mGrip) ? mGrip->getX() : 0); + const int dy = event.getY() - mDragOffsetY + + ((event.getSource() == mGrip) ? mGrip->getY() : 0); gcn::Rectangle newDim = getDimension(); - // We're dragging bottom right - newDim.width += event.getX() - mDragOffsetX; - newDim.height += event.getY() - mDragOffsetY; + if (mMouseResize & (TOP | BOTTOM)) + { + int newHeight = newDim.height + ((mMouseResize & TOP) ? -dy : dy); + newDim.height = std::min(mMaxWinHeight, + std::max(mMinWinHeight, newHeight)); + + if (mMouseResize & TOP) + { + newDim.y -= newDim.height - getHeight(); + } + } + + if (mMouseResize & (LEFT | RIGHT)) + { + int newWidth = newDim.width + ((mMouseResize & LEFT) ? -dx : dx); + newDim.width = std::min(mMaxWinWidth, + std::max(mMinWinWidth, newWidth)); + + if (mMouseResize & LEFT) + { + newDim.x -= newDim.width - getWidth(); + } + } // Keep guichan window inside screen (supports resizing any side) if (newDim.x < 0) @@ -338,29 +415,16 @@ void Window::mouseDragged(gcn::MouseEvent &event) newDim.height = windowContainer->getHeight() - newDim.y; } - // Keep the window at least its minimum size - if (newDim.width < mMinWinWidth) - { - newDim.width = mMinWinWidth; - } - else if (newDim.width > mMaxWinWidth) - { - newDim.width = mMaxWinWidth; - } - - if (newDim.height < mMinWinHeight) + // Update mouse offset when dragging bottom or right border + if (mMouseResize & BOTTOM) { - newDim.height = mMinWinHeight; + mDragOffsetY += newDim.height - getHeight(); } - else if (newDim.height > mMaxWinHeight) + if (mMouseResize & RIGHT) { - newDim.height = mMaxWinHeight; + mDragOffsetX += newDim.width - getWidth(); } - // Update mouse offset when dragging bottom or right border - mDragOffsetX += newDim.width - getWidth(); - mDragOffsetY += newDim.height - getHeight(); - // Set the new window and content dimensions setDimension(newDim); const gcn::Rectangle area = getChildrenArea(); @@ -368,15 +432,6 @@ void Window::mouseDragged(gcn::MouseEvent &event) } } -gcn::Rectangle -Window::getGripDimension() -{ - return gcn::Rectangle(getWidth() - resizeGrip->getWidth(), - getHeight() - resizeGrip->getHeight(), - getWidth(), - getHeight()); -} - void Window::loadWindowState() { diff --git a/src/gui/window.h b/src/gui/window.h index 31c260cf..03248908 100644 --- a/src/gui/window.h +++ b/src/gui/window.h @@ -30,11 +30,10 @@ class ConfigListener; class GCContainer; -class Image; class ImageRect; +class ResizeGrip; class WindowContainer; - /** * A window. This window can be dragged around and has a title bar. Windows are * invisible by default. @@ -99,6 +98,21 @@ class Window : public gcn::Window */ void setContentSize(int width, int height); + /** + * Sets the width of this window. + */ + void setWidth(int width); + + /** + * Sets the height of this window. + */ + void setHeight(int height); + + /** + * Sets the position and size of this window. + */ + void setDimension(const gcn::Rectangle &dimension); + /** * Sets the location relative to the given widget. */ @@ -168,16 +182,15 @@ class Window : public gcn::Window void scheduleDelete(); /** - * Window dragging and resizing mouse related. These methods also makes - * sure the window is not dragged/resized outside of the screen. + * Starts window resizing when appropriate. */ void mousePressed(gcn::MouseEvent &event); - void mouseDragged(gcn::MouseEvent &event); /** - * Gets the position of the resize grip. + * Implements window resizing and makes sure the window is not + * dragged/resized outside of the screen. */ - gcn::Rectangle getGripDimension(); + void mouseDragged(gcn::MouseEvent &event); /** * Sets the name of the window. This is not the window title. @@ -214,37 +227,50 @@ class Window : public gcn::Window */ virtual void resetToDefaultSize(); + enum ResizeHandles + { + TOP = 0x01, + RIGHT = 0x02, + BOTTOM = 0x04, + LEFT = 0x08 + }; + protected: - GCContainer *mChrome; /**< Contained container */ + GCContainer *mChrome; /**< Contained container */ + ResizeGrip *mGrip; /**< Resize grip */ Window *mParent; /**< The parent window */ std::string mWindowName; /**< Name of the window */ - int mSnapSize; /**< Snap distance to window edge */ bool mShowTitle; /**< Window has a title bar */ bool mModal; /**< Window is modal */ - bool mResizable; /**< Window can be resized */ - bool mMouseResize; /**< Window is being resized */ - bool mSticky; /**< Window resists minimzation */ - int mMinWinWidth; /**< Minimum window width */ - int mMinWinHeight; /**< Minimum window height */ - int mMaxWinWidth; /**< Maximum window width */ - int mMaxWinHeight; /**< Maximum window height */ + bool mResizable; /**< Window can be resized */ + int mMouseResize; /**< Window is being resized */ + bool mSticky; /**< Window resists minimization */ + int mMinWinWidth; /**< Minimum window width */ + int mMinWinHeight; /**< Minimum window height */ + int mMaxWinWidth; /**< Maximum window width */ + int mMaxWinHeight; /**< Maximum window height */ int mDefaultX; /**< Default window X position */ int mDefaultY; /**< Default window Y position */ int mDefaultWidth; /**< Default window width */ int mDefaultHeight; /**< Default window height */ /** The window container windows add themselves to. */ - static WindowContainer* windowContainer; + static WindowContainer *windowContainer; /** - * The config listener that listens to changes relevant to all - * windows + * The config listener that listens to changes relevant to all windows. */ static ConfigListener *windowConfigListener; static int instances; /**< Number of Window instances */ static ImageRect border; /**< The window border and background */ - static Image *resizeGrip; /**< The grip to resize window */ + + /** + * The width of the resize border. Is independent of the actual window + * border width, and determines mostly the size of the corner area + * where two borders are moved at the same time. + */ + static const int resizeBorderWidth = 10; }; #endif diff --git a/src/imageparticle.cpp b/src/imageparticle.cpp new file mode 100644 index 00000000..35cc21ad --- /dev/null +++ b/src/imageparticle.cpp @@ -0,0 +1,69 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "imageparticle.h" + +#include "graphics.h" + +#include "resources/image.h" + +ImageParticle::ImageParticle(Map *map, Image *image): + Particle(map), + mImage(image) +{ + mImage->incRef(); +} + +ImageParticle::~ImageParticle() +{ + mImage->decRef(); +} + +void ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const +{ + if (!mAlive) + return; + + int screenX = (int) mPosX + offsetX - mImage->getWidth() / 2; + int screenY = (int) mPosY - (int) mPosZ + offsetY - mImage->getHeight()/2; + + // Check if on screen + if (screenX + mImage->getWidth() < 0 || + screenX > graphics->getWidth() || + screenY + mImage->getHeight() < 0 || + screenY > graphics->getHeight()) + { + return; + } + + float alphafactor = 1.0f; + + if (mLifetimeLeft > -1 && mLifetimeLeft < mFadeOut) + alphafactor *= (float) mLifetimeLeft / (float) mFadeOut; + + if (mLifetimePast < mFadeIn) + alphafactor *= (float) mLifetimePast / (float) mFadeIn; + + mImage->setAlpha(alphafactor); + graphics->drawImage(mImage, screenX, screenY); +} diff --git a/src/imageparticle.h b/src/imageparticle.h new file mode 100644 index 00000000..0ad515cc --- /dev/null +++ b/src/imageparticle.h @@ -0,0 +1,61 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _IMAGEPARTICLE_H +#define _IMAGEPARTICLE_H + +#include "particle.h" + +class Image; +class Map; + +/** + * A particle that uses an image for its visualization. + */ +class ImageParticle : public Particle +{ + public: + /** + * Constructor. The image is reference counted by this particle. + * + * @param map the map this particle appears on + * @param image an Image instance, may not be NULL + */ + ImageParticle(Map *map, Image *image); + + /** + * Destructor. + */ + ~ImageParticle(); + + /** + * Draws the particle image + */ + virtual void + draw(Graphics *graphics, int offsetX, int offsetY) const; + + protected: + Image *mImage; /**< The image used for this particle. */ +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index bbbf0fd1..58c563ab 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,7 +40,7 @@ #include -#if (defined __USE_UNIX98 || defined __FreeBSD__ || defined __APPLE__) +#ifndef WIN32 #include #include #endif @@ -148,21 +148,21 @@ struct Options */ void initHomeDir() { -#if !(defined __USE_UNIX98 || defined __FreeBSD__ || defined __APPLE__) - homeDir = "."; -#else homeDir = std::string(PHYSFS_getUserDir()) + "/.tmw"; - +#if defined WIN32 + if (!CreateDirectory(homeDir.c_str(), 0) && + GetLastError() != ERROR_ALREADY_EXISTS) +#else // Checking if /home/user/.tmw folder exists. if ((mkdir(homeDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) && (errno != EEXIST)) +#endif { std::cout << homeDir - << " can't be made, but it doesn't exist! Exiting." + << " can't be created, but it doesn't exist! Exiting." << std::endl; exit(1); } -#endif } /** @@ -236,11 +236,17 @@ void initEngine() static SDL_SysWMinfo pInfo; SDL_GetWMInfo(&pInfo); HICON icon = LoadIcon(GetModuleHandle(NULL), "A"); - SetClassLong(pInfo.window, GCL_HICON, (LONG) icon); + if (icon) + { + SetClassLong(pInfo.window, GCL_HICON, (LONG) icon); + } #else SDL_Surface *icon = IMG_Load(TMW_DATADIR "data/icons/tmw.png"); - SDL_SetAlpha(icon, SDL_SRCALPHA, SDL_ALPHA_OPAQUE); - SDL_WM_SetIcon(icon, NULL); + if (icon) + { + SDL_SetAlpha(icon, SDL_SRCALPHA, SDL_ALPHA_OPAQUE); + SDL_WM_SetIcon(icon, NULL); + } #endif ResourceManager *resman = ResourceManager::getInstance(); diff --git a/src/map.cpp b/src/map.cpp index a6beb951..ac570627 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -29,6 +29,7 @@ #include "beingmanager.h" #include "game.h" #include "graphics.h" +#include "particle.h" #include "sprite.h" #include "tileset.h" @@ -530,3 +531,25 @@ Map::findPath(int startX, int startY, int destX, int destY) return path; } + +void +Map::addParticleEffect (std::string effectFile, int x, int y) +{ + ParticleEffectData newEffect; + newEffect.file = effectFile; + newEffect.x = x; + newEffect.y = y; + particleEffects.push_back(newEffect); +} + +void +Map::initializeParticleEffects(Particle* particleEngine) +{ + for (std::list::iterator i = particleEffects.begin(); + i != particleEffects.end(); + i++ + ) + { + particleEngine->addEffect(i->file, i->x, i->y); + } +} diff --git a/src/map.h b/src/map.h index c8a6fdb3..17772847 100644 --- a/src/map.h +++ b/src/map.h @@ -32,8 +32,9 @@ class AmbientOverlay; class Graphics; class Image; -class Tileset; +class Particle; class Sprite; +class Tileset; struct PATH_NODE; @@ -185,6 +186,17 @@ class Map : public Properties void removeSprite(SpriteIterator iterator); + /** + * Adds a particle effect + */ + void addParticleEffect (std::string effectFile, int x, int y); + + /** + * Initializes all added particle effects + */ + void + initializeParticleEffects(Particle* particleEngine); + private: /** * Converts a global tile id to the Image* pointing to the associated @@ -220,10 +232,19 @@ class Map : public Properties // Pathfinding members int mOnClosedList, mOnOpenList; - //overlay Data + // Overlay Data std::list mOverlays; float mLastScrollX; float mLastScrollY; + + // Particle effect data + struct ParticleEffectData + { + std::string file; + int x; + int y; + }; + std::list particleEffects; }; #endif diff --git a/src/monster.cpp b/src/monster.cpp index bea5b7a5..768bf16a 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -93,6 +93,12 @@ Monster::handleAttack() sound.playSfx(mi.getSound(EVENT_HIT)); } +Being::TargetCursorSize +Monster::getTargetCursorSize() const +{ + return getInfo().getTargetCursorSize(); +} + const MonsterInfo& Monster::getInfo() const { diff --git a/src/monster.h b/src/monster.h index 39bbf3d7..4915520d 100644 --- a/src/monster.h +++ b/src/monster.h @@ -37,6 +37,9 @@ class Monster : public Being virtual Type getType() const; + virtual TargetCursorSize + getTargetCursorSize() const; + /** * Handles an attack of another being by this monster. Plays a hit or * miss sound when appropriate. diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 53746671..f82a0fa8 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -34,6 +34,7 @@ #include "../localplayer.h" #include "../log.h" #include "../main.h" +#include "../particle.h" #include "../sound.h" const int EMOTION_TIME = 150; /**< Duration of emotion icon */ @@ -240,13 +241,23 @@ void BeingHandler::handleMessage(MessageIn &msg) break; case SMSG_BEING_LEVELUP: - if ((Uint32) msg.readLong() == player_node->getId()) { + id = (Uint32) msg->readLong(); + + if (id == player_node->getId()) { logger->log("Level up"); sound.playSfx("sfx/levelup.ogg"); - } else { + } + else { logger->log("Someone else went level up"); } - msg.readLong(); // type + Particle *levelupFX; + if (msg->readLong() == 0) { // type + levelupFX = particleEngine->addEffect("graphics/particles/levelup.particle.xml", 0, 0); + } + else { + levelupFX = particleEngine->addEffect("graphics/particles/skillup.particle.xml", 0, 0); + } + beingManager->findBeing(id)->controlParticle(levelupFX); break; case SMSG_BEING_EMOTION: diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp index ec6c1ee3..f4cda0b9 100644 --- a/src/openglgraphics.cpp +++ b/src/openglgraphics.cpp @@ -261,7 +261,7 @@ void OpenGLGraphics::drawPoint(int x, int y) setTexturingAndBlending(false); glBegin(GL_POINTS); - glVertex3i(x, y, 0); + glVertex2i(x, y); glEnd(); } @@ -270,12 +270,12 @@ void OpenGLGraphics::drawLine(int x1, int y1, int x2, int y2) setTexturingAndBlending(false); glBegin(GL_LINES); - glVertex3f(x1 + 0.5f, y1 + 0.5f, 0); - glVertex3f(x2 + 0.5f, y2 + 0.5f, 0); + glVertex2f(x1 + 0.5f, y1 + 0.5f); + glVertex2f(x2 + 0.5f, y2 + 0.5f); glEnd(); glBegin(GL_POINTS); - glVertex3f(x2 + 0.5f, y2 + 0.5f, 0); + glVertex2f(x2 + 0.5f, y2 + 0.5f); glEnd(); } @@ -329,10 +329,10 @@ void OpenGLGraphics::drawRectangle(const gcn::Rectangle& rect, bool filled) setTexturingAndBlending(false); glBegin(filled ? GL_QUADS : GL_LINE_LOOP); - glVertex3f(rect.x + offset, rect.y + offset, 0); - glVertex3f(rect.x + rect.width - offset, rect.y + offset, 0); - glVertex3f(rect.x + rect.width - offset, rect.y + rect.height - offset, 0); - glVertex3f(rect.x + offset, rect.y + rect.height - offset, 0); + glVertex2f(rect.x + offset, rect.y + offset); + glVertex2f(rect.x + rect.width - offset, rect.y + offset); + glVertex2f(rect.x + rect.width - offset, rect.y + rect.height - offset); + glVertex2f(rect.x + offset, rect.y + rect.height - offset); glEnd(); } @@ -344,16 +344,16 @@ void OpenGLGraphics::drawTexedQuad(int x, int y, int w, int h, // Draw a textured quad glBegin(GL_QUADS); glTexCoord2f(texX1, texY1); - glVertex3i(x, y, 0); + glVertex2i(x, y); glTexCoord2f(texX2, texY1); - glVertex3i(x + w, y, 0); + glVertex2i(x + w, y); glTexCoord2f(texX2, texY2); - glVertex3i(x + w, y + h, 0); + glVertex2i(x + w, y + h); glTexCoord2f(texX1, texY2); - glVertex3i(x, y + h, 0); + glVertex2i(x, y + h); glEnd(); } diff --git a/src/particle.cpp b/src/particle.cpp new file mode 100644 index 00000000..509c20ee --- /dev/null +++ b/src/particle.cpp @@ -0,0 +1,370 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "particle.h" + +#include + +#include "animationparticle.h" +#include "configuration.h" +#include "imageparticle.h" +#include "log.h" +#include "map.h" +#include "particleemitter.h" +#include "textparticle.h" + +#include "resources/resourcemanager.h" + +#include "utils/dtor.h" +#include "utils/fastsqrt.h" +#include "utils/xml.h" + +class Graphics; +class Image; + +int Particle::particleCount = 0; +int Particle::maxCount = 0; +int Particle::fastPhysics = 0; +int Particle::emitterSkip = 1; +const float Particle::PARTICLE_SKY = 800.0f; + +Particle::Particle(Map *map): + mAlive(true), + mPosX(0.0f), mPosY(0.0f), mPosZ(0.0f), + mLifetimeLeft(-1), + mLifetimePast(0), + mFadeOut(0), + mFadeIn(0), + mAutoDelete(true), + mMap(map), + mVectorX(0.0f), mVectorY(0.0f), mVectorZ(0.0f), + mGravity(0.0f), + mRandomnes(0), + mBounce(0.0f), + mTarget(NULL), + mAcceleration(0.0f), + mInvDieDistance(-1.0f), + mMomentum(1.0f) +{ + Particle::particleCount++; + if (mMap) setSpriteIterator(mMap->addSprite(this)); +} + + +void +Particle::setupEngine() +{ + Particle::maxCount = (int)config.getValue("particleMaxCount", 3000); + Particle::fastPhysics = (int)config.getValue("particleFastPhysics", 0); + Particle::emitterSkip = (int)config.getValue("particleEmitterSkip", 0) + 1; + disableAutoDelete(); + logger->log("Particle engine set up"); +} + +bool +Particle::update() +{ + if (!mMap) return false; + + if (mLifetimeLeft == 0) + { + mAlive = false; + } + + if (mAlive) + { + // Update child emitters + if (mLifetimePast%Particle::emitterSkip == 0) + { + for ( EmitterIterator e = mChildEmitters.begin(); + e != mChildEmitters.end(); + e++ + ) + { + Particles newParticles = (*e)->createParticles(); + for ( ParticleIterator p = newParticles.begin(); + p != newParticles.end(); + p++ + ) + { + (*p)->moveBy(mPosX, mPosY, mPosZ); + mChildParticles.push_back (*p); + } + } + } + + if (mMomentum != 1.0f) + { + mVectorX *= mMomentum; + mVectorY *= mMomentum; + mVectorZ *= mMomentum; + } + + if (mTarget && mAcceleration != 0.0f) + { + float distX = mPosX - mTarget->getPosX(); + float distY = mPosY - mTarget->getPosY(); + float distZ = mPosZ - mTarget->getPosZ(); + float invHypotenuse; + + switch(Particle::fastPhysics) + { + case 1: + invHypotenuse = fastInvSqrt( + distX * distX + distY * distY + distZ * distZ); + break; + case 2: + invHypotenuse = 2.0f / + fabs(distX) + fabs(distY) + fabs(distZ); + break; + default: + invHypotenuse = 1.0f / sqrt( + distX * distX + distY * distY + distZ * distZ); + break; + } + + if (invHypotenuse) + { + if (mInvDieDistance > 0.0f && invHypotenuse > mInvDieDistance) + { + mAlive = false; + } + float accFactor = invHypotenuse * mAcceleration; + mVectorX -= distX * accFactor; + mVectorY -= distY * accFactor; + mVectorZ -= distZ * accFactor; + } + } + + if (mRandomnes > 0) + { + mVectorX += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f; + mVectorY += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f; + mVectorZ += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f; + } + + mVectorZ -= mGravity; + + // Update position + mPosX += mVectorX; + mPosY += mVectorY; + mPosZ += mVectorZ; + + // Update other stuff + if (mLifetimeLeft > 0) + { + mLifetimeLeft--; + } + mLifetimePast++; + + if (mPosZ > PARTICLE_SKY || mPosZ < 0.0f) + { + if (mBounce > 0.0f) + { + mPosZ *= -mBounce; + mVectorX *= mBounce; + mVectorY *= mBounce; + mVectorZ *= -mBounce; + } + else { + mAlive = false; + } + } + } + + // Update child particles + for ( ParticleIterator p = mChildParticles.begin(); + p != mChildParticles.end(); + + ) + { + if ((*p)->update()) + { + p++; + } else { + delete (*p); + p = mChildParticles.erase(p); + } + } + + if (!mAlive && mChildParticles.empty() && mAutoDelete) + { + return false; + } + + return true; +} + + +void Particle::draw(Graphics *graphics, int offsetX, int offsetY) const +{ +} + + +Particle* +Particle::addEffect(std::string particleEffectFile, int pixelX, int pixelY) +{ + Particle *newParticle = NULL; + + // XML parser initialisation stuff + int size; + ResourceManager *resman = ResourceManager::getInstance(); + char *data = (char*) resman->loadFile(particleEffectFile.c_str(), size); + + if (!data) { + logger->log("Warning: Particle engine could not find %s !", + particleEffectFile.c_str()); + return NULL; + } + + xmlDocPtr doc = xmlParseMemory(data, size); + free(data); + + if (!doc) { + logger->log("Warning: Particle engine found syntax error in %s!", + particleEffectFile.c_str()); + return NULL; + } + + xmlNodePtr rootNode = xmlDocGetRootElement(doc); + if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "effect")) + { + logger->log("Warning: %s is not a valid particle effect definition file!", + particleEffectFile.c_str()); + return NULL; + } + + // Parse particles + for_each_xml_child_node(effectChildNode, rootNode) + { + // We're only interested in particles + if (!xmlStrEqual(effectChildNode->name, BAD_CAST "particle")) + continue; + + // Determine the exact particle type + xmlNodePtr node; + + // Animation + if ((node = XML::findFirstChildByName( + effectChildNode, "animation"))) { + newParticle = new AnimationParticle(mMap, node); + } + // Image + else if ((node = XML::findFirstChildByName( + effectChildNode, "image"))) { + Image *img= resman->getImage((const char*) + node->xmlChildrenNode->content); + + newParticle = new ImageParticle(mMap, img); + } + // Other + else { + newParticle = new Particle(mMap); + } + + // Read and set the basic properties of the particle + int offsetX = XML::getProperty(effectChildNode, "position-x", 0); + int offsetY = XML::getProperty(effectChildNode, "position-y", 0); + int offsetZ = XML::getProperty(effectChildNode, "position-z", 0); + + int particleX = (int)mPosX + pixelX + offsetX; + int particleY = (int)mPosY + pixelY + offsetY; + int particleZ = (int)mPosZ + offsetZ; + + int lifetime = XML::getProperty(effectChildNode, "lifetime", -1); + + newParticle->setPosition(particleX, particleY, particleZ); + newParticle->setLifetime(lifetime); + + // Look for additional emitters for this particle + for_each_xml_child_node(emitterNode, effectChildNode) + { + if (!xmlStrEqual(emitterNode->name, BAD_CAST "emitter")) + continue; + + ParticleEmitter *newEmitter; + newEmitter = new ParticleEmitter(emitterNode, newParticle, mMap); + newParticle->addEmitter(newEmitter); + } + + mChildParticles.push_back(newParticle); + } + + return newParticle; +} + + +Particle* +Particle::addTextSplashEffect(std::string text, + int colorR, int colorG, int colorB, + gcn::Font *font, int x, int y) +{ + Particle *newParticle = new TextParticle(mMap, text, colorR, colorG, colorB, + font); + newParticle->setPosition(x, y, 0); + newParticle->setVector ( ((rand()%100) - 50) / 200.0f, // X vector + ((rand()%100) - 50) / 200.0f, // Y vector + ((rand()%100) / 200.0f) + 4.0f // Z vector + ); + newParticle->setGravity(0.1f); + newParticle->setBounce(0.5f); + newParticle->setLifetime(200); + newParticle->setFadeOut(100); + + mChildParticles.push_back(newParticle); + + return newParticle; +} + + +void +Particle::setMap(Map *map) +{ + mMap = map; + if (mMap) setSpriteIterator(mMap->addSprite(this)); + + // TODO: Create map emitters based on emitter data in map data +} + + +Particle::~Particle() +{ + // Remove from map sprite list + if (mMap) mMap->removeSprite(mSpriteIterator); + // Delete child emitters and child particles + clear(); + Particle::particleCount--; +} + + +void +Particle::clear() +{ + std::for_each(mChildEmitters.begin(), mChildEmitters.end(), + make_dtor(mChildEmitters)); + mChildEmitters.clear(); + + std::for_each(mChildParticles.begin(), mChildParticles.end(), + make_dtor(mChildParticles)); + mChildParticles.clear(); +} diff --git a/src/particle.h b/src/particle.h new file mode 100644 index 00000000..7a747a5f --- /dev/null +++ b/src/particle.h @@ -0,0 +1,288 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _PARTICLE_H +#define _PARTICLE_H + +#include +#include + +#include + +#include "guichanfwd.h" +#include "sprite.h" + + +class Map; +class Particle; +class ParticleEmitter; + +typedef std::list Particles; +typedef Particles::iterator ParticleIterator; +typedef std::list Emitters; +typedef Emitters::iterator EmitterIterator; + +/** + * A particle spawned by a ParticleEmitter. + */ +class Particle : public Sprite +{ + public: + static const float PARTICLE_SKY; /**< Maximum Z position of particles */ + static int fastPhysics; /**< Mode of squareroot calculation */ + static int particleCount; /**< Current number of particles */ + static int maxCount; /**< Maximum number of particles */ + static int emitterSkip; /**< Duration of pause between two emitter updates in ticks */ + + /** + * Constructor. + * + * @param map the map this particle will add itself to, may be NULL + */ + Particle(Map *map); + + /** + * Destructor. + */ + ~Particle(); + + /** + * Deletes all child particles and emitters + */ + void + clear(); + + /** + * Gives a particle the properties of an engine root particle and loads + * the particle-related config settings + */ + void + setupEngine(); + + /** + * Updates particle position, returns false when the particle should + * be deleted + */ + virtual bool + update(); + + /** + * Draws the particle image + */ + virtual void + draw(Graphics *graphics, int offsetX, int offsetY) const; + + /** + * Necessary for sorting with the other sprites + */ + virtual int + getPixelY() const + { + return (int)(mPosY + mPosZ) - 64; + }; + + /* + Basic Particle properties: + */ + + /** + * Sets the map the particle is on. + */ + void setMap(Map *map); + + /** + * Creates a child particle that hosts some emitters described in the + * particleEffectFile. + */ + Particle* + addEffect(std::string particleEffectFile, int pixelX, int pixelY); + + /** + * Creates a standalone text particle. + */ + Particle* + addTextSplashEffect(std::string text, int colorR, int colorG, int colorB, + gcn::Font *font, int x, int y); + + /** + * Adds an emitter to the particle. + */ + void + addEmitter (ParticleEmitter* emitter) + { mChildEmitters.push_back(emitter); } + + /** + * Sets the position in 3 dimensional space in pixels relative to map + */ + void + setPosition(float x, float y, float z) + { mPosX = x; mPosY = y; mPosZ = z; } + + /** + * Sets the position in 2 dimensional space in pixels relative to map + */ + void + setPosition(float x, float y) + { mPosX = x; mPosY = y; } + + float getPosX() const + { return mPosX; } + + float getPosY() const + { return mPosY; } + + float getPosZ() const + { return mPosZ; } + + /** + * Changes the particle position relative + */ + void + moveBy(float x, float y, float z) + { mPosX += x; mPosY += y; mPosZ += z; } + + /** + * Sets the time in game ticks until the particle is destroyed. + */ + void + setLifetime(int lifetime) + { mLifetimeLeft = lifetime; mLifetimePast = 0; } + + /** + * Sets the age of the pixel in game ticks where the particle has + * faded in completely + */ + void + setFadeOut (int fadeOut) + { mFadeOut = fadeOut; } + + /** + * Sets the remaining particle lifetime where the particle starts to + * fade out + */ + void + setFadeIn (int fadeIn) + { mFadeIn = fadeIn; } + + /** + * Sets the sprite iterator of the particle on the current map to make + * it easier to remove the particle from the map when it is destroyed + */ + void + setSpriteIterator(std::list::iterator spriteIterator) + { mSpriteIterator = spriteIterator; } + + /** + * Gets the sprite iterator of the particle on the current map + */ + std::list::iterator + getSpriteIterator() const + { return mSpriteIterator; } + + /** + * Sets the current velocity in 3 dimensional space + */ + void + setVector(float x, float y, float z) + { mVectorX = x; mVectorY = y; mVectorZ = z; } + + /** + * Sets the downward acceleration + */ + void + setGravity(float g) + { mGravity = g; } + + /** + * Sets the ammount of random vector changes + */ + void + setRandomnes(int r) + { mRandomnes = r; } + + /** + * Sets the ammount of velocity particles retain after + * hitting the ground. + */ + void + setBounce(float bouncieness) + { mBounce = bouncieness; } + + /** + * Makes the particle move toward another particle with a + * given acceleration and momentum + */ + void setDestination(Particle *target, float accel, float moment) + { mTarget = target; mAcceleration = accel; mMomentum = moment; } + + /** + * Sets the distance in pixel the particle can come near the target + * particle before it is destroyed. Does only make sense after a + * target particle has been set using setDestination. + */ + void setDieDistance(float dist) + { mInvDieDistance = 1.0f / dist; } + + /** + * Manually marks the particle for deletion + */ + void kill() + { mAlive = false; mAutoDelete = true; } + + /** + * After calling this function the particle will only request + * deletion when kill() is called + */ + void disableAutoDelete() + { mAutoDelete = false; } + + protected: + bool mAlive; /**< Is the particle supposed to be drawn and updated?*/ + float mPosX, mPosY, mPosZ; /**< Position in 3 dimensonal space - pixel based relative to map */ + int mLifetimeLeft; /**< Lifetime left in game ticks*/ + int mLifetimePast; /**< Age of the particle in game ticks*/ + int mFadeOut; /**< Lifetime in game ticks left where fading out begins*/ + int mFadeIn; /**< Age in game ticks where fading in is finished*/ + + private: + // generic properties + bool mAutoDelete; /**< May the particle request its deletion by the parent particle?*/ + Map *mMap; /**< Map the particle is on*/ + std::list::iterator mSpriteIterator; /**< iterator of the particle on the current map */ + Emitters mChildEmitters; /**< List of child emitters*/ + Particles mChildParticles; /**< List of particles controlled by this particle*/ + //dynamic particle + float mVectorX, mVectorY, mVectorZ; /**< Speed in 3 dimensional space in pixels per game-tick */ + float mGravity; /**< Downward acceleration in pixels per game-tick²*/ + int mRandomnes; /**< Ammount of random vector change*/ + float mBounce; /**< How much the particle bounces off when hitting the ground*/ + //follow-point particles + Particle *mTarget; /**< The particle that attracts this particle*/ + float mAcceleration; /**< Acceleration towards the target particle in pixels per game-tick²*/ + float mInvDieDistance; /**< Distance in pixels from the target particle that causes the destruction of the particle*/ + float mMomentum; /**< How much speed the particle retains after each game tick*/ +}; + +extern Particle *particleEngine; + +#endif diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp new file mode 100644 index 00000000..2387c652 --- /dev/null +++ b/src/particleemitter.cpp @@ -0,0 +1,327 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "particleemitter.h" + +#include "animationparticle.h" +#include "imageparticle.h" +#include "log.h" +#include "particle.h" + +#include "resources/animation.h" +#include "resources/image.h" +#include "resources/resourcemanager.h" +#include "resources/imageset.h" + +#include + +#define SIN45 0.707106781f +#define DEG_RAD_FACTOR 0.017453293f + +ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map): + mParticleImage(0) +{ + mMap = map; + mParticleTarget = target; + + //initializing default values + mParticlePosX.set(0.0f); + mParticlePosY.set(0.0f); + mParticlePosZ.set(0.0f); + mParticleAngleHorizontal.set(0.0f); + mParticleAngleVertical.set(0.0f); + mParticlePower.set(0.0f); + mParticleGravity.set(0.0f); + mParticleRandomnes.set(0); + mParticleBounce.set(0.0f); + mParticleAcceleration.set(0.0f); + mParticleDieDistance.set(-1.0f); + mParticleMomentum.set(1.0f); + mParticleLifetime.set(-1); + mParticleFadeOut.set(0); + mParticleFadeIn.set(0); + mOutput.set(1); + + for_each_xml_child_node(propertyNode, emitterNode) + { + if (xmlStrEqual(propertyNode->name, BAD_CAST "property")) + { + std::string name = XML::getProperty(propertyNode, "name", ""); + + if (name == "position-x") + { + mParticlePosX = readMinMax(propertyNode, 0.0f); + } + else if (name == "position-y") + { + + mParticlePosY = readMinMax(propertyNode, 0.0f); + } + else if (name == "position-z") + { + mParticlePosZ = readMinMax(propertyNode, 0.0f); + } + else if (name == "image") + { + std::string image = XML::getProperty(propertyNode, "value", ""); + // Don't leak when multiple images are defined + if (image != "" && !mParticleImage) + { + ResourceManager *resman = ResourceManager::getInstance(); + mParticleImage = resman->getImage(image); + } + } + else if (name == "horizontal-angle") + { + mParticleAngleHorizontal = readMinMax(propertyNode, 0.0f); + mParticleAngleHorizontal.minVal *= DEG_RAD_FACTOR; + mParticleAngleHorizontal.maxVal *= DEG_RAD_FACTOR; + } + else if (name == "vertical-angle") + { + mParticleAngleVertical = readMinMax(propertyNode, 0.0f); + mParticleAngleVertical.minVal *= DEG_RAD_FACTOR; + mParticleAngleVertical.maxVal *= DEG_RAD_FACTOR; + } + else if (name == "power") + { + mParticlePower = readMinMax(propertyNode, 0.0f); + } + else if (name == "gravity") + { + mParticleGravity = readMinMax(propertyNode, 0.0f); + } + else if (name == "randomnes") + { + mParticleRandomnes = readMinMax(propertyNode, 0); + } + else if (name == "bounce") + { + mParticleBounce = readMinMax(propertyNode, 0.0f); + } + else if (name == "lifetime") + { + mParticleLifetime = readMinMax(propertyNode, 0); + mParticleLifetime.minVal += 1; + } + else if (name == "output") + { + mOutput = readMinMax(propertyNode, 0); + mOutput.maxVal +=1; + } + else if (name == "acceleration") + { + mParticleAcceleration = readMinMax(propertyNode, 0.0f); + } + else if (name == "die-distance") + { + mParticleDieDistance = readMinMax(propertyNode, 0.0f); + } + else if (name == "momentum") + { + mParticleMomentum = readMinMax(propertyNode, 1.0f); + } + else if (name == "fade-out") + { + mParticleFadeOut = readMinMax(propertyNode, 0); + } + else if (name == "fade-in") + { + mParticleFadeIn = readMinMax(propertyNode, 0); + } + else + { + logger->log("Particle Engine: Warning, unknown emitter property \"%s\"", + name.c_str() + ); + } + } + else if (xmlStrEqual(propertyNode->name, BAD_CAST "emitter")) + { + ParticleEmitter newEmitter(propertyNode, mParticleTarget, map); + mParticleChildEmitters.push_back(newEmitter); + } + else if (xmlStrEqual(propertyNode->name, BAD_CAST "animation")) + { + ImageSet *imageset = ResourceManager::getInstance()->getImageSet( + XML::getProperty(propertyNode, "imageset", ""), + XML::getProperty(propertyNode, "width", 0), + XML::getProperty(propertyNode, "height", 0) + ); + + // Get animation frames + for_each_xml_child_node(frameNode, propertyNode) + { + int delay = XML::getProperty(frameNode, "delay", 0); + int offsetX = XML::getProperty(frameNode, "offsetX", 0); + int offsetY = XML::getProperty(frameNode, "offsetY", 0); + offsetY -= imageset->getHeight() - 32; + offsetX -= imageset->getWidth() / 2 - 16; + + if (xmlStrEqual(frameNode->name, BAD_CAST "frame")) + { + int index = XML::getProperty(frameNode, "index", -1); + + if (index < 0) + { + logger->log("No valid value for 'index'"); + continue; + } + + Image *img = imageset->get(index); + + if (!img) + { + logger->log("No image at index " + (index)); + continue; + } + + mParticleAnimation.addFrame(img, delay, offsetX, offsetY); + } + else if (xmlStrEqual(frameNode->name, BAD_CAST "sequence")) + { + int start = XML::getProperty(frameNode, "start", -1); + int end = XML::getProperty(frameNode, "end", -1); + + if (start < 0 || end < 0) + { + logger->log("No valid value for 'start' or 'end'"); + continue; + } + + while (end >= start) + { + Image *img = imageset->get(start); + + if (!img) + { + logger->log("No image at index " + + (start)); + continue; + } + + mParticleAnimation.addFrame(img, delay, offsetX, offsetY); + start++; + } + } + else if (xmlStrEqual(frameNode->name, BAD_CAST "end")) + { + mParticleAnimation.addTerminator(); + } + } // for frameNode + } + } +} + + +ParticleEmitter::~ParticleEmitter() +{ + if (mParticleImage) + { + mParticleImage->decRef(); + } +} + + +template MinMax +ParticleEmitter::readMinMax(xmlNodePtr propertyNode, T def) +{ + MinMax retval; + + def = (T)XML::getFloatProperty(propertyNode, "value", (double)def); + retval.set ( (T)XML::getFloatProperty(propertyNode, "min", (double)def), + (T)XML::getFloatProperty(propertyNode, "max", (double)def) + ); + + return retval; +} + + +std::list +ParticleEmitter::createParticles() +{ + std::list newParticles; + + for (int i = mOutput.value(); i > 0; i--) + { + // Limit maximum particles + if (Particle::particleCount > Particle::maxCount) break; + + Particle *newParticle; + if (mParticleImage) + { + newParticle = new ImageParticle(mMap, mParticleImage); + } + else if (mParticleAnimation.getLength() > 0) + { + Animation *newAnimation = new Animation(mParticleAnimation); + newParticle = new AnimationParticle(mMap, newAnimation); + } + else + { + newParticle = new Particle(mMap); + } + + + newParticle->setPosition( + mParticlePosX.value(), + mParticlePosY.value(), + mParticlePosZ.value() + ); + + float angleH = mParticleAngleHorizontal.value(); + float angleV = mParticleAngleVertical.value(); + float power = mParticlePower.value(); + newParticle->setVector( + cos(angleH) * cos(angleV) * power, + sin(angleH) * cos(angleV) * SIN45 * power, + sin(angleV) * SIN45 * power + ); + + newParticle->setRandomnes(mParticleRandomnes.value()); + newParticle->setGravity(mParticleGravity.value()); + newParticle->setBounce(mParticleBounce.value()); + + newParticle->setDestination(mParticleTarget, + mParticleAcceleration.value(), + mParticleMomentum.value() + ); + newParticle->setDieDistance(mParticleDieDistance.value()); + + newParticle->setLifetime(mParticleLifetime.value()); + newParticle->setFadeOut(mParticleFadeOut.value()); + newParticle->setFadeIn(mParticleFadeIn.value()); + + for ( std::list::iterator i = mParticleChildEmitters.begin(); + i != mParticleChildEmitters.end(); + i++ + ) + { + newParticle->addEmitter(new ParticleEmitter(*i)); + } + + newParticles.push_back(newParticle); + } + + return newParticles; +} diff --git a/src/particleemitter.h b/src/particleemitter.h new file mode 100644 index 00000000..ca6d8622 --- /dev/null +++ b/src/particleemitter.h @@ -0,0 +1,120 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _PARTICLEEMITTER_H +#define _PARTICLEEMITTER_H + +#include + +#include "utils/xml.h" +#include "utils/minmax.h" + +#include "resources/animation.h" + +class Image; +class Map; +class Particle; + +/** + * Every Particle can have one or more particle emitters that create new + * particles when they are updated + */ +class ParticleEmitter +{ + public: + /** + * Constructor. + */ + ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map); + + /** + * Destructor. + */ + ~ParticleEmitter(); + + /** + * Spawns new particles + * @return: a list of created particles + */ + std::list createParticles(); + + /** + * Sets the target of the particles that are created + */ + void + setTarget(Particle *target) + { mParticleTarget = target; }; + + private: + template MinMax readMinMax(xmlNodePtr propertyNode, T def); + + /** + * initial position of particles: + */ + MinMax mParticlePosX, mParticlePosY, mParticlePosZ; + + /** + * initial vector of particles: + */ + MinMax mParticleAngleHorizontal, mParticleAngleVertical; + + /** + * Initial velocity of particles + */ + MinMax mParticlePower; + + /* + * Vector changing of particles: + */ + MinMax mParticleGravity; + MinMax mParticleRandomnes; + MinMax mParticleBounce; + + /* + * Properties of targeting particles: + */ + Particle *mParticleTarget; + MinMax mParticleAcceleration; + MinMax mParticleDieDistance; + MinMax mParticleMomentum; + + /* + * Behavior over time of the particles: + */ + MinMax mParticleLifetime; + MinMax mParticleFadeOut; + MinMax mParticleFadeIn; + + Map *mMap; /**< Map the particles are spawned on */ + + MinMax mOutput; /**< Number of particles spawned per update */ + + Image *mParticleImage; /**< Particle image, if used */ + + /** Filename of particle animation file */ + Animation mParticleAnimation; + + /** List of emitters the spawned particles are equipped with */ + std::list mParticleChildEmitters; +}; +#endif diff --git a/src/resources/animation.h b/src/resources/animation.h index d0d11c69..aad93cda 100644 --- a/src/resources/animation.h +++ b/src/resources/animation.h @@ -54,7 +54,7 @@ class Animation Animation(); /** - * Appends a new animation at the end of the sequence + * Appends a new animation at the end of the sequence. */ void addFrame(Image *image, unsigned int delay, int offsetX, int offsetY); diff --git a/src/resources/image.cpp b/src/resources/image.cpp index a27783d4..d7d4e64b 100644 --- a/src/resources/image.cpp +++ b/src/resources/image.cpp @@ -187,19 +187,22 @@ Image* Image::load(void *buffer, unsigned int bufferSize, bool hasAlpha = false; - // Figure out whether the image uses its alpha layer - for (int i = 0; i < tmpImage->w * tmpImage->h; ++i) + if (tmpImage->format->BitsPerPixel == 32) { - Uint8 r, g, b, a; - SDL_GetRGBA( - ((Uint32*) tmpImage->pixels)[i], - tmpImage->format, - &r, &g, &b, &a); - - if (a != 255) + // Figure out whether the image uses its alpha layer + for (int i = 0; i < tmpImage->w * tmpImage->h; ++i) { - hasAlpha = true; - break; + Uint8 r, g, b, a; + SDL_GetRGBA( + ((Uint32*) tmpImage->pixels)[i], + tmpImage->format, + &r, &g, &b, &a); + + if (a != 255) + { + hasAlpha = true; + break; + } } } diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index fda8916d..2230cb6a 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -231,6 +231,30 @@ MapReader::readMap(xmlNodePtr node, const std::string &path) { readProperties(childNode, map); } + else if (xmlStrEqual(childNode->name, BAD_CAST "objectgroup")) + { + for_each_xml_child_node(objectNode, childNode) + { + if (xmlStrEqual(objectNode->name, BAD_CAST "object")) + { + std::string objName = XML::getProperty(objectNode, "name", ""); + std::string objType = XML::getProperty(objectNode, "type", ""); + int objX = XML::getProperty(objectNode, "x", 0); + int objY = XML::getProperty(objectNode, "y", 0); + + logger->log("- Loading object name: %s type: %s at %d:%d", + objName.c_str(), objType.c_str(), objX, objY); + if (objType == "PARTICLE_EFFECT") + { + map->addParticleEffect(objName, objX, objY); + } + else + { + logger->log(" Warning: Unknown object type"); + } + } + } + } } map->initializeOverlays(); diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp index ac3ac3bc..89afc549 100644 --- a/src/resources/monsterdb.cpp +++ b/src/resources/monsterdb.cpp @@ -83,6 +83,27 @@ MonsterDB::load() currentInfo->setName (XML::getProperty(monsterNode, "name", "unnamed")); + std::string targetCursor; + targetCursor = XML::getProperty(monsterNode, "targetCursor", "medium"); + if (targetCursor == "small") + { + currentInfo->setTargetCursorSize(Being::TC_SMALL); + } + else if (targetCursor == "medium") + { + currentInfo->setTargetCursorSize(Being::TC_MEDIUM); + } + else if (targetCursor == "large") + { + currentInfo->setTargetCursorSize(Being::TC_LARGE); + } + else + { + logger->log("MonsterDB: Unknown target cursor type \"%s\" for %s - using medium sized one", + targetCursor.c_str(), currentInfo->getName().c_str()); + currentInfo->setTargetCursorSize(Being::TC_MEDIUM); + } + //iterate s and s for_each_xml_child_node(spriteNode, monsterNode) { diff --git a/src/resources/monsterinfo.h b/src/resources/monsterinfo.h index 05d4c014..d2a0a2c8 100644 --- a/src/resources/monsterinfo.h +++ b/src/resources/monsterinfo.h @@ -28,6 +28,9 @@ #include #include +#include "../being.h" + + enum SoundEvent { EVENT_HIT, @@ -62,7 +65,11 @@ class MonsterInfo setSprite(std::string filename) { mSprite = filename; } void - addSound (SoundEvent event, std::string filename); + setTargetCursorSize(Being::TargetCursorSize targetCursorSize) + { mTargetCursorSize = targetCursorSize; } + + void + addSound(SoundEvent event, std::string filename); const std::string& getName () const { return mName; }; @@ -70,13 +77,16 @@ class MonsterInfo const std::string& getSprite () const { return mSprite; }; + const Being::TargetCursorSize + getTargetCursorSize() const { return mTargetCursorSize; } + std::string getSound (SoundEvent event) const; private: std::string mName; std::string mSprite; - + Being::TargetCursorSize mTargetCursorSize; std::map* > mSounds; }; diff --git a/src/simpleanimation.cpp b/src/simpleanimation.cpp index 5fc35bcd..18e732ef 100644 --- a/src/simpleanimation.cpp +++ b/src/simpleanimation.cpp @@ -23,6 +23,91 @@ #include "simpleanimation.h" +#include "graphics.h" +#include "log.h" + +#include "resources/image.h" +#include "resources/resourcemanager.h" +#include "resources/imageset.h" + + +SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode): + mAnimationTime(0), + mAnimationPhase(0) +{ + mAnimation = new Animation(); + + ImageSet *imageset = ResourceManager::getInstance()->getImageSet( + XML::getProperty(animationNode, "imageset", ""), + XML::getProperty(animationNode, "width", 0), + XML::getProperty(animationNode, "height", 0) + ); + + // Get animation frames + for ( xmlNodePtr frameNode = animationNode->xmlChildrenNode; + frameNode != NULL; + frameNode = frameNode->next) + { + int delay = XML::getProperty(frameNode, "delay", 0); + int offsetX = XML::getProperty(frameNode, "offsetX", 0); + int offsetY = XML::getProperty(frameNode, "offsetY", 0); + offsetY -= imageset->getHeight() - 32; + offsetX -= imageset->getWidth() / 2 - 16; + + if (xmlStrEqual(frameNode->name, BAD_CAST "frame")) + { + int index = XML::getProperty(frameNode, "index", -1); + + if (index < 0) + { + logger->log("No valid value for 'index'"); + continue; + } + + Image *img = imageset->get(index); + + if (!img) + { + logger->log("No image at index " + (index)); + continue; + } + + mAnimation->addFrame(img, delay, offsetX, offsetY); + } + else if (xmlStrEqual(frameNode->name, BAD_CAST "sequence")) + { + int start = XML::getProperty(frameNode, "start", -1); + int end = XML::getProperty(frameNode, "end", -1); + + if (start < 0 || end < 0) + { + logger->log("No valid value for 'start' or 'end'"); + continue; + } + + while (end >= start) + { + Image *img = imageset->get(start); + + if (!img) + { + logger->log("No image at index " + + (start)); + continue; + } + + mAnimation->addFrame(img, delay, offsetX, offsetY); + start++; + } + } + else if (xmlStrEqual(frameNode->name, BAD_CAST "end")) + { + mAnimation->addTerminator(); + } + } + + mCurrentFrame = mAnimation->getFrame(0); +} void SimpleAnimation::update(unsigned int timePassed) { diff --git a/src/simpleanimation.h b/src/simpleanimation.h index a56c31da..561c540d 100644 --- a/src/simpleanimation.h +++ b/src/simpleanimation.h @@ -26,7 +26,10 @@ #include "resources/animation.h" +#include "utils/xml.h" + class Frame; +class Graphics; /** * This class is a leightweight alternative to the AnimatedSprite class. @@ -35,6 +38,9 @@ class Frame; class SimpleAnimation { public: + /** + * Creates a simple animation with an already created animation. + */ SimpleAnimation(Animation *animation): mAnimation(animation), mAnimationTime(0), @@ -42,6 +48,11 @@ class SimpleAnimation mCurrentFrame(mAnimation->getFrame(0)) {}; + /** + * Creates a simple animation that creates its animation from XML Data. + */ + SimpleAnimation(xmlNodePtr animationNode); + ~SimpleAnimation(); void update(unsigned int timePassed); @@ -55,10 +66,10 @@ class SimpleAnimation /** Time in game ticks the current frame is shown. */ unsigned int mAnimationTime; - /** Index of current animation frame. */ + /** Index of current animation phase. */ unsigned int mAnimationPhase; - /** Current animation frame. */ + /** Current animation phase. */ Frame *mCurrentFrame; }; diff --git a/src/sprite.h b/src/sprite.h index 51811149..89780519 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -49,6 +49,22 @@ class Sprite virtual void draw(Graphics *graphics, int offsetX, int offsetY) const = 0; + /** + * Returns the horizontal size of the sprites graphical representation + * in pixels or 0 when it is undefined. + */ + virtual int + getWidth() const + { return 0; } + + /** + * Returns the vertical size of the sprites graphical representation + * in pixels or 0 when it is undefined. + */ + virtual int + getHeight() const + { return 0; } + /** * Returns the pixel Y coordinate of the sprite. */ diff --git a/src/textparticle.cpp b/src/textparticle.cpp new file mode 100644 index 00000000..dd01d2fe --- /dev/null +++ b/src/textparticle.cpp @@ -0,0 +1,64 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "textparticle.h" + +#include "graphics.h" + +TextParticle::TextParticle(Map *map, const std::string &text, + int colorR, int colorG, int colorB, gcn::Font *font): + Particle(map), + mText(text), + mTextFont(font), + mColorR(colorR), + mColorG(colorG), + mColorB(colorB) +{ +} + +void TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const +{ + if (!mAlive) + return; + + int screenX = (int)mPosX + offsetX; + int screenY = (int)mPosY - int(mPosZ) + offsetY; + + int alpha = 255; + + if (mLifetimeLeft > -1 && mLifetimeLeft < mFadeOut) + { + alpha *= mLifetimeLeft; + alpha /= mFadeOut; + }; + + if (mLifetimePast < mFadeIn) + { + alpha *= mLifetimePast; + alpha /= mFadeIn; + } + + graphics->setFont(mTextFont); + graphics->setColor(gcn::Color (mColorR, mColorG, mColorB, alpha)); + graphics->drawText(mText, screenX, screenY, gcn::Graphics::CENTER); +} diff --git a/src/textparticle.h b/src/textparticle.h new file mode 100644 index 00000000..b365c885 --- /dev/null +++ b/src/textparticle.h @@ -0,0 +1,53 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TEXTPARTICLE_H +#define _TEXTPARTICLE_H + +#include "particle.h" + +#include + +#include "guichanfwd.h" + +class TextParticle : public Particle +{ + public: + TextParticle(Map *map, const std::string &text, + int colorR, int colorG, int colorB, gcn::Font *font); + /** + * Draws the particle image + */ + virtual void + draw(Graphics *graphics, int offsetX, int offsetY) const; + + // hack to improve text visibility + virtual int getPixelY() const { return (int)(mPosY + mPosZ); } + + private: + std::string mText; /**< Text of the particle */ + gcn::Font *mTextFont; /**< Font used for drawing the text */ + int mColorR, mColorG, mColorB; /**< Color used for drawing the text */ +}; + +#endif diff --git a/src/utils/fastsqrt.h b/src/utils/fastsqrt.h new file mode 100644 index 00000000..8da1d354 --- /dev/null +++ b/src/utils/fastsqrt.h @@ -0,0 +1,24 @@ +/* A very fast function to calculate the approximate inverse square root of a + * floating point value and a helper function that uses it for getting the + * normal squareroot. For an explanation of the inverse squareroot function + * read: + * http://www.math.purdue.edu/~clomont/Math/Papers/2003/InvSqrt.pdf + * + * Unfortunately the original creator of this function seems to be unknown. + */ + +float fastInvSqrt(float x) +{ + union { int i; float x; } tmp; + float xhalf = 0.5f * x; + tmp.x = x; + tmp.i = 0x5f375a86 - (tmp.i >> 1); + x = tmp.x; + x = x * (1.5f - xhalf * x * x); + return x; +} + +float fastSqrt(float x) +{ + return 1.0f / fastInvSqrt(x); +} diff --git a/src/utils/minmax.h b/src/utils/minmax.h new file mode 100644 index 00000000..1add2b7e --- /dev/null +++ b/src/utils/minmax.h @@ -0,0 +1,47 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/** + * Returns a random numeric value that is larger than or equal min and smaller + * than max + */ + +template struct MinMax +{ + void set(T min, T max) + { + minVal=min; maxVal=max; + } + + void set(T val) + { + set(val, val); + } + + T value() + { + return (T)(minVal + (maxVal - minVal) * (rand() / ((double) RAND_MAX + 1))); + } + + T minVal; + T maxVal; +}; diff --git a/src/utils/wingettimeofday.h b/src/utils/wingettimeofday.h index a5537f39..28afb7e5 100644 --- a/src/utils/wingettimeofday.h +++ b/src/utils/wingettimeofday.h @@ -1,113 +1,113 @@ -/* - * The Mana World - * Copyright 2004 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id$ - */ - -#ifndef _TMW_WINGETTIMEOFDAY_H_ -#define _TMW_WINGETTIMEOFDAY_H_ - -#ifdef WIN32 - -#include - -/* - * the function gettimeofday() is available on UNIX but not on windows. - * this header defines a windows implementation as a - * GetSystemTimeAsFileTime() wrapper. - */ - -int gettimeofday(struct timeval* tv, void *tz) -/*--------------------------------------------------------------- - * Copyright (c) 1999,2000,2001,2002,2003 - * The Board of Trustees of the University of Illinois - * All Rights Reserved. - *--------------------------------------------------------------- - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software (Iperf) and associated - * documentation files (the "Software"), to deal in the Software - * without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and - * the following disclaimers. - * - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimers in the documentation and/or other materials - * provided with the distribution. - * - * - * Neither the names of the University of Illinois, NCSA, - * nor the names of its contributors may be used to endorse - * or promote products derived from this Software without - * specific prior written permission. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ________________________________________________________________ - * National Laboratory for Applied Network Research - * National Center for Supercomputing Applications - * University of Illinois at Urbana-Champaign - * http://www.ncsa.uiuc.edu - * ________________________________________________________________ - * - * gettimeofday.c - * by Mark Gates - * ------------------------------------------------------------------- - * A (hack) implementation of gettimeofday for Windows. - * Since I send sec/usec in UDP packets, this made the most sense. - * ------------------------------------------------------------------- */ -{ - FILETIME time; - double timed; - - GetSystemTimeAsFileTime( &time ); - - // Apparently Win32 has units of 1e-7 sec (tenths of microsecs) - // 4294967296 is 2^32, to shift high word over - // 11644473600 is the number of seconds between - // the Win32 epoch 1601-Jan-01 and the Unix epoch 1970-Jan-01 - // Tests found floating point to be 10x faster than 64bit int math. - - timed = ((time.dwHighDateTime * 4294967296e-7) - 11644473600.0) + - (time.dwLowDateTime * 1e-7); - - tv->tv_sec = (long) timed; - tv->tv_usec = (long) ((timed - tv->tv_sec) * 1e6); - - return 0; -} - - -#endif // WIN32 -#endif +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_WINGETTIMEOFDAY_H_ +#define _TMW_WINGETTIMEOFDAY_H_ + +#ifdef WIN32 + +#include + +/* + * the function gettimeofday() is available on UNIX but not on windows. + * this header defines a windows implementation as a + * GetSystemTimeAsFileTime() wrapper. + */ + +int gettimeofday(struct timeval* tv, void *tz) +/*--------------------------------------------------------------- + * Copyright (c) 1999,2000,2001,2002,2003 + * The Board of Trustees of the University of Illinois + * All Rights Reserved. + *--------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software (Iperf) and associated + * documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and + * the following disclaimers. + * + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimers in the documentation and/or other materials + * provided with the distribution. + * + * + * Neither the names of the University of Illinois, NCSA, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without + * specific prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * ________________________________________________________________ + * National Laboratory for Applied Network Research + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * http://www.ncsa.uiuc.edu + * ________________________________________________________________ + * + * gettimeofday.c + * by Mark Gates + * ------------------------------------------------------------------- + * A (hack) implementation of gettimeofday for Windows. + * Since I send sec/usec in UDP packets, this made the most sense. + * ------------------------------------------------------------------- */ +{ + FILETIME time; + double timed; + + GetSystemTimeAsFileTime( &time ); + + // Apparently Win32 has units of 1e-7 sec (tenths of microsecs) + // 4294967296 is 2^32, to shift high word over + // 11644473600 is the number of seconds between + // the Win32 epoch 1601-Jan-01 and the Unix epoch 1970-Jan-01 + // Tests found floating point to be 10x faster than 64bit int math. + + timed = ((time.dwHighDateTime * 4294967296e-7) - 11644473600.0) + + (time.dwLowDateTime * 1e-7); + + tv->tv_sec = (long) timed; + tv->tv_usec = (long) ((timed - tv->tv_sec) * 1e6); + + return 0; +} + + +#endif // WIN32 +#endif diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp index 7c917dc0..e30450f0 100644 --- a/src/utils/xml.cpp +++ b/src/utils/xml.cpp @@ -39,6 +39,20 @@ namespace XML return ret; } + double + getFloatProperty(xmlNodePtr node, const char* name, double def) + { + double &ret = def; + + xmlChar *prop = xmlGetProp(node, BAD_CAST name); + if (prop) { + ret = atof((char*)prop); + xmlFree(prop); + } + + return ret; + } + std::string getProperty(xmlNodePtr node, const char *name, const std::string &def) { @@ -51,4 +65,13 @@ namespace XML return def; } + + xmlNodePtr findFirstChildByName(xmlNodePtr parent, const char *name) + { + for_each_xml_child_node(child, parent) + if (xmlStrEqual(child->name, BAD_CAST name)) + return child; + + return NULL; + } } diff --git a/src/utils/xml.h b/src/utils/xml.h index db4c264a..ef3bad3d 100644 --- a/src/utils/xml.h +++ b/src/utils/xml.h @@ -39,11 +39,22 @@ namespace XML int getProperty(xmlNodePtr node, const char *name, int def); + /** + * Gets an floating point property from an xmlNodePtr. + */ + double + getFloatProperty(xmlNodePtr node, const char *name, double def); + /** * Gets a string property from an xmlNodePtr. */ std::string getProperty(xmlNodePtr node, const char *name, const std::string &def); + + /** + * Finds the first child node with the given name + */ + xmlNodePtr findFirstChildByName(xmlNodePtr parent, const char *name); } #define for_each_xml_child_node(var, parent) \ -- cgit v1.2.3-70-g09d2 From 8d74404ce57618922b42913d94709f9c49d65d5d Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Sat, 30 Jun 2007 15:07:03 +0000 Subject: Changed include order to avoid a problem with guichan on windows. Implemented getting the direction of attacks from the server. --- ChangeLog | 7 +++++++ src/main.cpp | 5 +---- src/net/beinghandler.cpp | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 7e9691bd..c0bc698b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2007-06-30 Philipp Sehmisch + + * src/main.cpp: Changed include order to avoid a problem with guichan + on windows. + * src/net/beinghandler.cpp: Implemented getting the direction of + attacks from the server. + 2007-06-16 Guillaume Melquiond * src/resources/image.cpp: Set GL texture index to zero when an image diff --git a/src/main.cpp b/src/main.cpp index 58c563ab..c39582f2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,10 +30,6 @@ #include #include -#ifdef WIN32 -#include -#endif - #include #include #include @@ -43,6 +39,7 @@ #ifndef WIN32 #include #include +#include #endif #if defined __APPLE__ #include diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index f82a0fa8..e88914ac 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -523,6 +523,7 @@ void BeingHandler::handleBeingAttackMessage(MessageIn &msg) if (!being) return; being->setAction(Being::ATTACK); + being->setDirection(msg.readByte()); } void BeingHandler::handleBeingsDamageMessage(MessageIn &msg) -- cgit v1.2.3-70-g09d2 From 038388c2d1aeab8d653a8129e5ff95b4c83b2f88 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Thu, 12 Jul 2007 19:39:32 +0000 Subject: Added support for visible equipment. --- ChangeLog | 7 ++++++- src/net/beinghandler.cpp | 22 ++++++++++++++++++++++ src/net/beinghandler.h | 1 + src/net/protocol.h | 3 ++- 4 files changed, 31 insertions(+), 2 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 2ca0a272..641e18a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,9 @@ -2007-07-11 Bjørn Lindeijer +2007-07-12 Guillaume Melquiond + + * src/net/beinghandler.cpp, src/net/beinghandler.h, src/net/protocol.h: + Added support for visible equipment. + +2007-07-11 Bjørn Lindeijer * src/gui/window.cpp: Fixed resizing windows by their resize grip. diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index e88914ac..a6bc7fc3 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -60,6 +60,7 @@ BeingHandler::BeingHandler() GPMSG_BEINGS_MOVE, GPMSG_BEINGS_DAMAGE, GPMSG_BEING_ACTION_CHANGE, + GPMSG_BEING_LOOKS_CHANGE, 0 }; handledMessages = _messages; @@ -96,6 +97,9 @@ void BeingHandler::handleMessage(MessageIn &msg) case GPMSG_BEING_ACTION_CHANGE: handleBeingActionChangeMessage(msg); break; + case GPMSG_BEING_LOOKS_CHANGE: + handleBeingLooksChangeMessage(msg); + break; /* case SMSG_BEING_VISIBLE: @@ -411,6 +415,14 @@ void BeingHandler::handleMessage(MessageIn &msg) } } +static void handleLooks(Being *being, MessageIn &msg) +{ + being->setWeapon(msg.readShort()); + being->setVisibleEquipment(Being::HAT_SPRITE, msg.readShort()); + being->setVisibleEquipment(Being::TOPCLOTHES_SPRITE, msg.readShort()); + being->setVisibleEquipment(Being::BOTTOMCLOTHES_SPRITE, msg.readShort()); +} + void BeingHandler::handleBeingEnterMessage(MessageIn &msg) { @@ -443,7 +455,9 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) being->mY = py; being->setDestination(px, py); being->setAction(action); + handleLooks(being, msg); } break; + case OBJECT_MONSTER: { int monsterId = msg.readShort(); @@ -546,3 +560,11 @@ void BeingHandler::handleBeingActionChangeMessage(MessageIn &msg) being->setAction((Being::Action) msg.readByte()); } + +void BeingHandler::handleBeingLooksChangeMessage(MessageIn &msg) +{ + Being *being = beingManager->findBeing(msg.readShort()); + if (!being) return; + handleLooks(being, msg); +} + diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h index 7a018950..d2a332a8 100644 --- a/src/net/beinghandler.h +++ b/src/net/beinghandler.h @@ -40,6 +40,7 @@ class BeingHandler : public MessageHandler void handleBeingsMoveMessage(MessageIn &msg); void handleBeingsDamageMessage(MessageIn &msg); void handleBeingActionChangeMessage(MessageIn &msg); + void handleBeingLooksChangeMessage(MessageIn &msg); }; #endif diff --git a/src/net/protocol.h b/src/net/protocol.h index b5dc2996..ba16e99d 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -163,10 +163,11 @@ enum { GPMSG_INVENTORY_FULL = 0x0121, // { B slot, W item id [, B amount] }* GPMSG_PLAYER_ATTRIBUTE_UPDATE = 0x0130, // { W attribute, W value }* GPMSG_BEING_ENTER = 0x0200, // B type, W being id, B action, W*2 position - // player: S name, B hair style, B hair color, B gender + // player: S name, B hair style, B hair color, B gender, W weapon, W hat, W top clothes, W bottom clothes // monster: W type id GPMSG_BEING_LEAVE = 0x0201, // W being id GPMSG_ITEM_APPEAR = 0x0202, // W item id, W*2 position + GPMSG_BEING_LOOKS_CHANGE = 0x0210, // W weapon, W hat, W top clothes, W bottom clothes PGMSG_WALK = 0x0260, // W*2 destination PGMSG_ACTION_CHANGE = 0x0270, // B Action GPMSG_BEING_ACTION_CHANGE = 0x0271, // W being id, B action -- cgit v1.2.3-70-g09d2 From a138d81a27ed41062a677b1a54309b01f415df62 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sat, 14 Jul 2007 13:52:28 +0000 Subject: Reduced size of equipment packets. --- ChangeLog | 7 ++++++- src/net/beinghandler.cpp | 32 ++++++++++++++++++++++++++++---- src/net/protocol.h | 2 +- 3 files changed, 35 insertions(+), 6 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 641e18a3..634562d0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,9 @@ -2007-07-12 Guillaume Melquiond +2007-07-14 Guillaume Melquiond + + * src/net/beinghandler.cpp, src/net/protocol.h: Reduced size of + equipment packets. + +2007-07-12 Guillaume Melquiond * src/net/beinghandler.cpp, src/net/beinghandler.h, src/net/protocol.h: Added support for visible equipment. diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index a6bc7fc3..51609b1d 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -417,10 +417,34 @@ void BeingHandler::handleMessage(MessageIn &msg) static void handleLooks(Being *being, MessageIn &msg) { - being->setWeapon(msg.readShort()); - being->setVisibleEquipment(Being::HAT_SPRITE, msg.readShort()); - being->setVisibleEquipment(Being::TOPCLOTHES_SPRITE, msg.readShort()); - being->setVisibleEquipment(Being::BOTTOMCLOTHES_SPRITE, msg.readShort()); + // Order of sent slots. Has to be in sync with the server code. + static int const nb_slots = 4; + static int const slots[nb_slots] = + { Being::WEAPON_SPRITE, Being::HAT_SPRITE, Being::TOPCLOTHES_SPRITE, + Being::BOTTOMCLOTHES_SPRITE }; + + int mask = msg.readByte(); + if (mask & (1 << 8)) + { + // The equipment has to be cleared first. + being->setWeaponById(0); + for (int i = 0; i < nb_slots; ++i) + { + if (slots[i] != Being::WEAPON_SPRITE) + being->setVisibleEquipment(slots[i], 0); + } + } + + // Fill slots enumerated by the bitmask. + for (int i = 0; i < nb_slots; ++i) + { + if (!(mask & (1 << i))) continue; + int id = msg.readShort(); + if (slots[i] != Being::WEAPON_SPRITE) + being->setVisibleEquipment(slots[i], id); + else + being->setWeaponById(id); + } } void diff --git a/src/net/protocol.h b/src/net/protocol.h index ba16e99d..f13b6a02 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -163,7 +163,7 @@ enum { GPMSG_INVENTORY_FULL = 0x0121, // { B slot, W item id [, B amount] }* GPMSG_PLAYER_ATTRIBUTE_UPDATE = 0x0130, // { W attribute, W value }* GPMSG_BEING_ENTER = 0x0200, // B type, W being id, B action, W*2 position - // player: S name, B hair style, B hair color, B gender, W weapon, W hat, W top clothes, W bottom clothes + // player: S name, B hair style, B hair color, B gender, B item bitmask, { W item id }* // monster: W type id GPMSG_BEING_LEAVE = 0x0201, // W being id GPMSG_ITEM_APPEAR = 0x0202, // W item id, W*2 position -- cgit v1.2.3-70-g09d2 From 430bbe292eb51b3f3bb7b356d8b218b28bed0ff4 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Mon, 23 Jul 2007 16:51:13 +0000 Subject: Converted NPC code to new server. --- ChangeLog | 5 +++++ src/beingmanager.cpp | 12 ------------ src/net/beinghandler.cpp | 13 ++++++++++++- src/net/gameserver/player.cpp | 17 ++++++++++++++++- src/net/gameserver/player.h | 4 +++- src/net/npchandler.cpp | 34 ++++++++++++++-------------------- src/net/protocol.h | 6 ++++++ src/npc.cpp | 24 ++++++------------------ src/npc.h | 2 +- 9 files changed, 63 insertions(+), 54 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 25de29df..90c563d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,11 @@ * src/main.cpp, src/game.cpp: Fixed segfault on exit when OpenGL configuration changed. + * src/beingmanager.cpp: Removed dead code. + * src/npc.cpp, src/npc.h, src/net/protocol.h, src/net/npchandler.cpp, + src/net/gameserver/player.cpp, src/net/gameserver/player.h: Converted + to new server. + * src/beinghandler.cpp: Added support for NPCs. 2007-07-22 Eugenio Favalli diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp index 14b4ea7e..a5be17d2 100644 --- a/src/beingmanager.cpp +++ b/src/beingmanager.cpp @@ -72,19 +72,7 @@ Being* BeingManager::createBeing(Uint16 id, Uint16 job) else being = new Being(id, job, mMap); - // Player or NPC - if (job < 200) - { - // XXX Convert for new server - /* - MessageOut outMsg(mNetwork); - outMsg.writeInt16(0x0094); - outMsg.writeInt32(id);//readLong(2)); - */ - } - mBeings.push_back(being); - return being; } diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 51609b1d..bce2c3b8 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -486,13 +486,24 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) { int monsterId = msg.readShort(); Being *being; - being = beingManager->createBeing(id, 1002 + monsterId); + being = beingManager->createBeing(id, monsterId); being->setWalkSpeed(150); // TODO being->mX = px; being->mY = py; being->setDestination(px, py); being->setAction(action); } break; + + case OBJECT_NPC: + { + int npcId = msg.readShort(); + Being *being; + being = beingManager->createBeing(id, npcId); + being->mX = px; + being->mY = py; + being->setDestination(px, py); + being->setAction(action); + } break; } } diff --git a/src/net/gameserver/player.cpp b/src/net/gameserver/player.cpp index 9af0c238..daf76c3e 100644 --- a/src/net/gameserver/player.cpp +++ b/src/net/gameserver/player.cpp @@ -67,7 +67,7 @@ void Net::GameServer::Player::equip(int slot) Net::GameServer::connection->send(msg); } -void Net::GameServer::Player::attack(unsigned char direction) +void Net::GameServer::Player::attack(int direction) { MessageOut msg(PGMSG_ATTACK); msg.writeByte(direction); @@ -80,3 +80,18 @@ void Net::GameServer::Player::changeAction(Being::Action action) msg.writeByte(action); Net::GameServer::connection->send(msg); } + +void Net::GameServer::Player::talkToNPC(int id, bool restart) +{ + MessageOut msg(restart ? PGMSG_NPC_TALK : PGMSG_NPC_TALK_NEXT); + msg.writeShort(id); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::selectFromNPC(int id, int choice) +{ + MessageOut msg(PGMSG_NPC_SELECT); + msg.writeShort(id); + msg.writeByte(choice); + Net::GameServer::connection->send(msg); +} diff --git a/src/net/gameserver/player.h b/src/net/gameserver/player.h index 7cc45486..cb6927ba 100644 --- a/src/net/gameserver/player.h +++ b/src/net/gameserver/player.h @@ -39,8 +39,10 @@ namespace Net void pickUp(int x, int y); void drop(int slot, int amount); void equip(int slot); - void attack(unsigned char direction); + void attack(int direction); void changeAction(Being::Action action); + void talkToNPC(int id, bool restart); + void selectFromNPC(int id, int choice); } } } diff --git a/src/net/npchandler.cpp b/src/net/npchandler.cpp index 02204a84..888a3a29 100644 --- a/src/net/npchandler.cpp +++ b/src/net/npchandler.cpp @@ -38,10 +38,8 @@ extern NpcTextDialog *npcTextDialog; NPCHandler::NPCHandler() { static const Uint16 _messages[] = { - SMSG_NPC_CHOICE, - SMSG_NPC_MESSAGE, - SMSG_NPC_NEXT, - SMSG_NPC_CLOSE, + GPMSG_NPC_CHOICE, + GPMSG_NPC_MESSAGE, 0 }; handledMessages = _messages; @@ -49,30 +47,26 @@ NPCHandler::NPCHandler() void NPCHandler::handleMessage(MessageIn &msg) { - int id; + Being *being = beingManager->findBeing(msg.readShort()); + if (!being || being->getType() != Being::NPC) + { + return; + } + + current_npc = static_cast< NPC * >(being); + std::string text = msg.readString(msg.getUnreadLength()); switch (msg.getId()) { - case SMSG_NPC_CHOICE: - msg.readShort(); // length - id = msg.readLong(); - current_npc = dynamic_cast(beingManager->findBeing(id)); - npcListDialog->parseItems(msg.readString(msg.getLength() - 8)); + case GPMSG_NPC_CHOICE: + npcListDialog->parseItems(text); npcListDialog->setVisible(true); break; - case SMSG_NPC_MESSAGE: - msg.readShort(); // length - id = msg.readLong(); - current_npc = dynamic_cast(beingManager->findBeing(id)); - npcTextDialog->addText(msg.readString(msg.getLength() - 8)); + case GPMSG_NPC_MESSAGE: + npcTextDialog->addText(text); npcListDialog->setVisible(false); npcTextDialog->setVisible(true); break; - - case SMSG_NPC_NEXT: - case SMSG_NPC_CLOSE: - // Next/Close button in NPC dialog, currently unused - break; } } diff --git a/src/net/protocol.h b/src/net/protocol.h index f13b6a02..8fe7e1b6 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -165,6 +165,7 @@ enum { GPMSG_BEING_ENTER = 0x0200, // B type, W being id, B action, W*2 position // player: S name, B hair style, B hair color, B gender, B item bitmask, { W item id }* // monster: W type id + // npc: W type id GPMSG_BEING_LEAVE = 0x0201, // W being id GPMSG_ITEM_APPEAR = 0x0202, // W item id, W*2 position GPMSG_BEING_LOOKS_CHANGE = 0x0210, // W weapon, W hat, W top clothes, W bottom clothes @@ -177,6 +178,11 @@ enum { GPMSG_BEING_ATTACK = 0x0291, // W being id PGMSG_SAY = 0x02A0, // S text GPMSG_SAY = 0x02A1, // W being id, S text + GPMSG_NPC_CHOICE = 0x02B0, // W being id, B* text + GPMSG_NPC_MESSAGE = 0x02B1, // W being id, B* text + PGMSG_NPC_TALK = 0x02B2, // W being id + PGMSG_NPC_TALK_NEXT = 0x02B3, // W being id + PGMSG_NPC_SELECT = 0x02B4, // W being id, B choice PGMSG_USE_ITEM = 0x0300, // L item id GPMSG_USE_RESPONSE = 0x0301, // B error GPMSG_BEINGS_DAMAGE = 0x0310, // { W being id, W amount }* diff --git a/src/npc.cpp b/src/npc.cpp index 2d291104..f65c8d19 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -27,6 +27,8 @@ #include "graphics.h" #include "gui/gui.h" +#include "net/messageout.h" +#include "net/gameserver/player.h" NPC *current_npc = 0; @@ -57,34 +59,20 @@ NPC::drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) void NPC::talk() { - // XXX Convert for new server - /* - MessageOut outMsg(CMSG_NPC_TALK); - outMsg.writeLong(mId); - outMsg.writeByte(0); + Net::GameServer::Player::talkToNPC(mId, true); current_npc = this; - */ } void NPC::nextDialog() { - // XXX Convert for new server - /* - MessageOut outMsg(CMSG_NPC_NEXT_REQUEST); - outMsg.writeLong(mId); - */ + Net::GameServer::Player::talkToNPC(mId, false); } void -NPC::dialogChoice(char choice) +NPC::dialogChoice(int choice) { - // XXX Convert for new server - /* - MessageOut outMsg(CMSG_NPC_LIST_CHOICE); - outMsg.writeLong(mId); - outMsg.writeByte(choice); - */ + Net::GameServer::Player::selectFromNPC(mId, choice); } /* diff --git a/src/npc.h b/src/npc.h index cf5defbc..90570b36 100644 --- a/src/npc.h +++ b/src/npc.h @@ -41,7 +41,7 @@ class NPC : public Being void talk(); void nextDialog(); - void dialogChoice(char choice); + void dialogChoice(int choice); void buy(); void sell(); -- cgit v1.2.3-70-g09d2 From 88b3f92061c703fdf6cf0f970684fb77de6d8795 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Wed, 25 Jul 2007 20:22:41 +0000 Subject: Added being speed to protocol. --- ChangeLog | 5 +++++ src/net/beinghandler.cpp | 12 ++++++++---- src/net/protocol.h | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 9c33ff8e..b27becc3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2007-07-25 Guillaume Melquiond + + * src/net/beinghandler.cpp, src/net/protocol.h: Added being speed to + protocol. + 2007-07-23 Eugenio Favalli * data/maps/new_1-1.tar.gz, data/maps/new_3-1.tar.gz: Fixed warp diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index bce2c3b8..44b1a7af 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -487,7 +487,6 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) int monsterId = msg.readShort(); Being *being; being = beingManager->createBeing(id, monsterId); - being->setWalkSpeed(150); // TODO being->mX = px; being->mY = py; being->setDestination(px, py); @@ -519,16 +518,17 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) { while (msg.getUnreadLength()) { - Uint16 id = msg.readShort(); - Uint8 flags = msg.readByte(); + int id = msg.readShort(); + int flags = msg.readByte(); Being *being = beingManager->findBeing(id); - int sx = 0, sy = 0, dx = 0, dy = 0; + int sx = 0, sy = 0, dx = 0, dy = 0, speed = 0; if (flags & MOVING_POSITION) { Uint16 sx2, sy2; msg.readCoordinates(sx2, sy2); sx = sx2 * 32 + 16; sy = sy2 * 32 + 16; + speed = msg.readByte(); } if (flags & MOVING_DESTINATION) { @@ -544,6 +544,10 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) { continue; } + if (speed) + { + being->setWalkSpeed(speed * 10); + } if (abs(being->mX - sx) + abs(being->mY - sy) > 4 * 32) { // Too large a desynchronization. diff --git a/src/net/protocol.h b/src/net/protocol.h index 8fe7e1b6..1a20b0a4 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -172,7 +172,7 @@ enum { PGMSG_WALK = 0x0260, // W*2 destination PGMSG_ACTION_CHANGE = 0x0270, // B Action GPMSG_BEING_ACTION_CHANGE = 0x0271, // W being id, B action - GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, C position] [, W*2 destination] }* + GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, C position, B speed] [, W*2 destination] }* GPMSG_ITEMS = 0x0281, // { W item id, W*2 position }* PGMSG_ATTACK = 0x0290, // B direction GPMSG_BEING_ATTACK = 0x0291, // W being id -- cgit v1.2.3-70-g09d2 From 998920e7da3c1b27f2d7cc5f8b5a37efbf5663e5 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Wed, 8 Aug 2007 14:40:09 +0000 Subject: Fixed position of the cleaning bit for looks, so that it actually fits into network data. --- ChangeLog | 4 ++++ src/equipment.cpp | 2 +- src/equipment.h | 10 +++++++--- src/localplayer.cpp | 1 + src/net/beinghandler.cpp | 3 ++- 5 files changed, 15 insertions(+), 5 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 3b6f5d94..5e921f9f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ * src/gui/equipmentwindow.cpp, data/graphics/gui/Makefile.am, data/graphics/images/EquipBackground.png: Moved equipment background to the gui directory. Changed name to lowercase only. + * src/localplayer.cpp, src/equipment.h, src/equipment.cpp: Ensured that + equipment is cleared at the same time as the inventory. + * src/net/beinghandler.cpp: Fixed position of the cleaning bit for + looks, so that it actually fits into network data. 2007-08-08 Josh Langley diff --git a/src/equipment.cpp b/src/equipment.cpp index 1dfc7d02..9de8c26e 100644 --- a/src/equipment.cpp +++ b/src/equipment.cpp @@ -25,7 +25,7 @@ #include "equipment.h" -Equipment::Equipment() +void Equipment::clear() { std::fill_n(mEquipment, EQUIPMENT_SIZE, 0); } diff --git a/src/equipment.h b/src/equipment.h index bac5a028..f820dcf0 100644 --- a/src/equipment.h +++ b/src/equipment.h @@ -24,8 +24,6 @@ #ifndef _TMW_EQUIPMENT_H_ #define _TMW_EQUIPMENT_H_ -class Item; - #define EQUIPMENT_SIZE 11 class Equipment @@ -34,7 +32,13 @@ class Equipment /** * Constructor. */ - Equipment(); + Equipment() + { clear(); } + + /** + * Clears equipment. + */ + void clear(); /** * Get equipment at the given slot. diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 23d4c99b..478603b8 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -92,6 +92,7 @@ Being::Type LocalPlayer::getType() const void LocalPlayer::clearInventory() { + mEquipment->clear(); mInventory->clear(); } diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 44b1a7af..87972212 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -424,7 +424,8 @@ static void handleLooks(Being *being, MessageIn &msg) Being::BOTTOMCLOTHES_SPRITE }; int mask = msg.readByte(); - if (mask & (1 << 8)) + + if (mask & (1 << 7)) { // The equipment has to be cleared first. being->setWeaponById(0); -- cgit v1.2.3-70-g09d2 From 1a9320fafb23940d0463e6f384713d0f99fc0c61 Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Wed, 19 Sep 2007 17:28:33 +0000 Subject: Merged 0.0 changes from revision 3362 to 3580 to trunk. --- ChangeLog | 306 ++++++++++++++++++++++++++++++- data/graphics/gui/CMakeLists.txt | 4 + data/graphics/gui/Makefile.am | 4 + data/graphics/gui/close_button.png | Bin 0 -> 650 bytes data/graphics/gui/hits_yellow.png | Bin 356 -> 894 bytes data/graphics/gui/item_shortcut_bgr.png | Bin 0 -> 1026 bytes data/graphics/gui/mouse.png | Bin 1134 -> 4508 bytes data/graphics/gui/unknown-item.png | Bin 0 -> 540 bytes data/graphics/images/login_wallpaper.png | Bin 215527 -> 643307 bytes src/CMakeLists.txt | 22 ++- src/Makefile.am | 38 ++-- src/animationparticle.cpp | 3 +- src/being.cpp | 90 ++------- src/being.h | 42 +---- src/game.cpp | 179 ++++++++++-------- src/gui/button.cpp | 20 +- src/gui/button.h | 10 +- src/gui/buy.cpp | 125 ++++++++----- src/gui/buy.h | 10 +- src/gui/char_select.cpp | 12 +- src/gui/char_select.h | 31 ++-- src/gui/chat.cpp | 10 +- src/gui/debugwindow.cpp | 14 +- src/gui/debugwindow.h | 9 +- src/gui/equipmentwindow.cpp | 1 + src/gui/gui.cpp | 45 +++-- src/gui/gui.h | 43 +++-- src/gui/inventorywindow.cpp | 13 +- src/gui/inventorywindow.h | 11 +- src/gui/itemcontainer.cpp | 4 + src/gui/itemshortcutcontainer.cpp | 224 ++++++++++++++++++++++ src/gui/itemshortcutcontainer.h | 115 ++++++++++++ src/gui/itemshortcutwindow.cpp | 74 ++++++++ src/gui/itemshortcutwindow.h | 69 +++++++ src/gui/menuwindow.cpp | 12 +- src/gui/popupmenu.cpp | 6 - src/gui/selectionlistener.h | 16 +- src/gui/sell.cpp | 127 +++++++------ src/gui/sell.h | 16 +- src/gui/setup.cpp | 10 +- src/gui/setup_keyboard.cpp | 187 +++++++++++++++++++ src/gui/setup_keyboard.h | 84 +++++++++ src/gui/shoplistbox.cpp | 20 +- src/gui/skill.cpp | 6 +- src/gui/skill.h | 1 - src/gui/status.cpp | 6 +- src/gui/status.h | 3 +- src/gui/updatewindow.cpp | 4 +- src/gui/viewport.cpp | 25 +-- src/gui/viewport.h | 13 -- src/gui/window.cpp | 198 +++++++++++++++++--- src/gui/window.h | 99 +++++++++- src/gui/windowlistener.h | 86 +++++++++ src/imageparticle.cpp | 8 +- src/itemshortcut.cpp | 87 +++++++++ src/itemshortcut.h | 130 +++++++++++++ src/keyboardconfig.cpp | 144 +++++++++++++++ src/keyboardconfig.h | 185 +++++++++++++++++++ src/localplayer.cpp | 43 ++++- src/localplayer.h | 22 +++ src/main.cpp | 19 +- src/monster.cpp | 10 +- src/net/beinghandler.cpp | 84 +++++---- src/net/chathandler.cpp | 2 + src/net/inventoryhandler.cpp | 2 + src/net/playerhandler.cpp | 3 +- src/particle.cpp | 96 +++++----- src/particle.h | 112 +++++------ src/particleemitter.cpp | 30 ++- src/player.cpp | 50 ++--- src/player.h | 3 - src/resources/equipmentdb.cpp | 156 ---------------- src/resources/equipmentdb.h | 55 ------ src/resources/equipmentinfo.h | 52 ------ src/resources/itemdb.cpp | 126 ++++++++++--- src/resources/iteminfo.cpp | 86 ++++++++- src/resources/iteminfo.h | 118 +++++++----- src/resources/mapreader.cpp | 2 +- src/resources/monsterdb.cpp | 8 +- src/resources/monsterinfo.cpp | 12 +- src/resources/monsterinfo.h | 16 +- src/resources/spritedef.h | 4 +- src/textparticle.cpp | 11 +- src/textparticle.h | 17 +- src/utils/fastsqrt.h | 2 + src/utils/minmax.h | 1 + src/utils/trim.h | 53 ++++++ src/vector.h | 134 ++++++++++++++ tools/adler32.c | 67 +++++++ 89 files changed, 3257 insertions(+), 1140 deletions(-) create mode 100644 data/graphics/gui/close_button.png create mode 100644 data/graphics/gui/item_shortcut_bgr.png create mode 100644 data/graphics/gui/unknown-item.png create mode 100644 src/gui/itemshortcutcontainer.cpp create mode 100644 src/gui/itemshortcutcontainer.h create mode 100644 src/gui/itemshortcutwindow.cpp create mode 100644 src/gui/itemshortcutwindow.h create mode 100644 src/gui/setup_keyboard.cpp create mode 100644 src/gui/setup_keyboard.h create mode 100644 src/gui/windowlistener.h create mode 100644 src/itemshortcut.cpp create mode 100644 src/itemshortcut.h create mode 100644 src/keyboardconfig.cpp create mode 100644 src/keyboardconfig.h delete mode 100644 src/resources/equipmentdb.cpp delete mode 100644 src/resources/equipmentdb.h delete mode 100644 src/resources/equipmentinfo.h create mode 100644 src/utils/trim.h create mode 100644 src/vector.h create mode 100644 tools/adler32.c (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 082c9b94..d0e43d40 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,19 @@ * src/gui/button.cpp: Fixed improper const qualifier. +2007-09-12 Bjørn Lindeijer + + * data/items.xml, data/equipment.xml: Added temporary weapon IDs below + 256 to use as view-ID in eAthena's item DB. + * src/gui/shoplistbox.cpp, src/gui/buy.h, src/gui/buy.cpp: Allowed + selection of items that cannot be afforded, so that their descriptions + are still accessible. Also made sure the player's money value of + ShopItemList gets updated. + +2007-09-11 Eugenio Favalli + + * src/gui/chat.cpp, tmw.cbp: Fixed admin commands. + 2007-09-10 Eugenio Favalli * configure.ac, data/fonts/dejavusans.ttf, @@ -18,17 +31,103 @@ * po/LINGUAS: Added German to the list of available languages. * po/de.po: Fixed two syntax errors preventing compilation. -2007-08-27 Matthias Hartmann +2007-09-08 Philipp Sehmisch + + * data/graphics/particles/aniblaze.png, + data/graphics/particles/cookingfire.particle.xml, + data/graphics/particles/fireplace.particle.xml, + data/graphics/particles/flame.particle.xml: Improved fire effects by + using animated particles. - * po/de.po: Added german translation. +2007-09-06 Philipp Sehmisch + + * src/animationparticle.cpp, src/imageparticle.cpp: Fixed animated + particles. + +2007-09-01 Bjørn Lindeijer + + * src/Makefile.am: Fixed the entry for windowlistener.h. + +2007-08-30 Bjørn Lindeijer + + * src/localplayer.cpp, src/player.cpp, src/main.cpp, src/being.cpp, + src/CMakeLists.txt, src/Makefile.am, src/resources/iteminfo.h, + src/resources/equipmentdb.h, src/resources/equipmentinfo.h, + src/resources/itemdb.cpp, src/resources/iteminfo.cpp, + src/resources/equipmentdb.cpp, src/resources/equipmentinfo.cpp, + src/resources/spritedef.h, src/being.h, data/items.xml, + data/equipment.xml: Merged equipment database with items database and + got rid of the unused item art attribute. + * src/net/beinghandler.cpp, src/net/charserverhandler.cpp: Removed the + now unnecessary multiplication of weapon IDs with 10000. + * src/resources/iteminfo.cpp, data/graphics/items/unknown.png: Added + fallback item icon and use it for unknown items or when item image + fails to load. + * NEWS: Updated with changes since last update. + * data/items.xml, data/equipment.xml: Reverted equipment database and + included original low-ID items in items.xml for compatibility with + eAthena, which doesn't support View ID to come above 255. + * src/resources/itemdb.cpp: Accept items without a name. + +2007-08-29 Bjørn Lindeijer + + * src/gui/sell.cpp, src/gui/inventorywindow.cpp, src/gui/sell.h: Made + sell dialog resizable and tweaked inventory resize code a bit. + * data/items.xml: Fixed typo in chainmail description. + +2007-08-28 Bjørn Lindeijer + + * src/gui/window.cpp, src/gui/inventorywindow.h, + src/gui/selectionlistener.h, src/gui/buy.h, + src/gui/itemshortcutwindow.cpp, src/gui/inventorywindow.cpp, + src/gui/buy.cpp, src/gui/window.h, src/gui/windowlistener.h, + src/gui/itemshortcutwindow.h, src/CMakeLists.txt, src/Makefile.am: + Made buy dialog resizable and added a WindowListener class for + listening for window resize and move events. + * src/textparticle.h, src/particle.h, src/CMakeLists.txt, + src/particle.cpp, src/imageparticle.cpp, src/vector.h, + src/textparticle.cpp, src/Makefile.am: Added Vector class and used it + in the particle engine. + +2007-08-27 Bjørn Lindeijer + + * src/engine.cpp, src/resources/mapreader.cpp: Made client search for + both compressed and non-compressed map files. 2007-08-27 Eugenio Favalli + * src/game.cpp: Assigned unused emotions to Alt +/-. (applied a patch + by Quiche_on_a_leash). + * data/maps/new_1-1.tmx, data/maps/new_1-1.tmx.gz, + data/maps/new_10-1.tmx, data/maps/new_10-1.tmx.gz, + data/maps/new_11-1.tmx, data/maps/new_11-1.tmx.gz, + data/maps/new_12-1.tmx, data/maps/new_12-1.tmx.gz, + data/maps/new_13-1.tmx, data/maps/new_13-1.tmx.gz, + data/maps/new_14-1.tmx, data/maps/new_14-1.tmx.gz, + data/maps/new_15-1.tmx, data/maps/new_15-1.tmx.gz, + data/maps/new_16-1.tmx, data/maps/new_16-1.tmx.gz, + data/maps/new_17-1.tmx, data/maps/new_17-1.tmx.gz, + data/maps/new_18-1.tmx, data/maps/new_18-1.tmx.gz, + data/maps/new_19-1.tmx, data/maps/new_19-1.tmx.gz, + data/maps/new_2-1.tmx, data/maps/new_2-1.tmx.gz, + data/maps/new_20-1.tmx, data/maps/new_20-1.tmx.gz, + data/maps/new_3-1.tmx, data/maps/new_3-1.tmx.gz, + data/maps/new_4-1.tmx, data/maps/new_4-1.tmx.gz, + data/maps/new_5-1.tmx, data/maps/new_5-1.tmx.gz, + data/maps/new_6-1.tmx, data/maps/new_6-1.tmx.gz, + data/maps/new_7-1.tmx, data/maps/new_7-1.tmx.gz, + data/maps/new_8-1.tmx, data/maps/new_8-1.tmx.gz, + data/maps/new_9-1.tmx, data/maps/new_9-1.tmx.gz: Replaced compressed + maps with layer compressed maps. * data/maps/new_1-1.tmx.gz: Added test npcs. * src/openglgraphics.cpp, tmw.cbp: Fixed compilation with old OpenGL headers. * po/it.po: Updated italian translation. +2007-08-27 Matthias Hartmann + + * po/de.po: Added German translation. + 2007-08-27 Guillaume Melquiond * src/gui/chat.h, src/gui/chat.cpp: Added "/admin" chat command for @@ -36,6 +135,11 @@ * src/engine.cpp, src/resources/mapreader.cpp: Ported patch from 0.0, in order to support missing extensions and uncompressed maps. +2007-08-26 Eugenio Favalli + + * src/gui/updatewindow.cpp, src/main.cpp, tmw.cbp: Removed home dir + from config file to avoid encoding issues. + 2007-08-26 Guillaume Melquiond * src/gui/button.cpp: Fixed incorrect button dimensions, as they mess @@ -58,10 +162,103 @@ for rectangle OpenGL textures when available, in order to reduce video memory usage. +2007-08-24 Bjørn Lindeijer + + * src/gui/gui.h, src/gui/gui.cpp: Removed useless logic method and + reverted mouse cursor to non-static since there can be only one Gui + instance so there is no point in supporting a shared resource. + * src/gui/window.cpp, src/gui/gui.h: Removed unnecessary + Gui::isCustomCursor method. + * src/gui/char_select.h, src/gui/char_select.cpp, src/utils/trim.h: + Added trimming of name for new character creation. + * src/net/chathandler.cpp: Added trimming of chat messages appearing + above players. + * src/gui/window.cpp, src/gui/window.h: Improved resize mouse cursor + indication, removing duplicated code and fixing indicator above resize + grip. + +2007-08-23 Bjørn Lindeijer + + * src/gui/viewport.h, src/gui/viewport.cpp: Removed two useless popup + related methods. + * src/gui/debugwindow.h, src/gui/debugwindow.cpp: Use generic close + button functionality. + * src/particle.h, src/particleemitter.cpp, src/particle.cpp: Renamed + Particle::mVector to Particle::mVelocity for clarity. + * src/localplayer.cpp, src/gui/ministatus.cpp, src/gui/status.cpp, + src/being.cpp, src/net/charserverhandler.cpp, + src/net/playerhandler.cpp, src/localplayer.h, src/being.h: Changed XP + gaining effect to appear on the player instead. + * data/graphics/gui/hits_yellow.png: Restored shadow of yellow font. + +2007-08-22 Bjørn Lindeijer + + * src/gui/itemshortcutcontainer.h: Fixed compiler warning. + * src/CMakeLists.txt, src/Makefile.am: Updated source lists. + * data/graphics/gui/CMakeLists.txt, data/graphics/gui/Makefile.am: + Added close button and item shortcut backgrounds to files that will be + installed. + * src/gui/itemshortcutcontainer.cpp: Make sure mGridWidth and + mGridHeight are initialized properly (fixes arithmetic exception in + ItemShortcutContainer::draw). + * src/keyboardconfig.cpp: Changed default sitting key back to 's'. + * src/net/equipmenthandler.cpp: Removed a line that attempted to set + the player's weapon sprite with each kind of equipment. Seems to work + fine without as well. + * src/gui/chat.cpp, src/utils/trim.h, src/CMakeLists.txt, + src/Makefile.am: Added trimming of chat messages. + +2007-08-22 Philipp Sehmisch + + * data/graphics/sprites/chest-lightplatemail-male.png, + data/graphics/sprites/chest-lightplatemail-female.png, + data/graphics/items/armor-chest-lightplatemail.png, + data/graphics/tiles/woodland_indoor_x2.png: Another color correction + at the light platemail (looks more metalic now) + * data/maps/new_18-1.tmx.gz, data/maps/new_19-1.tmx.gz, + data/images/minimap_new_18-1.png, data/images/minimap_new_19-1.png: + Removed a tree that prevented people from sitting on one of the + benches properly. Added correct minimap to woodland village and + surrounding. + +2007-08-22 Joshua Langley + + * data/graphics/gui/item_shortcut_bgr.png, src/game.cpp, + src/gui/gui.cpp, src/gui/itemcontainer.cpp, + src/gui/itemshortcutcontainer.cpp, src/gui/itemshortcutcontainer.h, + src/gui/itemshortcutwindow.cpp, src/gui/itemshortcutwindow.h, + src/gui/menuwindow.cpp, src/gui/setup_keyboard.cpp, src/gui/window.h, + src/itemshortcut.cpp, src/itemshortcut.h, src/keyboardconfig.cpp, + src/keyboardconfig.h, src/localplayer.cpp, src/localplayer.h, + src/main.cpp, src/net/inventoryhandler.cpp, src/utils/tostring.h, + tmw.cbp: Added item shortcut bar. + +2007-08-20 Joshua Langley + + * data/graphics/gui/mouse.png, src/gui/equipmentwindow.cpp, + src/gui/gui.cpp, src/gui/gui.h, src/gui/inventorywindow.cpp, + src/gui/setup.cpp, src/gui/skill.cpp, src/gui/skill.h, + src/gui/status.cpp, src/gui/window.cpp, src/gui/window.h, + data/graphics/gui/close_button.png: Added close button functionality, + resize cursor cues. + * data/graphics/gui/hits_yellow.png, src/being.cpp, src/being.h, + src/gui/gui.cpp, src/localplayer.cpp, src/localplayer.h, + src/net/charserverhandler.cpp, src/net/playerhandler.cpp, + src/particle.cpp, src/particle.h: Added monster killed xp notification + effect. + 2007-08-19 Bjørn Lindeijer - * src/CMakeLists.txt: Updated CMake file. * data/equipment.xml: Fixed typo in female light plate mail. + * NEWS: Updated with changes since 0.0.23. + * src/CMakeLists.txt: Updated CMake file. + +2007-08-19 Joshua Langley + + * src/keyboardconfig.cpp, src/keyboardconfig.h: Minor cleanup. + * src/gui/buy.cpp, src/gui/sell.cpp: Buy/sell fixed minimum quantity. + * src/gui/setup_keyboard.cpp, src/gui/setup_keyboard.h: Fixed bug - + reverts unassigned key. 2007-08-19 Guillaume Melquiond @@ -73,6 +270,23 @@ src/net/playerhandler.cpp, src/localplayer.h: Adapted to new server handling of character attributes. +2007-08-17 Bjørn Lindeijer + + * tools/adler32.c: Added little program for calculating adler32 + checksums of files. + * src/gui/setup_keyboard.cpp: Fixed compile issue related to array + bound not being an integer constant. + +2007-08-15 Philipp Sehmisch + + * data/graphics/sprites/npcs.png, data/graphics/sprites/npc.xml: + Added farmer NPC for woodland village. + +2007-08-14 Eugenio Favalli + + * src/gui/popupmenu.cpp, src/gui/viewport.cpp, src/gui/viewport.h, + tmw.cbp: Fixed popup menu requiring one more click after being used. + 2007-08-14 Guillaume Melquiond * src/net/messagein.h, src/net/messagein.cpp: Fixed error-prone @@ -111,6 +325,15 @@ * src/gui/npclistdialog.cpp, src/gui/npclistdialog.h, src/net/npchandler.cpp: Removed colon in NPC choice messages. +2007-08-09 Philipp Sehmisch + + * data/graphics/sprites/chest-lightplatemail-male.png, + data/graphics/sprites/chest-lightplatemail-female.png, + data/graphics/items/armor-chest-lightplatemail.png, + data/graphics/tiles/woodland_indoor_x2.png: Gave the platemail + armor a blue tint. Looks less boring and makes recoloring through + hue shifting possible. + 2007-08-09 Guillaume Melquiond * po/POTFILES.in: Updated list of translatable source files. @@ -133,9 +356,29 @@ data/graphics/images/EquipBackground.png: Re-designed equipment window, un-equip created. +2007-08-08 Philipp Sehmisch + + * data/graphics/particles/cookingfire.particle.xml, + data/graphics/particles/fireplace.particle.xml, + data/maps/new_20-1.tmx.gz: Added particle effects and music to the + woodland village indoor map. + * data/maps/new_19-1.tmx.gz: Added overlay effect and music to + woodland village outdoor map. + * data/maps/new_18-1.tmx.gz: Fixed some collision map errors and added + music and overlay effect to the surrounding of the woodland village. + +2007-08-07 Philipp Sehmisch + + * data/graphics/sprites/npcs.png: Added two new NPCs and gave some + of the older NPCs a makeover to look more like the style of the new + playerset. + * data/maps/new_20-1.tmx.gz: Corrected a few mapping errors in the + new woodland village. + * data/items.xml: Tweaked description and values of the scythe. + 2007-08-07 Guillaume Melquiond - * po/Makevars, src/main.cpp: Replaced PACKAGE by tmw to reduce + * po/Makevars, src/main.cpp: Replaced PACKAGE by tmw to reduce preprocessing hell. Set gettext charset to utf8. * src/gui/menuwindow.cpp, src/gui/connection.cpp, src/gui/register.cpp, src/gui/equipmentwindow.cpp, @@ -172,6 +415,14 @@ Makefile.am, autogen.sh: Used autopoint for generating gettext environment, and removed conflicting files. +2007-08-05 Philipp Sehmisch + + * data/graphics/tiles/woodland_indoor.png, + data/graphics/tiles/woodland_indoor_x2.png, + data/graphics/tiles/woodland_indoor_x3.png: Added woodland + village indoor tilesets. + * data/maps/new_20-1.tmx.gz: Added woodland village indoor map. + 2007-08-05 Guillaume Melquiond * configure.ac, Makefile.am, po, src/Makefile.am, src/main.cpp, @@ -222,12 +473,22 @@ src/gui/itemcontainer.cpp, src/gui/checkbox.cpp, src/gui/minimap.cpp, src/gui/scrollarea.cpp, src/gui/popupmenu.cpp: Removed useless yet costly dynamic casts. - -2007-07-25 Guillaume Melquiond - * src/net/beinghandler.cpp, src/net/protocol.h: Added being speed to protocol. +2007-07-25 Joshua Langley + + * src/gui/setup.cpp, src/gui/setup_keyboard.cpp, + src/gui/setup_keyboard.h, src/keyboardconfig.cpp, + src/keyboardconfig.h, src/main.cpp: Minor changes to keyboard config, + keyboard setup gui re-designed. + +2007-07-24 Bjørn Lindeijer + + * src/CMakeLists.txt, src/Makefile.am: Added setup_keyboard.* and + keyboardconfig.* to the list of source files. + * src/keyboardconfig.h: Fixed initialization order. + 2007-07-23 Eugenio Favalli * data/maps/new_1-1.tar.gz, data/maps/new_3-1.tar.gz: Fixed warp @@ -247,8 +508,21 @@ * data/maps/new_1-1.tar.gz: Fixed insecure filenames. +2007-07-17 Joshua Langley + + * src/game.cpp: Only one key per function. + * src/main.cpp: Keyboard configuration included. + * src/gui/button.cpp, src/gui/button.h: Default constructor and + init function added. + * src/gui/setup.cpp: Keyboard setup tab added. + * src/gui/setup_keyboard.cpp, src/gui/setup_keyboard.h: Add to project + file, it is the keyboard setup tab. + * src/keyboardconfig.cpp, src/keyboardconfig.h: Add to project file, + the main keyboard config operations. + 2007-07-16 Eugenio Favalli + * data/items.xml: Fixed description of silk headband. * data/maps/new_1-1.tar.gz, data/maps/new_3-1.tar.gz: Added warp and spawn areas. @@ -262,6 +536,24 @@ * src/net/beinghandler.cpp, src/net/beinghandler.h, src/net/protocol.h: Added support for visible equipment. +2007-07-11 Philipp Sehmisch + + * src/resources/monsterdb.cpp, src/resources/monsterinfo.cpp, + src/resources/monsterinfo.h, src/monster.cpp: Renamed SoundEvent + to MonsterSoundEvent. + * src/resources/equipmentdb.cpp, src/resources/equipmentinfo.cpp, + src/resources/equipmentinfo.h: EquipmentDB now holds the type of + attack animation and the sounds of weapons. + * src/being.cpp. src/being.h, src/localplayer.cpp, + src/net/beinghandler.cpp, src/net/charserverhandler.cpp, + src/net/equipmenthandler.cpp, src/player.cpp, src/player.h: The + type of weapon player characters are using is now set using + setVisibleEquipment() instead of setWeapon() or setWeaponById(). + * src/CMakeLists.txt, src/Makefile.AM, tmw.cbp, The Mana World.dev: + Updated project files and buildscripts. + * data/graphics/images/login-wallpaper.png: Replaced login wallpaper + with a new one by Irukard. + 2007-07-11 Bjørn Lindeijer * src/gui/window.cpp: Fixed resizing windows by their resize grip. diff --git a/data/graphics/gui/CMakeLists.txt b/data/graphics/gui/CMakeLists.txt index 5a02d7f1..649e0917 100644 --- a/data/graphics/gui/CMakeLists.txt +++ b/data/graphics/gui/CMakeLists.txt @@ -7,6 +7,7 @@ SET (FILES button.png buttonpress.png checkbox.png + close_button.png deepbox.png fixedfont.png hits_blue.png @@ -18,6 +19,8 @@ SET (FILES hscroll_right_default.png hscroll_right_highlight.png hscroll_right_pressed.png + item_shortcut_bgr.png + mouse.png menuitemD.png menuitemF.png menuitemN.png @@ -37,6 +40,7 @@ SET (FILES target-cursor-red-m.png target-cursor-red-s.png thickborder.png + unknown-item.png vscroll_blue.png vscroll_down_default.png vscroll_down_highlight.png diff --git a/data/graphics/gui/Makefile.am b/data/graphics/gui/Makefile.am index 92e4f3bb..7287d717 100644 --- a/data/graphics/gui/Makefile.am +++ b/data/graphics/gui/Makefile.am @@ -10,6 +10,7 @@ gui_DATA = \ buttonhi.png \ buttonpress.png \ checkbox.png \ + close_button.png \ deepbox.png \ equip_bg.png \ fixedfont.png \ @@ -22,6 +23,8 @@ gui_DATA = \ hscroll_right_default.png \ hscroll_right_highlight.png \ hscroll_right_pressed.png \ + item_shortcut_bgr.png \ + mouse.png \ menuitemD.png \ menuitemF.png \ menuitemN.png \ @@ -41,6 +44,7 @@ gui_DATA = \ target-cursor-red-m.png \ target-cursor-red-s.png \ thickborder.png \ + unknown-item.png \ vscroll_blue.png \ vscroll_down_default.png \ vscroll_down_highlight.png \ diff --git a/data/graphics/gui/close_button.png b/data/graphics/gui/close_button.png new file mode 100644 index 00000000..f87cc2a9 Binary files /dev/null and b/data/graphics/gui/close_button.png differ diff --git a/data/graphics/gui/hits_yellow.png b/data/graphics/gui/hits_yellow.png index f917bc67..d77b7c05 100644 Binary files a/data/graphics/gui/hits_yellow.png and b/data/graphics/gui/hits_yellow.png differ diff --git a/data/graphics/gui/item_shortcut_bgr.png b/data/graphics/gui/item_shortcut_bgr.png new file mode 100644 index 00000000..e878fc7a Binary files /dev/null and b/data/graphics/gui/item_shortcut_bgr.png differ diff --git a/data/graphics/gui/mouse.png b/data/graphics/gui/mouse.png index 2eeb0e51..84dc2ad1 100644 Binary files a/data/graphics/gui/mouse.png and b/data/graphics/gui/mouse.png differ diff --git a/data/graphics/gui/unknown-item.png b/data/graphics/gui/unknown-item.png new file mode 100644 index 00000000..9201d688 Binary files /dev/null and b/data/graphics/gui/unknown-item.png differ diff --git a/data/graphics/images/login_wallpaper.png b/data/graphics/images/login_wallpaper.png index 54692dfd..7af4f913 100644 Binary files a/data/graphics/images/login_wallpaper.png and b/data/graphics/images/login_wallpaper.png differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fa19cfb5..96338338 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -97,6 +97,12 @@ SET(SRCS gui/item_amount.h gui/itemcontainer.cpp gui/itemcontainer.h + gui/itemshortcutcontainer.cpp + gui/itemshortcutcontainer.h + gui/itemshortcutwindow.cpp + gui/itemshortcutwindow.h + gui/item_amount.cpp + gui/item_amount.h gui/linkhandler.h gui/listbox.cpp gui/listbox.h @@ -143,6 +149,8 @@ SET(SRCS gui/setup.h gui/setup_joystick.cpp gui/setup_joystick.h + gui/setup_keyboard.cpp + gui/setup_keyboard.h gui/setuptab.h gui/setup_video.cpp gui/setup_video.h @@ -170,12 +178,13 @@ SET(SRCS gui/updatewindow.h gui/vbox.cpp gui/vbox.h - gui/windowcontainer.cpp - gui/windowcontainer.h gui/viewport.cpp gui/viewport.h gui/window.cpp gui/window.h + gui/windowcontainer.cpp + gui/windowcontainer.h + gui/windowlistener.h gui/widgets/dropdown.cpp gui/widgets/dropdown.h net/beinghandler.cpp @@ -239,9 +248,6 @@ SET(SRCS resources/buddylist.h resources/animation.cpp resources/animation.h - resources/equipmentdb.cpp - resources/equipmentdb.h - resources/equipmentinfo.h resources/image.cpp resources/image.h resources/imagewriter.cpp @@ -281,6 +287,7 @@ SET(SRCS utils/strprintf.cpp utils/strprintf.h utils/tostring.h + utils/trim.h utils/xml.cpp utils/xml.h animatedsprite.cpp @@ -317,8 +324,12 @@ SET(SRCS inventory.h item.cpp item.h + itemshortcut.cpp + itemshortcut.h joystick.cpp joystick.h + keyboardconfig.cpp + keyboardconfig.h localplayer.cpp localplayer.h lockedarray.h @@ -351,6 +362,7 @@ SET(SRCS textparticle.cpp textparticle.h tileset.h + vector.h ) ADD_EXECUTABLE(tmw ${SRCS}) diff --git a/src/Makefile.am b/src/Makefile.am index 7006f66e..2f29e299 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,6 +5,8 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ gui/widgets/dropdown.h \ gui/widgets/resizegrip.cpp \ gui/widgets/resizegrip.h \ + gui/box.h \ + gui/box.cpp \ gui/browserbox.cpp \ gui/browserbox.h \ gui/buddywindow.cpp \ @@ -39,12 +41,20 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ gui/gccontainer.h \ gui/gui.cpp \ gui/gui.h \ + gui/hbox.h \ + gui/hbox.cpp \ gui/help.cpp \ gui/help.h \ + gui/inttextbox.h \ + gui/inttextbox.cpp \ gui/inventorywindow.cpp \ gui/inventorywindow.h \ gui/itemcontainer.cpp \ gui/itemcontainer.h \ + gui/itemshortcutcontainer.cpp \ + gui/itemshortcutcontainer.h \ + gui/itemshortcutwindow.cpp \ + gui/itemshortcutwindow.h \ gui/item_amount.cpp \ gui/item_amount.h \ gui/linkhandler.h \ @@ -95,6 +105,8 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ gui/setup.h \ gui/setup_joystick.cpp \ gui/setup_joystick.h \ + gui/setup_keyboard.cpp \ + gui/setup_keyboard.h \ gui/setuptab.h \ gui/setup_video.cpp \ gui/setup_video.h \ @@ -118,22 +130,17 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ gui/trade.h \ gui/unregisterdialog.cpp \ gui/unregisterdialog.h \ + gui/updatewindow.h \ + gui/updatewindow.cpp \ + gui/vbox.h \ + gui/vbox.cpp \ gui/viewport.cpp \ gui/viewport.h \ gui/window.cpp \ gui/window.h \ gui/windowcontainer.cpp \ gui/windowcontainer.h \ - gui/inttextbox.h \ - gui/inttextbox.cpp \ - gui/box.h \ - gui/box.cpp \ - gui/vbox.h \ - gui/vbox.cpp \ - gui/hbox.h \ - gui/hbox.cpp \ - gui/updatewindow.h \ - gui/updatewindow.cpp \ + gui/windowlistener.h \ net/beinghandler.h \ net/beinghandler.cpp \ net/buysellhandler.h \ @@ -193,9 +200,6 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ resources/ambientoverlay.h \ resources/animation.cpp \ resources/animation.h \ - resources/equipmentdb.cpp \ - resources/equipmentdb.h \ - resources/equipmentinfo.h \ resources/image.cpp \ resources/image.h \ resources/imageloader.cpp \ @@ -235,6 +239,7 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ utils/strprintf.h \ utils/strprintf.cpp \ utils/tostring.h \ + utils/trim.h \ utils/xml.cpp \ utils/xml.h \ animatedsprite.cpp \ @@ -271,8 +276,12 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ inventory.h \ item.cpp \ item.h \ + itemshortcut.cpp \ + itemshortcut.h \ joystick.cpp \ joystick.h \ + keyboardconfig.cpp \ + keyboardconfig.h \ localplayer.cpp \ localplayer.h \ lockedarray.h \ @@ -304,7 +313,8 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ sprite.h \ textparticle.cpp \ textparticle.h \ - tileset.h + tileset.h \ + vector.h # set the include path found by configure INCLUDES = \ diff --git a/src/animationparticle.cpp b/src/animationparticle.cpp index 30c33da7..c79a5bc4 100644 --- a/src/animationparticle.cpp +++ b/src/animationparticle.cpp @@ -26,7 +26,7 @@ #include "simpleanimation.h" AnimationParticle::AnimationParticle(Map *map, Animation *animation): - ImageParticle(map, 0), + ImageParticle(map, NULL), mAnimation(new SimpleAnimation(animation)) { } @@ -40,6 +40,7 @@ AnimationParticle::AnimationParticle(Map *map, xmlNodePtr animationNode): AnimationParticle::~AnimationParticle() { delete mAnimation; + mImage = NULL; } bool AnimationParticle::update() diff --git a/src/being.cpp b/src/being.cpp index bdb27384..81bed667 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -36,12 +36,10 @@ #include "resources/resourcemanager.h" #include "resources/imageset.h" +#include "resources/iteminfo.h" #include "gui/gui.h" -#include "resources/resourcemanager.h" -#include "resources/imageset.h" - #include "utils/dtor.h" #include "utils/tostring.h" @@ -58,11 +56,11 @@ Being::Being(Uint16 id, Uint16 job, Map *map): mEquipment(new Equipment()), mId(id), mSex(2), - mWeapon(0), mWalkSpeed(150), mSpeedModifier(1024), mSpriteDirection(DIRECTION_DOWN), mDirection(DOWN), mMap(NULL), + mEquippedWeapon(NULL), mHairStyle(0), mHairColor(0), mSpeechTime(0), mPx(0), mPy(0), @@ -302,7 +300,7 @@ Being::setSpeech(const std::string &text, Uint32 time) void Being::takeDamage(int amount) { - gcn::Font* font; + gcn::Font *font; std::string damage = amount ? toString(amount) : "miss"; // Selecting the right color @@ -312,8 +310,9 @@ Being::takeDamage(int amount) } else { - // hit particle effect - controlParticle(particleEngine->addEffect("graphics/particles/hit.particle.xml", 0, 0)); + // Hit particle effect + controlParticle(particleEngine->addEffect( + "graphics/particles/hit.particle.xml", 0, 0)); if (getType() == MONSTER) { @@ -325,7 +324,7 @@ Being::takeDamage(int amount) } } - // show damage number + // Show damage number particleEngine->addTextSplashEffect(damage, 255, 255, 255, font, mPx + 16, mPy + 16); } @@ -340,7 +339,7 @@ void Being::setMap(Map *map) { // Remove sprite from potential previous map - if (mMap != NULL) + if (mMap) { mMap->removeSprite(mSpriteIterator); } @@ -348,12 +347,12 @@ Being::setMap(Map *map) mMap = map; // Add sprite to potential new map - if (mMap != NULL) + if (mMap) { mSpriteIterator = mMap->addSprite(this); } - //clear particle effect list because child particles became invalid + // Clear particle effect list because child particles became invalid mChildParticleEffects.clear(); } @@ -362,7 +361,8 @@ Being::controlParticle(Particle *particle) { if (particle) { - particle->disableAutoDelete(); //the effect may not die without the beings permission or we segvault + // The effect may not die without the beings permission or we segfault + particle->disableAutoDelete(); mChildParticleEffects.push_back(particle); } } @@ -380,20 +380,12 @@ Being::setAction(Action action) currentAction = ACTION_SIT; break; case ATTACK: - switch (getWeapon()) + if (mEquippedWeapon) { - case 3: - currentAction = ACTION_ATTACK; - break; - case 2: - currentAction = ACTION_ATTACK_BOW; - break; - case 1: - currentAction = ACTION_ATTACK_STAB; - break; - case 0: - currentAction = ACTION_ATTACK; - break; + currentAction = mEquippedWeapon->getAttackType(); + } + else { + currentAction = ACTION_ATTACK; } for (int i = 0; i < VECTOREND_SPRITE; i++) { @@ -533,11 +525,9 @@ Being::logic() } } - //Update particle effects - for ( std::list::iterator i = mChildParticleEffects.begin(); - i != mChildParticleEffects.end(); - - ) + // Update particle effects + for (std::list::iterator i = mChildParticleEffects.begin(); + i != mChildParticleEffects.end();) { (*i)->setPosition((float)mPx + 16.0f, (float)mPy + 32.0f); if (!(*i)->isAlive()) @@ -599,46 +589,6 @@ Being::getType() const return UNKNOWN; } -void -Being::setWeaponById(Uint16 weapon) -{ - //TODO: Use an external file to map weapon IDs to weapon types - switch (weapon) - { - case 529: // iron arrows - case 1199: // arrows - break; - - case 623: //scythe - setWeapon(3); - break; - - case 1200: // bow - case 530: // short bow - case 545: // forest bow - setWeapon(2); - break; - - case 521: // sharp knife - /* UNCOMMENT TO TEST SHARP KNIFE AS SCYTHE - * setWeapon(3) - * break; - */ - case 522: // dagger - case 536: // short sword - case 1201: // knife - setWeapon(1); - break; - - case 0: // unequip - setWeapon(0); - break; - - default: - logger->log("Not a weapon: %d", weapon); - } -} - int Being::getOffset(int step) const { // Check whether we're walking in the requested direction diff --git a/src/being.h b/src/being.h index afb3cb8b..fadf9656 100644 --- a/src/being.h +++ b/src/being.h @@ -38,6 +38,7 @@ class AnimatedSprite; class Equipment; +class ItemInfo; class Item; class Map; class Graphics; @@ -161,8 +162,7 @@ class Being : public Sprite void setSpeech(const std::string &text, Uint32 time); /** - * Puts a damage bubble above this being for the specified amount of - * time. + * Puts a damage bubble above this being. * * @param amount The amount of damage. */ @@ -266,27 +266,6 @@ class Being : public Sprite */ virtual Type getType() const; - /** - * Gets the weapon picture id. - */ - Uint16 getWeapon() const { return mWeapon; } - - /** - * Sets the weapon picture id. - * - * @param weapon the picture id - */ - virtual void - setWeapon(Uint16 weapon) { mWeapon = weapon; } - - /** - * Sets the weapon picture id with the weapon id. - * - * @param weapon the weapon id - */ - void - setWeaponById(Uint16 weapon); - /** * Gets the walk speed. */ @@ -380,30 +359,26 @@ class Being : public Sprite getHeight() const; /** - * Returns the required size of a target cursor for this being + * Returns the required size of a target cursor for this being. */ - virtual Being::TargetCursorSize - getTargetCursorSize() const + virtual Being::TargetCursorSize getTargetCursorSize() const { return TC_MEDIUM; } std::auto_ptr mEquipment; /** - * Take control of a particle + * Take control of a particle. */ - void - controlParticle(Particle *particle); + void controlParticle(Particle *particle); protected: /** * Sets the new path for this being. */ - void - setPath(const Path &path, int mod = 1024); + void setPath(const Path &path, int mod = 1024); Uint16 mId; /**< Unique being id */ Uint8 mSex; /**< Character's gender */ - Uint16 mWeapon; /**< Weapon picture id */ Uint16 mWalkSpeed; /**< Walking speed */ Uint16 mSpeedModifier; /**< Modifier to keep course on sync (1024 = normal speed) */ Uint8 mSpriteDirection; /**< Facing direction */ @@ -411,6 +386,9 @@ class Being : public Sprite Map *mMap; /**< Map on which this being resides */ SpriteIterator mSpriteIterator; + /** Engine-related infos about weapon. */ + const ItemInfo* mEquippedWeapon; + Path mPath; std::string mSpeech; Uint16 mHairStyle, mHairColor; diff --git a/src/game.cpp b/src/game.cpp index 495f9a8d..a40bfa28 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -37,7 +37,9 @@ #include "engine.h" #include "flooritemmanager.h" #include "graphics.h" +#include "itemshortcut.h" #include "joystick.h" +#include "keyboardconfig.h" #include "localplayer.h" #include "log.h" #include "npc.h" @@ -53,6 +55,7 @@ #include "gui/gui.h" #include "gui/help.h" #include "gui/inventorywindow.h" +#include "gui/itemshortcutwindow.h" #include "gui/menuwindow.h" #include "gui/minimap.h" #include "gui/ministatus.h" @@ -116,6 +119,7 @@ TradeWindow *tradeWindow; //BuddyWindow *buddyWindow; HelpWindow *helpWindow; DebugWindow *debugWindow; +ItemShortcutWindow *itemShortcutWindow; BeingManager *beingManager = NULL; FloorItemManager *floorItemManager = NULL; @@ -181,6 +185,7 @@ void createGuiWindows() //buddyWindow = new BuddyWindow(); helpWindow = new HelpWindow(); debugWindow = new DebugWindow(); + itemShortcutWindow = new ItemShortcutWindow(); // Initialize window positions //chargeDialog->setPosition( @@ -193,6 +198,7 @@ void createGuiWindows() chatWindow->setVisible(true); miniStatusWindow->setVisible(true); menuWindow->setVisible(true); + itemShortcutWindow->setVisible(true); } /** @@ -220,6 +226,7 @@ void destroyGuiWindows() //delete buddyWindow; delete helpWindow; delete debugWindow; + delete itemShortcutWindow; } Game::Game(): @@ -420,6 +427,14 @@ void Game::handleInput() { gcn::Window *requestedWindow = NULL; + if (setupWindow->isVisible() && + keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE) + { + keyboard.setNewKey((int) event.key.keysym.sym); + keyboard.callbackNewKey(); + keyboard.setNewKeyIndex(keyboard.KEY_NO_VALUE); + return; + } switch (event.key.keysym.sym) { case SDLK_F1: @@ -473,65 +488,7 @@ void Game::handleInput() used = true; } break; - - // Hide certain windows - case SDLK_h: - if (!chatWindow->isFocused()) - { - statusWindow->setVisible(false); - inventoryWindow->setVisible(false); - skillDialog->setVisible(false); - setupWindow->setVisible(false); - equipmentWindow->setVisible(false); - helpWindow->setVisible(false); - debugWindow->setVisible(false); - } - break; - - // Picking up items on the floor - case SDLK_g: - case SDLK_z: - if (!chatWindow->isFocused()) - { - Uint16 x = player_node->mX / 32, y = player_node->mY / 32; - FloorItem *item = floorItemManager->findByCoordinates(x, y); - - // If none below the player, try the tile in front of - // the player - if (!item) - { - // Temporary until tile-based picking is removed. - switch (player_node->getSpriteDirection()) - { - case DIRECTION_UP : --y; break; - case DIRECTION_DOWN : ++y; break; - case DIRECTION_LEFT : --x; break; - case DIRECTION_RIGHT: ++x; break; - default: break; - } - - item = floorItemManager->findByCoordinates(x, y); - } - - if (item) - player_node->pickUp(item); - - used = true; - } - break; - - // attacking - // TODO: Reimplement attacking with joystick buttons - // (old code allowed permanent attacking and not 1 attack - // with each button push) - // I would like to do this but i don't own a joystick. - case SDLK_LCTRL: - case SDLK_RCTRL: - player_node->attack(); - used = true; - break; - - // Quitting confirmation dialog + // Quitting confirmation dialog case SDLK_ESCAPE: if (!quitDialog) { @@ -547,6 +504,74 @@ void Game::handleInput() break; } + if (keyboard.isEnabled() && !chatWindow->isFocused()) + { + const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); + // Checks if any item shortcut is pressed. + for (int i = KeyboardConfig::KEY_SHORTCUT_0; + i <= KeyboardConfig::KEY_SHORTCUT_9; + i++) + { + if (tKey == i) { + itemShortcut->useItem( + i - KeyboardConfig::KEY_SHORTCUT_0); + break; + } + } + switch (tKey) { + case KeyboardConfig::KEY_PICKUP: + { + Uint16 x = player_node->mX / 32; + Uint16 y = player_node->mY / 32; + FloorItem *item = + floorItemManager->findByCoordinates(x, y); + + // If none below the player, try the tile in front + // of the player + if (!item) + { + // Temporary until tile-based picking is + // removed. + switch (player_node->getSpriteDirection()) + { + case DIRECTION_UP : --y; break; + case DIRECTION_DOWN : ++y; break; + case DIRECTION_LEFT : --x; break; + case DIRECTION_RIGHT: ++x; break; + default: break; + } + + item = + floorItemManager->findByCoordinates(x, y); + } + + if (item) + player_node->pickUp(item); + + used = true; + } + break; + case KeyboardConfig::KEY_SIT: + // Player sit action + player_node->toggleSit(); + used = true; + break; + case KeyboardConfig::KEY_HIDE_WINDOWS: + // Hide certain windows + if (!chatWindow->isFocused()) + { + statusWindow->setVisible(false); + inventoryWindow->setVisible(false); + skillDialog->setVisible(false); + setupWindow->setVisible(false); + equipmentWindow->setVisible(false); + helpWindow->setVisible(false); + debugWindow->setVisible(false); + } + break; + } + } + if (requestedWindow) { requestedWindow->setVisible(!requestedWindow->isVisible()); @@ -563,19 +588,14 @@ void Game::handleInput() { switch (event.key.keysym.sym) { - case SDLK_s: - // Player sit action - player_node->toggleSit(); - used = true; - break; - case SDLK_p: // Screenshot (picture, hence the p) { SDL_Surface *screenshot = graphics->getScreenshot(); if (!saveScreenshot(screenshot)) { - logger->log("Error: could not save Screenshot."); + logger->log( + "Error: could not save Screenshot."); } SDL_FreeSurface(screenshot); } @@ -606,6 +626,8 @@ void Game::handleInput() case SDLK_8: emotion = 8; break; case SDLK_9: emotion = 9; break; case SDLK_0: emotion = 10; break; + case SDLK_MINUS: emotion = 11; break; + case SDLK_EQUALS: emotion = 12; break; default: emotion = 0; break; } @@ -638,41 +660,41 @@ void Game::handleInput() } } // End while - + // If the user is configuring the keys then don't respond. + if (!keyboard.isEnabled()) + { + return; + } // Moving player around if (player_node->mAction != Being::DEAD && current_npc == 0 && !chatWindow->isFocused()) { // Get the state of the keyboard keys - Uint8* keys; - keys = SDL_GetKeyState(NULL); + keyboard.refreshActiveKeys(); Uint16 x = player_node->mX / 32, y = player_node->mY / 32; unsigned char direction = 0; // Translate pressed keys to movement and direction - if (keys[SDLK_UP] || keys[SDLK_KP8] || - keys[SDLK_KP7] || keys[SDLK_KP9] || + if ( keyboard.isKeyActive(keyboard.KEY_MOVE_UP) || joystick && joystick->isUp()) { direction |= Being::UP; } - else if (keys[SDLK_DOWN] || keys[SDLK_KP2] || - keys[SDLK_KP1] || keys[SDLK_KP3] || + else if ( keyboard.isKeyActive(keyboard.KEY_MOVE_DOWN) || joystick && joystick->isDown()) { direction |= Being::DOWN; } - if (keys[SDLK_LEFT] || keys[SDLK_KP4] || - keys[SDLK_KP1] || keys[SDLK_KP7] || + + if ( keyboard.isKeyActive(keyboard.KEY_MOVE_LEFT) || joystick && joystick->isLeft()) { direction |= Being::LEFT; } - else if (keys[SDLK_RIGHT] || keys[SDLK_KP6] || - keys[SDLK_KP3] || keys[SDLK_KP9] || + else if ( keyboard.isKeyActive(keyboard.KEY_MOVE_RIGHT) || joystick && joystick->isRight()) { direction |= Being::RIGHT; @@ -681,7 +703,8 @@ void Game::handleInput() player_node->setWalkingDir(direction); // Target the nearest monster if 'a' pressed - if (keys[SDLK_a]) + if ( keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) ) + //if (keys[SDLK_a]) { Being *target = beingManager->findNearestLivingBeing(x, y, 20, Being::MONSTER); diff --git a/src/gui/button.cpp b/src/gui/button.cpp index 4e236c33..0379ebc0 100644 --- a/src/gui/button.cpp +++ b/src/gui/button.cpp @@ -60,10 +60,25 @@ static ButtonData const data[BUTTON_COUNT] = { ImageRect Button::button[BUTTON_COUNT]; +Button::Button(): + mIsLogged(false) +{ + init(); +} + Button::Button(const std::string& caption, const std::string &actionEventId, gcn::ActionListener *listener): gcn::Button(caption), mIsLogged(false) +{ + init(); + setActionEventId(actionEventId); + if (listener) { + addActionListener(listener); + } +} + +void Button::init() { setBorderSize(0); @@ -91,12 +106,7 @@ Button::Button(const std::string& caption, const std::string &actionEventId, btn[mode]->decRef(); } } - mInstances++; - setActionEventId(actionEventId); - if (listener) { - addActionListener(listener); - } } Button::~Button() diff --git a/src/gui/button.h b/src/gui/button.h index eb73e311..d12173b2 100644 --- a/src/gui/button.h +++ b/src/gui/button.h @@ -38,7 +38,13 @@ class ImageRect; class Button : public gcn::Button { public: /** - * Constructor, sets the caption of the button to the given string. + * Default constructor. + */ + Button(); + + /** + * Constructor, sets the caption of the button to the given string and + * adds the given action listener. */ Button(const std::string& caption, const std::string &actionEventId, gcn::ActionListener *listener); @@ -60,6 +66,8 @@ class Button : public gcn::Button { { mIsLogged = enable; } private: + void init(); + static ImageRect button[4]; /**< Button state graphics */ static int mInstances; /**< Number of button instances */ bool mIsLogged; /**< Makes the button appear pressed all the time */ diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp index 6cfe5e18..bbf2102e 100644 --- a/src/gui/buy.cpp +++ b/src/gui/buy.cpp @@ -28,6 +28,7 @@ #include "button.h" #include "scrollarea.h" #include "shop.h" +#include "shoplistbox.h" #include "slider.h" #include "../npc.h" @@ -35,11 +36,15 @@ #include "../resources/itemdb.h" #include "../utils/tostring.h" - BuyDialog::BuyDialog(): Window("Buy"), mMoney(0), mAmountItems(0), mMaxItems(0) { + setResizable(true); + setMinWidth(260); + setMinHeight(230); + setDefaultSize(0, 0, 260, 230); + mShopItems = new ShopItems; mShopItemList = new ShopListBox(mShopItems, mShopItems); @@ -54,32 +59,15 @@ BuyDialog::BuyDialog(): mItemDescLabel = new gcn::Label("Description:"); mItemEffectLabel = new gcn::Label("Effect:"); - setContentSize(260, 210); - mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mScrollArea->setDimension(gcn::Rectangle(5, 5, 250, 110)); - mShopItemList->setDimension(gcn::Rectangle(5, 5, 238, 110)); - - mSlider->setDimension(gcn::Rectangle(5, 120, 200, 10)); - mSlider->setEnabled(false); - - mQuantityLabel->setPosition(215, 120); - mMoneyLabel->setPosition(5, 130); - - mIncreaseButton->setPosition(40, 186); mIncreaseButton->setSize(20, 20); - mIncreaseButton->setEnabled(false); - - mDecreaseButton->setPosition(10, 186); mDecreaseButton->setSize(20, 20); - mDecreaseButton->setEnabled(false); + mQuantityLabel->setWidth(60); - mBuyButton->setPosition(180, 186); + mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mIncreaseButton->setEnabled(false); + mDecreaseButton->setEnabled(false); mBuyButton->setEnabled(false); - - mQuitButton->setPosition(212, 186); - - mItemEffectLabel->setDimension(gcn::Rectangle(5, 150, 240, 14)); - mItemDescLabel->setDimension(gcn::Rectangle(5, 169, 240, 14)); + mSlider->setEnabled(false); mShopItemList->setActionEventId("item"); mSlider->setActionEventId("slider"); @@ -98,6 +86,8 @@ BuyDialog::BuyDialog(): add(mItemDescLabel); add(mItemEffectLabel); + addWindowListener(this); + loadWindowState("Buy"); setLocationRelativeTo(getParent()); } @@ -118,13 +108,12 @@ void BuyDialog::reset() { mShopItems->clear(); mShopItemList->adjustSize(); - mMoney = 0; - mSlider->setValue(0.0); - // Reset Previous Selected Items to prevent failing asserts + // Reset previous selected items to prevent failing asserts mShopItemList->setSelected(-1); + mSlider->setValue(0); - updateButtonsAndLabels(); + setMoney(0); } void BuyDialog::addItem(int id, int amount, int price) @@ -141,6 +130,7 @@ void BuyDialog::action(const gcn::ActionEvent &event) { setVisible(false); current_npc = 0; + return; } // The following actions require a valid selection @@ -152,21 +142,19 @@ void BuyDialog::action(const gcn::ActionEvent &event) if (event.getId() == "slider") { - mAmountItems = (int)(mSlider->getValue() * mMaxItems); + mAmountItems = (int) mSlider->getValue(); updateButtonsAndLabels(); } else if (event.getId() == "+" && mAmountItems < mMaxItems) { mAmountItems++; - - mSlider->setValue((double) mAmountItems / (double) mMaxItems); + mSlider->setValue(mAmountItems); updateButtonsAndLabels(); } - else if (event.getId() == "-" && mAmountItems > 0) + else if (event.getId() == "-" && mAmountItems > 1) { mAmountItems--; - - mSlider->setValue((double) mAmountItems / (double) mMaxItems); + mSlider->setValue(mAmountItems); updateButtonsAndLabels(); } // TODO: Actually we'd have a bug elsewhere if this check for the number @@ -178,25 +166,69 @@ void BuyDialog::action(const gcn::ActionEvent &event) Net::GameServer::Player::tradeWithNPC (mShopItems->at(selectedItem).id, mAmountItems); - // Update money and adjust the max number of items that can be bought - mMoney -= mAmountItems * mShopItems->at(selectedItem).price; - mMaxItems -= mAmountItems; - // Reset selection - mAmountItems = 0; - mSlider->setValue(0.0); + mAmountItems = 1; + mSlider->setValue(1); + mSlider->gcn::Slider::setScale(1, mMaxItems); - updateButtonsAndLabels(); + // Update money and adjust the max number of items that can be bought + mMaxItems -= mAmountItems; + setMoney(mMoney - mAmountItems * mShopItems->at(selectedItem).price); } } void BuyDialog::selectionChanged(const SelectionEvent &event) { + // Reset amount of items and update labels - mAmountItems = 0; - mSlider->setValue(0.0); + mAmountItems = 1; + mSlider->setValue(1); updateButtonsAndLabels(); + mSlider->gcn::Slider::setScale(1, mMaxItems); +} + +void BuyDialog::windowResized(const WindowEvent &event) +{ + gcn::Rectangle area = getChildrenArea(); + int width = area.width; + int height = area.height; + + mDecreaseButton->setPosition(8, height - 8 - mDecreaseButton->getHeight()); + mIncreaseButton->setPosition( + mDecreaseButton->getX() + mDecreaseButton->getWidth() + 5, + mDecreaseButton->getY()); + + mQuitButton->setPosition( + width - 8 - mQuitButton->getWidth(), + height - 8 - mQuitButton->getHeight()); + mBuyButton->setPosition( + mQuitButton->getX() - 5 - mBuyButton->getWidth(), + mQuitButton->getY()); + + mItemDescLabel->setDimension(gcn::Rectangle(8, + mBuyButton->getY() - 5 - mItemDescLabel->getHeight(), + width - 16, + mItemDescLabel->getHeight())); + mItemEffectLabel->setDimension(gcn::Rectangle(8, + mItemDescLabel->getY() - 5 - mItemEffectLabel->getHeight(), + width - 16, + mItemEffectLabel->getHeight())); + mMoneyLabel->setDimension(gcn::Rectangle(8, + mItemEffectLabel->getY() - 5 - mMoneyLabel->getHeight(), + width - 16, + mMoneyLabel->getHeight())); + + mQuantityLabel->setPosition( + width - mQuantityLabel->getWidth() - 8, + mMoneyLabel->getY() - 5 - mQuantityLabel->getHeight()); + mSlider->setDimension(gcn::Rectangle(8, + mQuantityLabel->getY(), + mQuantityLabel->getX() - 8 - 8, + 10)); + + mScrollArea->setDimension(gcn::Rectangle(8, 8, width - 16, + mSlider->getY() - 5 - 8)); } void @@ -232,14 +264,13 @@ BuyDialog::updateButtonsAndLabels() // Enable or disable buttons and slider mIncreaseButton->setEnabled(mAmountItems < mMaxItems); - mDecreaseButton->setEnabled(mAmountItems > 0); + mDecreaseButton->setEnabled(mAmountItems > 1); mBuyButton->setEnabled(mAmountItems > 0); - mSlider->setEnabled(mMaxItems > 0); + mSlider->setEnabled(mMaxItems > 1); // Update quantity and money labels - mQuantityLabel->setCaption(toString(mAmountItems)); - mQuantityLabel->adjustSize(); + mQuantityLabel->setCaption( + toString(mAmountItems) + " / " + toString(mMaxItems)); mMoneyLabel->setCaption("Price: " + toString(price) + " GP / " + toString(mMoney - price) + " GP" ); - mMoneyLabel->adjustSize(); } diff --git a/src/gui/buy.h b/src/gui/buy.h index 875deef9..63d25583 100644 --- a/src/gui/buy.h +++ b/src/gui/buy.h @@ -28,11 +28,11 @@ #include "window.h" #include "selectionlistener.h" -#include "shoplistbox.h" #include "../guichanfwd.h" class ShopItems; +class ShopListBox; class ListBox; /** @@ -40,7 +40,8 @@ class ListBox; * * \ingroup Interface */ -class BuyDialog : public Window, public gcn::ActionListener, SelectionListener +class BuyDialog : public Window, public gcn::ActionListener, SelectionListener, + WindowListener { public: /** @@ -98,6 +99,11 @@ class BuyDialog : public Window, public gcn::ActionListener, SelectionListener void updateButtonsAndLabels(); + /** + * Called whenever the window is resized. + */ + void windowResized(const WindowEvent &event); + private: gcn::Button *mBuyButton; gcn::Button *mQuitButton; diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp index d752cdb3..e8381bef 100644 --- a/src/gui/char_select.cpp +++ b/src/gui/char_select.cpp @@ -48,6 +48,7 @@ #include "../utils/gettext.h" #include "../utils/strprintf.h" #include "../utils/tostring.h" +#include "../utils/trim.h" // Defined in main.cpp, used here for setting the char create dialog extern CharServerHandler charServerHandler; @@ -255,11 +256,6 @@ bool CharSelectDialog::selectByName(const std::string &name) return false; } -std::string CharSelectDialog::getName() -{ - return mNameLabel->getCaption(); -} - CharCreateDialog::CharCreateDialog(Window *parent, int slot): Window(_("Create Character"), true, parent), mSlot(slot) { @@ -410,10 +406,12 @@ CharCreateDialog::action(const gcn::ActionEvent &event) } } -const std::string& +std::string CharCreateDialog::getName() { - return mNameField->getText(); + std::string name = mNameField->getText(); + trim(name); + return name; } void CharCreateDialog::UpdateSliders() diff --git a/src/gui/char_select.h b/src/gui/char_select.h index 9d9184ea..5d0b42fa 100644 --- a/src/gui/char_select.h +++ b/src/gui/char_select.h @@ -60,11 +60,6 @@ class CharSelectDialog : public Window, public gcn::ActionListener bool selectByName(const std::string &name); - /** - * Returns name of selected player - */ - std::string getName(); - private: LockedArray *mCharInfo; @@ -114,22 +109,28 @@ class CharCreateDialog : public Window, public gcn::ActionListener */ ~CharCreateDialog(); - void - action(const gcn::ActionEvent &event); - - const std::string& - getName(); + void action(const gcn::ActionEvent &event); /** * Unlocks the dialog, enabling the create character button again. */ - void - unlock(); + void unlock(); private: int getDistributedPoints(); + void UpdateSliders(); + /** + * Returns the name of the character to create. + */ + std::string getName(); + + /** + * Communicate character creation to the server. + */ + void attemptCharCreate(); + gcn::TextField *mNameField; gcn::Label *mNameLabel; gcn::Button *mNextHairColorButton; @@ -154,12 +155,6 @@ class CharCreateDialog : public Window, public gcn::ActionListener static const int mMaxPoints = 70; int mUsedPoints; - - - /** - * Communicate character creation to the server. - */ - void attemptCharCreate(); }; #endif diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp index ba7c7f02..4ed8bb97 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -44,6 +44,7 @@ #include "../net/gameserver/player.h" #include "../utils/dtor.h" +#include "../utils/trim.h" ChatWindow::ChatWindow(): Window(), @@ -125,7 +126,7 @@ void ChatWindow::chatLog(std::string line, int own, std::string channelName) { // Delete overhead from the end of the list - while ((int)mChatlog.size() > mItemsKeep) { + while ((int) mChatlog.size() > mItemsKeep) { mChatlog.pop_back(); } @@ -142,12 +143,15 @@ ChatWindow::chatLog(std::string line, int own, std::string channelName) own = BY_SERVER; } - int pos = line.find(" : "); - if (pos > 0) { + std::string::size_type pos = line.find(" : "); + if (pos != std::string::npos) { tmp.nick = line.substr(0, pos); line.erase(0, pos + 3); } + // Trim whitespace + trim(line); + std::string lineColor = "##0"; // Equiv. to BrowserBox::BLACK switch (own) { case BY_GM: diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp index 11ad37c2..884cdf7e 100644 --- a/src/gui/debugwindow.cpp +++ b/src/gui/debugwindow.cpp @@ -42,6 +42,7 @@ DebugWindow::DebugWindow(): Window("Debug") { setResizable(true); + setCloseButton(true); setDefaultSize(0, 0, 400, 100); loadWindowState("Debug"); @@ -60,15 +61,11 @@ DebugWindow::DebugWindow(): mParticleCountLabel = new gcn::Label("[Particle count: 0]"); mParticleCountLabel->setPosition(100, 60); - Button *closeButton = new Button("Close", "close", this); - closeButton->setPosition(5, 60); - add(mFPSLabel); add(mMusicFileLabel); add(mMapFileLabel); add(mTileMouseLabel); add(mParticleCountLabel); - add(closeButton); } void @@ -106,12 +103,3 @@ DebugWindow::logic() +"]"); mParticleCountLabel->adjustSize(); } - -void -DebugWindow::action(const gcn::ActionEvent &event) -{ - if (event.getId() == "close") - { - setVisible(false); - } -} diff --git a/src/gui/debugwindow.h b/src/gui/debugwindow.h index d082b2ca..9b6f2017 100644 --- a/src/gui/debugwindow.h +++ b/src/gui/debugwindow.h @@ -33,11 +33,11 @@ #include "../guichanfwd.h" /** - * The chat window. + * The debug window. * * \ingroup Interface */ -class DebugWindow : public Window, public gcn::ActionListener +class DebugWindow : public Window { public: /** @@ -50,11 +50,6 @@ class DebugWindow : public Window, public gcn::ActionListener */ void logic(); - /** - * Performs action. - */ - void action(const gcn::ActionEvent &event); - private: gcn::Label *mMusicFileLabel, *mMapFileLabel; gcn::Label *mTileMouseLabel, *mFPSLabel; diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp index 5e835985..c86a27fc 100644 --- a/src/gui/equipmentwindow.cpp +++ b/src/gui/equipmentwindow.cpp @@ -59,6 +59,7 @@ EquipmentWindow::EquipmentWindow(Equipment *equipment): mBackground(NULL), mSelected(-1) { + setCloseButton(true); setDefaultSize(5, 195, 216, 260); loadWindowState("Equipment"); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index dc51054c..97dd4d44 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -42,7 +42,7 @@ #include "../graphics.h" #include "../log.h" -#include "../resources/image.h" +#include "../resources/imageset.h" #include "../resources/resourcemanager.h" #include "../resources/imageloader.h" @@ -77,8 +77,9 @@ class GuiConfigListener : public ConfigListener }; Gui::Gui(Graphics *graphics): - mMouseCursor(NULL), - mCustomCursor(false) + mCustomCursor(false), + mMouseCursors(NULL), + mCursorType(CURSOR_POINTER) { logger->log("Initializing GUI..."); // Set graphics @@ -106,7 +107,7 @@ Gui::Gui(Graphics *graphics): // Set global font try { - mGuiFont = new TrueTypeFont("data/fonts/dejavusans.ttf", 12); + mGuiFont = new TrueTypeFont("data/fonts/dejavusans.ttf", 11); } catch (gcn::Exception e) { @@ -139,7 +140,7 @@ Gui::Gui(Graphics *graphics): hitBlueFont = new gcn::ImageFont("graphics/gui/hits_blue.png", "0123456789"); hitYellowFont = new gcn::ImageFont("graphics/gui/hits_yellow.png", - "mis"); + "0123456789misxp "); } catch (gcn::Exception e) { @@ -169,8 +170,8 @@ Gui::~Gui() delete hitBlueFont; delete hitYellowFont; - if (mMouseCursor) { - mMouseCursor->decRef(); + if (mMouseCursors) { + mMouseCursors->decRef(); } delete mGuiFont; @@ -181,12 +182,6 @@ Gui::~Gui() delete guiInput; } -void -Gui::logic() -{ - gcn::Gui::logic(); -} - void Gui::draw() { @@ -196,11 +191,13 @@ Gui::draw() int mouseX, mouseY; Uint8 button = SDL_GetMouseState(&mouseX, &mouseY); - if ((SDL_GetAppState() & SDL_APPMOUSEFOCUS || button & SDL_BUTTON(1)) - && mCustomCursor) + if ((SDL_GetAppState() & SDL_APPMOUSEFOCUS || button & SDL_BUTTON(1)) && + mCustomCursor) { - static_cast(mGraphics)-> - drawImage(mMouseCursor, mouseX - 5, mouseY - 2); + static_cast(mGraphics)->drawImage( + mMouseCursors->get(mCursorType), + mouseX - 15, + mouseY - 17); } mGraphics->popClipArea(); @@ -220,9 +217,11 @@ Gui::setUseCustomCursor(bool customCursor) // Load the mouse cursor ResourceManager *resman = ResourceManager::getInstance(); - mMouseCursor = resman->getImage("graphics/gui/mouse.png"); - if (!mMouseCursor) { - logger->error("Unable to load mouse cursor."); + mMouseCursors = + resman->getImageSet("graphics/gui/mouse.png", 40, 40); + + if (!mMouseCursors) { + logger->error("Unable to load mouse cursors."); } } else @@ -231,9 +230,9 @@ Gui::setUseCustomCursor(bool customCursor) SDL_ShowCursor(SDL_ENABLE); // Unload the mouse cursor - if (mMouseCursor) { - mMouseCursor->decRef(); - mMouseCursor = NULL; + if (mMouseCursors) { + mMouseCursors->decRef(); + mMouseCursors = NULL; } } } diff --git a/src/gui/gui.h b/src/gui/gui.h index 5f2cc810..1e4b9348 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -30,7 +30,7 @@ class GuiConfigListener; class Graphics; -class Image; +class ImageSet; class Viewport; /** @@ -59,36 +59,49 @@ class Gui : public gcn::Gui */ ~Gui(); - /** - * Works around Guichan bug - */ - void - logic(); - /** * Draws the whole Gui by calling draw functions down in the * Gui hierarchy. It also draws the mouse pointer. */ - void - draw(); + void draw(); /** - * Return game font + * Return game font. */ - gcn::Font* - getFont() { return mGuiFont; } + gcn::Font* getFont() const + { return mGuiFont; } /** * Sets whether a custom cursor should be rendered. */ - void - setUseCustomCursor(bool customCursor); + void setUseCustomCursor(bool customCursor); + + /** + * Sets which cursor should be used. + */ + void setCursorType(int index) + { mCursorType = index; } + + /** + * Cursors are in graphic order from left to right. + * CURSOR_POINTER should be left untouched. + * CURSOR_TOTAL should always be last. + */ + enum { + CURSOR_POINTER = 0, + CURSOR_RESIZE_ACROSS, + CURSOR_RESIZE_DOWN, + CURSOR_RESIZE_DOWN_LEFT, + CURSOR_RESIZE_DOWN_RIGHT, + CURSOR_TOTAL + }; private: GuiConfigListener *mConfigListener; gcn::Font *mGuiFont; /**< The global GUI font */ - Image *mMouseCursor; /**< Mouse cursor image */ bool mCustomCursor; /**< Show custom cursor */ + ImageSet *mMouseCursors; /**< Mouse cursor images */ + int mCursorType; }; extern Gui *gui; /**< The GUI system */ diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index 085ab188..1e62b130 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -51,6 +51,7 @@ InventoryWindow::InventoryWindow(): mSplit(false) { setResizable(true); + setCloseButton(true); setMinWidth(240); setMinHeight(172); // If you adjust these defaults, don't forget to adjust the trade window's. @@ -69,7 +70,6 @@ InventoryWindow::InventoryWindow(): mItems->addSelectionListener(this); mInvenScroll = new ScrollArea(mItems); - mInvenScroll->setPosition(8, 8); mItemNameLabel = new gcn::Label(strprintf(_("Name: %s"), "")); mItemDescriptionLabel = new gcn::Label( @@ -100,8 +100,8 @@ InventoryWindow::InventoryWindow(): mSplitButton->setWidth(48); } + addWindowListener(this); loadWindowState("Inventory"); - updateContentSize(); } InventoryWindow::~InventoryWindow() @@ -130,7 +130,6 @@ void InventoryWindow::logic() mWeightLabel->setCaption( strprintf(_("Total Weight: %d - Maximum Weight: %d"), player_node->getTotalWeight(), player_node->getMaxWeight())); - mWeightLabel->adjustSize(); } void InventoryWindow::action(const gcn::ActionEvent &event) @@ -215,7 +214,7 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event) } } -void InventoryWindow::updateContentSize() +void InventoryWindow::windowResized(const WindowEvent &event) { const gcn::Rectangle area = getChildrenArea(); @@ -260,8 +259,7 @@ Item* InventoryWindow::getItem() return mItems->getItem(); } -void -InventoryWindow::keyPressed(gcn::KeyEvent &event) +void InventoryWindow::keyPressed(gcn::KeyEvent &event) { switch (event.getKey().getValue()) { @@ -271,8 +269,7 @@ InventoryWindow::keyPressed(gcn::KeyEvent &event) } } -void -InventoryWindow::keyReleased(gcn::KeyEvent &event) +void InventoryWindow::keyReleased(gcn::KeyEvent &event) { switch (event.getKey().getValue()) { diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h index 37ef0406..a9fdadf2 100644 --- a/src/gui/inventorywindow.h +++ b/src/gui/inventorywindow.h @@ -29,8 +29,9 @@ #include -#include "window.h" #include "selectionlistener.h" +#include "window.h" +#include "windowlistener.h" #include "../guichanfwd.h" @@ -45,7 +46,8 @@ class ItemContainer; class InventoryWindow : public Window, public gcn::ActionListener, public gcn::KeyListener, - public SelectionListener + public SelectionListener, + public WindowListener { public: /** @@ -92,7 +94,10 @@ class InventoryWindow : public Window, */ void selectionChanged(const SelectionEvent &event); - void updateContentSize(); /**< Updates widgets size/position. */ + /** + * Called whenever the window is resized. + */ + void windowResized(const WindowEvent &event); private: void updateButtons(); /**< Updates button states. */ diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp index b032bd49..bddf7cee 100644 --- a/src/gui/itemcontainer.cpp +++ b/src/gui/itemcontainer.cpp @@ -30,6 +30,7 @@ #include "../graphics.h" #include "../inventory.h" #include "../item.h" +#include "../itemshortcut.h" #include "../localplayer.h" #include "../resources/image.h" @@ -38,6 +39,9 @@ #include "../utils/tostring.h" +// TODO: Add support for adding items to the item shortcut window (global +// itemShortcut). + static const int BOX_WIDTH = 36; static const int BOX_HEIGHT = 44; diff --git a/src/gui/itemshortcutcontainer.cpp b/src/gui/itemshortcutcontainer.cpp new file mode 100644 index 00000000..1943ef93 --- /dev/null +++ b/src/gui/itemshortcutcontainer.cpp @@ -0,0 +1,224 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "itemshortcutcontainer.h" + +#include "../graphics.h" +#include "../item.h" +#include "../itemshortcut.h" +#include "../keyboardconfig.h" + +#include "../resources/image.h" +#include "../resources/resourcemanager.h" + +#include "../utils/tostring.h" + +ItemShortcutContainer::ItemShortcutContainer(): + mGridWidth(1), + mGridHeight(1), + mItemClicked(false), + mItemMoved(NULL) +{ + addMouseListener(this); + + ResourceManager *resman = ResourceManager::getInstance(); + + mBackgroundImg = resman->getImage("graphics/gui/item_shortcut_bgr.png"); + mMaxItems = itemShortcut->getItemCount(); + + mBoxHeight = 42; + mBoxWidth = 36; +} + +ItemShortcutContainer::~ItemShortcutContainer() +{ + mBackgroundImg->decRef(); +} + +void +ItemShortcutContainer::logic() +{ + gcn::Widget::logic(); + + int i = itemShortcut->getItemCount(); + + if (i != mMaxItems) + { + mMaxItems = i; + setWidth(getWidth()); + } +} + +void +ItemShortcutContainer::draw(gcn::Graphics *graphics) +{ + Graphics *g = static_cast(graphics); + + for (int i = 0; i < mMaxItems; i++) + { + const int itemX = (i % mGridWidth) * mBoxWidth; + const int itemY = (i / mGridWidth) * mBoxHeight; + + g->drawImage(mBackgroundImg, itemX, itemY); + + // Draw item keyboard shortcut. + const char *key = SDL_GetKeyName( + (SDLKey) keyboard.getKeyValue(keyboard.KEY_SHORTCUT_0+i)); + g->drawText(key, itemX + 2, itemY + 2, gcn::Graphics::LEFT); + + Item *item = itemShortcut->getItem(i); + if (item) { + // Draw item icon. + Image* image = item->getInfo().getImage(); + if (image) { + g->drawImage(image, itemX, itemY); + g->drawText( + toString(item->getQuantity()), + itemX + mBoxWidth / 2, + itemY + mBoxHeight - 14, + gcn::Graphics::CENTER); + } + } + } + if (mItemMoved) + { + // Draw the item image being dragged by the cursor. + Image* image = mItemMoved->getInfo().getImage(); + if (image) + { + const int tPosX = mCursorPosX - (image->getWidth() / 2); + const int tPosY = mCursorPosY - (image->getHeight() / 2); + + g->drawImage(image, tPosX, tPosY); + g->drawText( + toString(mItemMoved->getQuantity()), + tPosX + mBoxWidth / 2, + tPosY + mBoxHeight - 14, + gcn::Graphics::CENTER); + } + } +} + +void +ItemShortcutContainer::setWidth(int width) +{ + gcn::Widget::setWidth(width); + + mGridWidth = getWidth() / mBoxWidth; + if (mGridWidth < 1) { + mGridWidth = 1; + } + + setHeight((mMaxItems / mGridWidth + + (mMaxItems % mGridWidth > 0 ? 1 : 0)) * mBoxHeight); + + mGridHeight = getHeight() / mBoxHeight; + if (mGridHeight < 1) { + mGridHeight = 1; + } +} + +void +ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event) +{ + if (event.getButton() == gcn::MouseEvent::LEFT) { + if (!mItemMoved && mItemClicked) { + const int index = getIndexFromGrid(event.getX(), event.getY()); + if (index == -1) { + return; + } + Item *item = itemShortcut->getItem(index); + if (item) + { + mItemMoved = item; + itemShortcut->removeItem(index); + } + } + if (mItemMoved) { + mCursorPosX = event.getX(); + mCursorPosY = event.getY(); + } + } +} + +void +ItemShortcutContainer::mousePressed(gcn::MouseEvent &event) +{ + const int index = getIndexFromGrid(event.getX(), event.getY()); + if (index == -1) { + return; + } + + // Stores the selected item if theirs one. + if (itemShortcut->isItemSelected()) { + itemShortcut->setItem(index); + itemShortcut->setItemSelected(NULL); + } + else if (itemShortcut->getItem(index)) { + mItemClicked = true; + } +} + +void +ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event) +{ + if (event.getButton() == gcn::MouseEvent::LEFT) + { + if (itemShortcut->isItemSelected()) + { + itemShortcut->setItemSelected(NULL); + } + const int index = getIndexFromGrid(event.getX(), event.getY()); + if (index == -1) { + mItemMoved = NULL; + return; + } + if (mItemMoved) { + itemShortcut->setItems(index, mItemMoved); + mItemMoved = NULL; + } + else if (itemShortcut->getItem(index) && mItemClicked) + { + itemShortcut->useItem(index); + } + if (mItemClicked) { + mItemClicked = false; + } + } +} + +int +ItemShortcutContainer::getIndexFromGrid(int pointX, int pointY) const +{ + const gcn::Rectangle tRect = gcn::Rectangle( + 0, 0, mGridWidth * mBoxWidth, mGridHeight * mBoxHeight); + if (!tRect.isPointInRect(pointX, pointY)) { + return -1; + } + const int index = ((pointY / mBoxHeight) * mGridWidth) + + pointX / mBoxWidth; + if (index >= mMaxItems) + { + return -1; + } + return index; +} diff --git a/src/gui/itemshortcutcontainer.h b/src/gui/itemshortcutcontainer.h new file mode 100644 index 00000000..4b154cbb --- /dev/null +++ b/src/gui/itemshortcutcontainer.h @@ -0,0 +1,115 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _TMW_ITEMSHORTCUTCONTAINER_H__ +#define _TMW_ITEMSHORTCUTCONTAINER_H__ + +#include +#include + +#include + +class Image; +class Item; + +/** + * An item shortcut container. Used to quickly use items. + * + * \ingroup GUI + */ +class ItemShortcutContainer : public gcn::Widget, public gcn::MouseListener +{ + public: + /** + * Constructor. Initializes the graphic. + */ + ItemShortcutContainer(); + + /** + * Destructor. + */ + virtual ~ItemShortcutContainer(); + + /** + * Handles the logic of the ItemContainer + */ + void logic(); + + /** + * Draws the items. + */ + void draw(gcn::Graphics *graphics); + + /** + * Sets the width of the container. This is used to determine the new + * height of the container. + */ + void setWidth(int width); + + /** + * Handles mouse when dragged. + */ + void mouseDragged(gcn::MouseEvent &event); + + /** + * Handles mouse when pressed. + */ + void mousePressed(gcn::MouseEvent &event); + + /** + * Handles mouse release. + */ + void mouseReleased(gcn::MouseEvent &event); + + + int getMaxItems() + { return mMaxItems; } + + int getBoxWidth() + { return mBoxWidth; } + + int getBoxHeight() + { return mBoxHeight; } + + private: + /** + * Gets the index from the grid provided the point is in an item box. + * + * @param pointX X coordinate of the point. + * @param pointY Y coordinate of the point. + * @return index on success, -1 on failure. + */ + int getIndexFromGrid(int pointX, int pointY) const; + + Image *mBackgroundImg; + + int mMaxItems; + int mBoxWidth; + int mBoxHeight; + int mCursorPosX, mCursorPosY; + int mGridWidth, mGridHeight; + bool mItemClicked; + Item *mItemMoved; + +}; + +#endif diff --git a/src/gui/itemshortcutwindow.cpp b/src/gui/itemshortcutwindow.cpp new file mode 100644 index 00000000..dd97a7db --- /dev/null +++ b/src/gui/itemshortcutwindow.cpp @@ -0,0 +1,74 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "itemshortcutwindow.h" + +#include "itemshortcutcontainer.h" +#include "scrollarea.h" + +static const int SCROLL_PADDING = 0; + +ItemShortcutWindow::ItemShortcutWindow() +{ + // no title presented, title bar is padding so window can be moved. + gcn::Window::setTitleBarHeight(gcn::Window::getPadding()); + setShowTitle(false); + setResizable(true); + setDefaultSize(758, 174, 42, 426); + + mItems = new ItemShortcutContainer(); + + int border = SCROLL_PADDING * 2 + getPadding() * 2; + setMinWidth(mItems->getBoxWidth() + border); + setMinHeight(mItems->getBoxHeight() + border); + setMaxWidth(mItems->getBoxWidth() * mItems->getMaxItems() + border); + setMaxHeight(mItems->getBoxHeight() * mItems->getMaxItems() + border); + + mInvenScroll = new ScrollArea(mItems); + mInvenScroll->setPosition(SCROLL_PADDING, SCROLL_PADDING); + mInvenScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + add(mInvenScroll); + + addWindowListener(this); + loadWindowState("ItemShortcut"); +} + +ItemShortcutWindow::~ItemShortcutWindow() +{ + delete mItems; + delete mInvenScroll; +} + +void ItemShortcutWindow::logic() +{ + Window::logic(); +} + +void ItemShortcutWindow::windowResized(const WindowEvent &event) +{ + const gcn::Rectangle area = getChildrenArea(); + + mInvenScroll->setSize( + area.width - SCROLL_PADDING, + area.height - SCROLL_PADDING); +} diff --git a/src/gui/itemshortcutwindow.h b/src/gui/itemshortcutwindow.h new file mode 100644 index 00000000..83bc348d --- /dev/null +++ b/src/gui/itemshortcutwindow.h @@ -0,0 +1,69 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _TMW_ITEMSHORTCUTWINDOW_H +#define _TMW_ITEMSHORTCUTWINDOW_H + +#include "window.h" +#include "windowlistener.h" + +#include "../guichanfwd.h" + +class ItemShortcutContainer; + +/** + * Inventory dialog. + * + * \ingroup Interface + */ +class ItemShortcutWindow : public Window, WindowListener +{ + public: + /** + * Constructor. + */ + ItemShortcutWindow(); + + /** + * Destructor. + */ + ~ItemShortcutWindow(); + + /** + * Logic (updates buttons and weight information). + */ + void logic(); + + /** + * Called whenever the window is resized. + */ + void windowResized(const WindowEvent &event); + + private: + ItemShortcutContainer *mItems; + + gcn::ScrollArea *mInvenScroll; +}; + +extern ItemShortcutWindow *itemShortcutWindow; + +#endif diff --git a/src/gui/menuwindow.cpp b/src/gui/menuwindow.cpp index bfa2f1f2..8d4d184d 100644 --- a/src/gui/menuwindow.cpp +++ b/src/gui/menuwindow.cpp @@ -37,6 +37,7 @@ extern Window *inventoryWindow; extern Window *equipmentWindow; extern Window *skillDialog; extern Window *statusWindow; +extern Window *itemShortcutWindow; namespace { struct MenuWindowListener : public gcn::ActionListener @@ -62,6 +63,7 @@ MenuWindow::MenuWindow(): N_("Equipment"), N_("Inventory"), N_("Skills"), + N_("Shortcut"), N_("Setup"), 0 }; @@ -109,14 +111,20 @@ void MenuWindowListener::action(const gcn::ActionEvent &event) { window = skillDialog; } + else if (event.getId() == "Shortcut") + { + window = itemShortcutWindow; + } else if (event.getId() == "Setup") { window = setupWindow; } - if (window) { + if (window) + { window->setVisible(!window->isVisible()); - if (window->isVisible()) { + if (window->isVisible()) + { window->requestMoveToTop(); } } diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index 48bbd3d0..aeb6637d 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -200,12 +200,6 @@ void PopupMenu::handleLink(const std::string& link) setVisible(false); - /* - * This is need cause of a bug in guichan that leave - * the focus on the popup menu even if is not visible. - */ - _getFocusHandler()->focusNone(); - mBeing = NULL; mFloorItem = NULL; mItem = NULL; diff --git a/src/gui/selectionlistener.h b/src/gui/selectionlistener.h index b39672b5..917a4871 100644 --- a/src/gui/selectionlistener.h +++ b/src/gui/selectionlistener.h @@ -25,33 +25,23 @@ #define _TMW_SELECTIONLISTENER_H__ #include +#include /** * An event that characterizes a change in the current selection. * * \ingroup GUI */ -class SelectionEvent +class SelectionEvent : public gcn::Event { public: /** * Constructor. */ SelectionEvent(gcn::Widget *source): - mSource(source) + gcn::Event(source) { } - - /** - * The widget from which the event originated. - */ - gcn::Widget* getSource() const - { - return mSource; - } - - private: - gcn::Widget *mSource; }; /** diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index b601d70c..5f1011c1 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -44,58 +44,44 @@ SellDialog::SellDialog(): Window("Sell"), mMaxItems(0), mAmountItems(0) { + setResizable(true); + setMinWidth(260); + setMinHeight(230); + setDefaultSize(0, 0, 260, 230); + mShopItems = new ShopItems(); mShopItemList = new ShopListBox(mShopItems, mShopItems); - ScrollArea *scrollArea = new ScrollArea(mShopItemList); + mScrollArea = new ScrollArea(mShopItemList); mSlider = new Slider(1.0); mQuantityLabel = new gcn::Label("0"); mMoneyLabel = new gcn::Label("Money: 0 GP / Total: 0 GP"); - mItemDescLabel = new gcn::Label("Description:"); - mItemEffectLabel = new gcn::Label("Effect:"); mIncreaseButton = new Button("+", "+", this); mDecreaseButton = new Button("-", "-", this); mSellButton = new Button("Sell", "sell", this); - Button *quitButton = new Button("Quit", "quit", this); - mSellButton->setEnabled(false); - - setContentSize(260, 210); - scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - scrollArea->setDimension(gcn::Rectangle(5, 5, 250, 110)); - mShopItemList->setDimension(gcn::Rectangle(5, 5, 238, 110)); - - mSlider->setDimension(gcn::Rectangle(5, 120, 200, 10)); - mSlider->setEnabled(false); - - mQuantityLabel->setPosition(215, 120); + mQuitButton = new Button("Quit", "quit", this); + mItemDescLabel = new gcn::Label("Description:"); + mItemEffectLabel = new gcn::Label("Effect:"); - mIncreaseButton->setPosition(40, 186); mIncreaseButton->setSize(20, 20); - mIncreaseButton->setEnabled(false); - - mDecreaseButton->setPosition(10, 186); mDecreaseButton->setSize(20, 20); - mDecreaseButton->setEnabled(false); + mQuantityLabel->setWidth(60); - mMoneyLabel->setPosition(5, 130); - mItemEffectLabel->setDimension(gcn::Rectangle(5, 150, 240, 14)); - mItemDescLabel->setDimension(gcn::Rectangle(5, 169, 240, 14)); - - mSellButton->setPosition(175, 186); + mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mIncreaseButton->setEnabled(false); + mDecreaseButton->setEnabled(false); mSellButton->setEnabled(false); + mSlider->setEnabled(false); - quitButton->setPosition(208, 186); - + mShopItemList->setPriceCheck(false); mShopItemList->setActionEventId("item"); mSlider->setActionEventId("slider"); - mShopItemList->setPriceCheck(false); - mShopItemList->addActionListener(this); mShopItemList->addSelectionListener(this); mSlider->addActionListener(this); - add(scrollArea); + add(mScrollArea); add(mSlider); add(mQuantityLabel); add(mMoneyLabel); @@ -104,8 +90,10 @@ SellDialog::SellDialog(): add(mIncreaseButton); add(mDecreaseButton); add(mSellButton); - add(quitButton); + add(mQuitButton); + addWindowListener(this); + loadWindowState("Sell"); setLocationRelativeTo(getParent()); } @@ -117,7 +105,7 @@ SellDialog::~SellDialog() void SellDialog::reset() { mShopItems->clear(); - mSlider->setValue(0.0); + mSlider->setValue(0); // Reset previous selected item to prevent failing asserts mShopItemList->setSelected(-1); @@ -135,16 +123,11 @@ void SellDialog::action(const gcn::ActionEvent &event) { int selectedItem = mShopItemList->getSelected(); - if (event.getId() == "item") - { - mAmountItems = 0; - mSlider->setValue(0); - updateButtonsAndLabels(); - } - else if (event.getId() == "quit") + if (event.getId() == "quit") { setVisible(false); current_npc = 0; + return; } // The following actions require a valid item selection @@ -156,21 +139,19 @@ void SellDialog::action(const gcn::ActionEvent &event) if (event.getId() == "slider") { - mAmountItems = (int) (mSlider->getValue() * mMaxItems); + mAmountItems = (int) mSlider->getValue(); updateButtonsAndLabels(); } else if (event.getId() == "+" && mAmountItems < mMaxItems) { mAmountItems++; - - mSlider->setValue((double) mAmountItems /(double) mMaxItems); + mSlider->setValue(mAmountItems); updateButtonsAndLabels(); } - else if (event.getId() == "-" && mAmountItems > 0) + else if (event.getId() == "-" && mAmountItems > 1) { mAmountItems--; - - mSlider->setValue((double) mAmountItems / (double) mMaxItems); + mSlider->setValue(mAmountItems); updateButtonsAndLabels(); } else if (event.getId() == "sell" && mAmountItems > 0 @@ -182,8 +163,7 @@ void SellDialog::action(const gcn::ActionEvent &event) mMaxItems -= mAmountItems; mShopItems->getShop()->at(selectedItem).quantity = mMaxItems; mPlayerMoney += (mAmountItems * mShopItems->at(selectedItem).price); - mAmountItems = 0; - mSlider->setValue(0); + mAmountItems = 1; if (!mMaxItems) { @@ -194,6 +174,7 @@ void SellDialog::action(const gcn::ActionEvent &event) } else { + mSlider->gcn::Slider::setScale(1, mMaxItems); // Update only when there are items left, the entry doesn't exist // otherwise and can't be updated updateButtonsAndLabels(); @@ -204,10 +185,54 @@ void SellDialog::action(const gcn::ActionEvent &event) void SellDialog::selectionChanged(const SelectionEvent &event) { // Reset amount of items and update labels - mAmountItems = 0; + mAmountItems = 1; mSlider->setValue(0); updateButtonsAndLabels(); + mSlider->gcn::Slider::setScale(1, mMaxItems); +} + +void SellDialog::windowResized(const WindowEvent &event) +{ + gcn::Rectangle area = getChildrenArea(); + int width = area.width; + int height = area.height; + + mDecreaseButton->setPosition(8, height - 8 - mDecreaseButton->getHeight()); + mIncreaseButton->setPosition( + mDecreaseButton->getX() + mDecreaseButton->getWidth() + 5, + mDecreaseButton->getY()); + + mQuitButton->setPosition( + width - 8 - mQuitButton->getWidth(), + height - 8 - mQuitButton->getHeight()); + mSellButton->setPosition( + mQuitButton->getX() - 5 - mSellButton->getWidth(), + mQuitButton->getY()); + + mItemDescLabel->setDimension(gcn::Rectangle(8, + mSellButton->getY() - 5 - mItemDescLabel->getHeight(), + width - 16, + mItemDescLabel->getHeight())); + mItemEffectLabel->setDimension(gcn::Rectangle(8, + mItemDescLabel->getY() - 5 - mItemEffectLabel->getHeight(), + width - 16, + mItemEffectLabel->getHeight())); + mMoneyLabel->setDimension(gcn::Rectangle(8, + mItemEffectLabel->getY() - 5 - mMoneyLabel->getHeight(), + width - 16, + mMoneyLabel->getHeight())); + + mQuantityLabel->setPosition( + width - mQuantityLabel->getWidth() - 8, + mMoneyLabel->getY() - 5 - mQuantityLabel->getHeight()); + mSlider->setDimension(gcn::Rectangle(8, + mQuantityLabel->getY(), + mQuantityLabel->getX() - 8 - 8, + 10)); + + mScrollArea->setDimension(gcn::Rectangle(8, 8, width - 16, + mSlider->getY() - 5 - 8)); } void SellDialog::setMoney(int amount) @@ -246,15 +271,13 @@ SellDialog::updateButtonsAndLabels() // Update Buttons and slider mSellButton->setEnabled(mAmountItems > 0); - mDecreaseButton->setEnabled(mAmountItems > 0); + mDecreaseButton->setEnabled(mAmountItems > 1); mIncreaseButton->setEnabled(mAmountItems < mMaxItems); - mSlider->setEnabled(selectedItem > -1); + mSlider->setEnabled(mMaxItems > 1); // Update the quantity and money labels mQuantityLabel->setCaption( toString(mAmountItems) + " / " + toString(mMaxItems)); - mQuantityLabel->adjustSize(); mMoneyLabel->setCaption("Money: " + toString(income) + " GP / Total: " + toString(mPlayerMoney + income) + " GP"); - mMoneyLabel->adjustSize(); } diff --git a/src/gui/sell.h b/src/gui/sell.h index fc42fd1c..d1e2ddd2 100644 --- a/src/gui/sell.h +++ b/src/gui/sell.h @@ -28,6 +28,7 @@ #include "window.h" #include "selectionlistener.h" +#include "windowlistener.h" #include "../guichanfwd.h" @@ -40,7 +41,8 @@ class ShopListBox; * * \ingroup Interface */ -class SellDialog : public Window, gcn::ActionListener, SelectionListener +class SellDialog : public Window, gcn::ActionListener, SelectionListener, + WindowListener { public: /** @@ -77,22 +79,28 @@ class SellDialog : public Window, gcn::ActionListener, SelectionListener */ void selectionChanged(const SelectionEvent &event); + /** + * Called whenever the window is resized. + */ + void windowResized(const WindowEvent &event); + /** * Gives Player's Money amount */ void setMoney(int amount); + private: /** * Updates the state of buttons and labels. */ - void - updateButtonsAndLabels(); + void updateButtonsAndLabels(); - private: gcn::Button *mSellButton; + gcn::Button *mQuitButton; gcn::Button *mIncreaseButton; gcn::Button *mDecreaseButton; ShopListBox *mShopItemList; + gcn::ScrollArea *mScrollArea; gcn::Label *mMoneyLabel; gcn::Label *mItemDescLabel; gcn::Label *mItemEffectLabel; diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp index 3ea19059..6a13232a 100644 --- a/src/gui/setup.cpp +++ b/src/gui/setup.cpp @@ -27,6 +27,7 @@ #include "setup_audio.h" #include "setup_joystick.h" #include "setup_video.h" +#include "setup_keyboard.h" #include "tabbedcontainer.h" #include "../utils/dtor.h" @@ -43,7 +44,8 @@ extern Window *skillDialog; Setup::Setup(): Window(_("Setup")) { - int width = 230; + setCloseButton(true); + int width = 250; int height = 245; setContentSize(width, height); @@ -59,7 +61,7 @@ Setup::Setup(): } TabbedContainer *panel = new TabbedContainer(); - panel->setDimension(gcn::Rectangle(5, 5, 220, 205)); + panel->setDimension(gcn::Rectangle(5, 5, 250, 205)); panel->setOpaque(false); SetupTab *tab; @@ -76,6 +78,10 @@ Setup::Setup(): panel->addTab(tab, _("Joystick")); mTabs.push_back(tab); + tab = new Setup_Keyboard(); + panel->addTab(tab, "Keyboard"); + mTabs.push_back(tab); + add(panel); setLocationRelativeTo(getParent()); diff --git a/src/gui/setup_keyboard.cpp b/src/gui/setup_keyboard.cpp new file mode 100644 index 00000000..e88080b5 --- /dev/null +++ b/src/gui/setup_keyboard.cpp @@ -0,0 +1,187 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "setup_keyboard.h" + +#include +#include + +#include "button.h" +#include "listbox.h" +#include "ok_dialog.h" +#include "scrollarea.h" + +#include "../configuration.h" +#include "../keyboardconfig.h" + +#include "../utils/tostring.h" + +#include + +/** + * The list model for key function list. + * + * \ingroup Interface + */ +class KeyListModel : public gcn::ListModel +{ + public: + /** + * Returns the number of elements in container. + */ + int getNumberOfElements() { return keyboard.KEY_TOTAL; } + + /** + * Returns element from container. + */ + std::string getElementAt(int i) { return mKeyFunctions[i]; } + + /** + * Sets element from container. + */ + void setElementAt(int i, std::string caption) + { + mKeyFunctions[i] = caption; + } + + private: + std::string mKeyFunctions[KeyboardConfig::KEY_TOTAL]; +}; + +Setup_Keyboard::Setup_Keyboard(): + mKeyListModel(new KeyListModel()), + mKeyList(new ListBox(mKeyListModel)), + mKeySetting(false) +{ + keyboard.setSetupKeyboard(this); + setOpaque(false); + + refreshKeys(); + + mKeyList->setDimension(gcn::Rectangle(0, 0, 185, 140)); + mKeyList->addActionListener(this); + mKeyList->setSelected(-1); + + ScrollArea *scrollArea = new ScrollArea(mKeyList); + scrollArea->setDimension(gcn::Rectangle(10, 10, 200, 140)); + add(scrollArea); + + mAssignKeyButton = new Button("Assign", "assign", this); + mAssignKeyButton->setPosition(165, 155); + mAssignKeyButton->addActionListener(this); + mAssignKeyButton->setEnabled(false); + add(mAssignKeyButton); + + mMakeDefaultButton = new Button("Default", "makeDefault", this); + mMakeDefaultButton->setPosition(10, 155); + mMakeDefaultButton->addActionListener(this); + add(mMakeDefaultButton); +} + +Setup_Keyboard::~Setup_Keyboard() +{ + delete mKeyList; + delete mKeyListModel; + + delete mAssignKeyButton; + delete mMakeDefaultButton; +} + +void Setup_Keyboard::apply() +{ + keyUnresolved(); + + if (keyboard.hasConflicts()) + { + new OkDialog("Key Conflict(s) Detected.", + "Resolve them, or gameplay may result in strange behaviour."); + } + keyboard.setEnabled(true); + keyboard.store(); +} + +void Setup_Keyboard::cancel() +{ + keyUnresolved(); + + keyboard.retrieve(); + keyboard.setEnabled(true); + + refreshKeys(); +} + +void Setup_Keyboard::action(const gcn::ActionEvent &event) +{ + if (event.getSource() == mKeyList) + { + if (!mKeySetting) { + mAssignKeyButton->setEnabled(true); + } + } + else if (event.getId() == "assign") + { + mKeySetting = true; + mAssignKeyButton->setEnabled(false); + keyboard.setEnabled(false); + int i(mKeyList->getSelected()); + keyboard.setNewKeyIndex(i); + mKeyListModel->setElementAt(i, keyboard.getKeyCaption(i) + ": ?"); + } + else if (event.getId() == "makeDefault") + { + keyboard.makeDefault(); + refreshKeys(); + } +} + +void Setup_Keyboard::refreshAssignedKey(int index) +{ + std::string caption; + char *temp = SDL_GetKeyName( + (SDLKey) keyboard.getKeyValue(index)); + caption = keyboard.getKeyCaption(index) + ": " + toString(temp); + mKeyListModel->setElementAt(index, caption); +} + +void Setup_Keyboard::newKeyCallback(int index) +{ + mKeySetting = false; + refreshAssignedKey(index); + mAssignKeyButton->setEnabled(true); +} + +void Setup_Keyboard::refreshKeys() +{ + for(int i = 0; i < keyboard.KEY_TOTAL; i++) + { + refreshAssignedKey(i); + } +} + +void Setup_Keyboard::keyUnresolved() +{ + if (mKeySetting) { + newKeyCallback(keyboard.getNewKeyIndex()); + keyboard.setNewKeyIndex(keyboard.KEY_NO_VALUE); + } +} diff --git a/src/gui/setup_keyboard.h b/src/gui/setup_keyboard.h new file mode 100644 index 00000000..b72e8746 --- /dev/null +++ b/src/gui/setup_keyboard.h @@ -0,0 +1,84 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_GUI_SETUP_KEYBOARD_H +#define _TMW_GUI_SETUP_KEYBOARD_H + +#include "setuptab.h" +#include "button.h" +#include "../guichanfwd.h" + +#include + + +#include + +class Setup_Keyboard : public SetupTab, public gcn::ActionListener +{ + public: + /** + * Constructor + */ + Setup_Keyboard(); + + /** + * Destructor + */ + ~Setup_Keyboard(); + + void apply(); + void cancel(); + + void action(const gcn::ActionEvent &event); + + /** + * Get an update on the assigned key. + */ + void refreshAssignedKey(int index); + + /** + * The callback function when a new key has been pressed. + */ + void newKeyCallback(int index); + + /** + * Shorthand method to update all the keys. + */ + void refreshKeys(); + + /** + * If a key function is unresolved, then this reverts it. + */ + void keyUnresolved(); + + private: + class KeyListModel *mKeyListModel; + gcn::ListBox *mKeyList; + + gcn::Button *mAssignKeyButton; + gcn::Button *mMakeDefaultButton; + + bool mKeySetting; /**< flag to check if key being set. */ +}; + +#endif diff --git a/src/gui/shoplistbox.cpp b/src/gui/shoplistbox.cpp index 0e2ea6d3..ae787ab7 100644 --- a/src/gui/shoplistbox.cpp +++ b/src/gui/shoplistbox.cpp @@ -129,24 +129,8 @@ void ShopListBox::mousePressed(gcn::MouseEvent &event) { if (event.getButton() == gcn::MouseEvent::LEFT) { - bool enoughMoney = false; - int y = event.getY(); - - if (mShopItems && mPriceCheck) - { - if (mPlayerMoney >= mShopItems->at(y / mRowHeight).price) - enoughMoney = true; - } - else // Old Behaviour - { - enoughMoney = true; - } - - if (enoughMoney) - { - setSelected(y / mRowHeight); - generateAction(); - } + setSelected(event.getY() / mRowHeight); + generateAction(); } } diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp index 884b3744..d5cfe76a 100644 --- a/src/gui/skill.cpp +++ b/src/gui/skill.cpp @@ -63,22 +63,18 @@ const char *skill_db[] = { SkillDialog::SkillDialog(): Window("Skills") { + setCloseButton(true); setDefaultSize(windowContainer->getWidth() - 255, 25, 240, 240); mSkillListBox = new ListBox(this); ScrollArea *skillScrollArea = new ScrollArea(mSkillListBox); - mCloseButton = new Button("Close", "close", this); mSkillListBox->setActionEventId("skill"); skillScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); skillScrollArea->setDimension(gcn::Rectangle(5, 5, 230, 180)); - mCloseButton->setPosition( - skillScrollArea->getX() + skillScrollArea->getWidth() - mCloseButton->getWidth(), - 210); add(skillScrollArea); - add(mCloseButton); mSkillListBox->addActionListener(this); diff --git a/src/gui/skill.h b/src/gui/skill.h index b8794e35..f1a14d50 100644 --- a/src/gui/skill.h +++ b/src/gui/skill.h @@ -71,7 +71,6 @@ class SkillDialog : public Window, public gcn::ActionListener, private: gcn::ListBox *mSkillListBox; - gcn::Button *mCloseButton; std::vector mSkillList; }; diff --git a/src/gui/status.cpp b/src/gui/status.cpp index 7da3b905..323a6b16 100644 --- a/src/gui/status.cpp +++ b/src/gui/status.cpp @@ -39,6 +39,7 @@ StatusWindow::StatusWindow(LocalPlayer *player): mPlayer(player) { setResizable(true); + setCloseButton(true); setDefaultSize((windowContainer->getWidth() - 365) / 2, (windowContainer->getHeight() - 255) / 2, 365, 280); loadWindowState("Status"); @@ -219,7 +220,7 @@ void StatusWindow::update() mHpBar->setColor(0, 171, 34); // Green } - mHpBar->setProgress((float)hp / maxHp); + mHpBar->setProgress((float) hp / maxHp); // Stats Part // ---------- @@ -235,7 +236,8 @@ void StatusWindow::update() int statusPoints = mPlayer->getAttributeIncreasePoints(); // Update labels - for (int i = 0; i < 7; i++) { + for (int i = 0; i < 7; i++) + { mStatsLabel[i]->setCaption(attrNames[i]); mStatsDisplayLabel[i]->setCaption( strprintf("%d / %d", diff --git a/src/gui/status.h b/src/gui/status.h index 40d25a2a..62cd8805 100644 --- a/src/gui/status.h +++ b/src/gui/status.h @@ -41,7 +41,8 @@ class ProgressBar; * * \ingroup Interface */ -class StatusWindow : public Window, public gcn::ActionListener { +class StatusWindow : public Window, public gcn::ActionListener +{ public: /** * Constructor. diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index ed75e5b3..5d81bb9c 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -46,6 +46,8 @@ #include "../resources/resourcemanager.h" +extern std::string homeDir; + /** * Calculates the Alder-32 checksum for the given file. */ @@ -119,7 +121,7 @@ UpdaterWindow::UpdaterWindow(): mUpdateHost = config.getValue("updatehost", "http://updates.themanaworld.org"); - mBasePath = config.getValue("homeDir", "."); + mBasePath = homeDir; // Try to download the updates list download(); diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index 2af1d960..4c6b04a2 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -55,8 +55,7 @@ Viewport::Viewport(): mCameraX(0), mCameraY(0), mShowDebugPath(false), - mPlayerFollowMouse(false), - mPopupActive(false) + mPlayerFollowMouse(false) { setOpaque(false); addMouseListener(this); @@ -372,21 +371,20 @@ Viewport::mousePressed(gcn::MouseEvent &event) if ((being = beingManager->findBeing(tilex, tiley)) && being->getType() != Being::LOCALPLAYER) { - showPopup(event.getX(), event.getY(), being); + mPopupMenu->showPopup(event.getX(), event.getY(), being); return; } else if((floorItem = floorItemManager->findByCoordinates(tilex, tiley))) { - showPopup(event.getX(), event.getY(), floorItem); + mPopupMenu->showPopup(event.getX(), event.getY(), floorItem); return; } } // If a popup is active, just remove it - if (mPopupActive) + if (mPopupMenu->isVisible()) { mPopupMenu->setVisible(false); - mPopupActive = false; return; } @@ -450,21 +448,6 @@ void Viewport::showPopup(int x, int y, Item *item) { mPopupMenu->showPopup(x, y, item); - mPopupActive = true; -} - -void -Viewport::showPopup(int x, int y, FloorItem *floorItem) -{ - mPopupMenu->showPopup(x, y, floorItem); - mPopupActive = true; -} - -void -Viewport::showPopup(int x, int y, Being *being) -{ - mPopupMenu->showPopup(x, y, being); - mPopupActive = true; } void diff --git a/src/gui/viewport.h b/src/gui/viewport.h index 22d0f249..eeb31bae 100644 --- a/src/gui/viewport.h +++ b/src/gui/viewport.h @@ -129,18 +129,6 @@ class Viewport : public WindowContainer, public gcn::MouseListener, getCameraY() { return mCameraY; } private: - /** - * Shows a popup for a floor item. - * TODO Find some way to get rid of FloorItem here - */ - void showPopup(int x, int y, FloorItem *floorItem); - - /** - * Shows a popup for a being. - * TODO Find some way to get rid of Being here - */ - void showPopup(int x, int y, Being *being); - /** * Helper function for loading target cursors */ @@ -187,7 +175,6 @@ class Viewport : public WindowContainer, public gcn::MouseListener, int mWalkTime; PopupMenu *mPopupMenu; /**< Popup menu. */ - bool mPopupActive; }; #endif diff --git a/src/gui/window.cpp b/src/gui/window.cpp index 84f4466c..17447009 100644 --- a/src/gui/window.cpp +++ b/src/gui/window.cpp @@ -26,6 +26,7 @@ #include #include +#include "gui.h" #include "gccontainer.h" #include "windowcontainer.h" @@ -42,7 +43,9 @@ ConfigListener *Window::windowConfigListener = 0; WindowContainer *Window::windowContainer = 0; int Window::instances = 0; +int Window::mouseResize = 0; ImageRect Window::border; +Image *Window::closeImage = NULL; class WindowConfigListener : public ConfigListener { @@ -60,7 +63,7 @@ Window::Window(const std::string& caption, bool modal, Window *parent): mParent(parent), mModal(modal), mResizable(false), - mMouseResize(0), + mCloseButton(false), mSticky(false), mMinWinWidth(100), mMinWinHeight(40), @@ -88,6 +91,8 @@ Window::Window(const std::string& caption, bool modal, Window *parent): border.grid[7] = dBorders->getSubImage(4, 15, 3, 4); border.grid[8] = dBorders->getSubImage(7, 15, 4, 4); dBorders->decRef(); + closeImage = resman->getImage("graphics/gui/close_button.png"); + windowConfigListener = new WindowConfigListener(); // Send GUI alpha changed for initialization windowConfigListener->optionChanged("guialpha"); @@ -110,6 +115,7 @@ Window::Window(const std::string& caption, bool modal, Window *parent): if (mModal) { + gui->setCursorType(Gui::CURSOR_POINTER); requestModalFocus(); } @@ -153,6 +159,7 @@ Window::~Window() delete border.grid[6]; delete border.grid[7]; delete border.grid[8]; + closeImage->decRef(); } delete mChrome; @@ -173,11 +180,19 @@ void Window::draw(gcn::Graphics *graphics) // Draw title if (getTitleBarHeight()) { - graphics->setColor(gcn::Color(0, 0, 0)); - graphics->setFont(getFont()); - graphics->drawText(getCaption(), 7, 5, gcn::Graphics::LEFT); + g->setColor(gcn::Color(0, 0, 0)); + g->setFont(getFont()); + g->drawText(getCaption(), 7, 5, gcn::Graphics::LEFT); } + // Draw Close Button + if (mCloseButton) + { + g->drawImage(closeImage, + getWidth() - closeImage->getWidth() - getPadding(), + getPadding() + ); + } drawChildren(graphics); } @@ -207,6 +222,8 @@ void Window::setWidth(int width) { mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x); } + + fireWindowEvent(WindowEvent(this, WindowEvent::WINDOW_RESIZED)); } void Window::setHeight(int height) @@ -217,6 +234,8 @@ void Window::setHeight(int height) { mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y); } + + fireWindowEvent(WindowEvent(this, WindowEvent::WINDOW_RESIZED)); } void Window::setDimension(const gcn::Rectangle &dimension) @@ -228,6 +247,27 @@ void Window::setDimension(const gcn::Rectangle &dimension) mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x); mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y); } + + fireWindowEvent(WindowEvent(this, WindowEvent::WINDOW_RESIZED)); + fireWindowEvent(WindowEvent(this, WindowEvent::WINDOW_MOVED)); +} + +void Window::setPosition(int x, int y) +{ + gcn::Window::setPosition(x, y); + fireWindowEvent(WindowEvent(this, WindowEvent::WINDOW_MOVED)); +} + +void Window::setX(int x) +{ + gcn::Window::setX(x); + fireWindowEvent(WindowEvent(this, WindowEvent::WINDOW_MOVED)); +} + +void Window::setY(int y) +{ + gcn::Window::setY(y); + fireWindowEvent(WindowEvent(this, WindowEvent::WINDOW_MOVED)); } void Window::setLocationRelativeTo(gcn::Widget *widget) @@ -280,6 +320,11 @@ void Window::setResizable(bool r) } } +void Window::setCloseButton(bool flag) +{ + mCloseButton = flag; +} + bool Window::isResizable() { return mResizable; @@ -327,27 +372,73 @@ void Window::mousePressed(gcn::MouseEvent &event) // Let Guichan move window to top and figure out title bar drag gcn::Window::mousePressed(event); - const int x = event.getX(); - const int y = event.getY(); - mMouseResize = 0; + if (event.getButton() == gcn::MouseEvent::LEFT) + { + const int x = event.getX(); + const int y = event.getY(); + + // Handle close button + if (mCloseButton) + { + gcn::Rectangle closeButtonRect( + getWidth() - closeImage->getWidth() - getPadding(), + getPadding(), + closeImage->getWidth(), + closeImage->getHeight()); + + if (closeButtonRect.isPointInRect(x, y)) + { + setVisible(false); + } + } + + // Handle window resizing + mouseResize = getResizeHandles(event); + } +} + +void Window::mouseReleased(gcn::MouseEvent &event) +{ + if (mResizable && mouseResize) + { + mouseResize = 0; + gui->setCursorType(Gui::CURSOR_POINTER); + } + + // This should be the responsibility of Guichan (and is from 0.8.0 on) + mIsMoving = false; +} - // Activate resizing handles as appropriate - if (event.getSource() == this && isResizable() && - event.getButton() == gcn::MouseEvent::LEFT && - !getChildrenArea().isPointInRect(x, y)) +void Window::mouseExited(gcn::MouseEvent &event) +{ + if (mResizable && !mouseResize) { - mMouseResize |= (x > getWidth() - resizeBorderWidth) ? RIGHT : - (x < resizeBorderWidth) ? LEFT : 0; - mMouseResize |= (y > getHeight() - resizeBorderWidth) ? BOTTOM : - (y < resizeBorderWidth) ? TOP : 0; + gui->setCursorType(Gui::CURSOR_POINTER); } - else if (event.getSource() == mGrip && - event.getButton() == gcn::MouseEvent::LEFT) +} + +void Window::mouseMoved(gcn::MouseEvent &event) +{ + int resizeHandles = getResizeHandles(event); + + // Changes the custom mouse cursor based on it's current position. + switch (resizeHandles) { - mDragOffsetX = x; - mDragOffsetY = y; - mMouseResize |= BOTTOM | RIGHT; - mIsMoving = false; + case BOTTOM | RIGHT: + gui->setCursorType(Gui::CURSOR_RESIZE_DOWN_RIGHT); + break; + case BOTTOM | LEFT: + gui->setCursorType(Gui::CURSOR_RESIZE_DOWN_LEFT); + break; + case BOTTOM: + gui->setCursorType(Gui::CURSOR_RESIZE_DOWN); + break; + case RIGHT: + case LEFT: + gui->setCursorType(Gui::CURSOR_RESIZE_ACROSS); + break; + default: + gui->setCursorType(Gui::CURSOR_POINTER); } } @@ -366,31 +457,31 @@ void Window::mouseDragged(gcn::MouseEvent &event) setPosition(newX, newY); } - if (mMouseResize && !mIsMoving) + if (mouseResize && !mIsMoving) { const int dx = event.getX() - mDragOffsetX; const int dy = event.getY() - mDragOffsetY; gcn::Rectangle newDim = getDimension(); - if (mMouseResize & (TOP | BOTTOM)) + if (mouseResize & (TOP | BOTTOM)) { - int newHeight = newDim.height + ((mMouseResize & TOP) ? -dy : dy); + int newHeight = newDim.height + ((mouseResize & TOP) ? -dy : dy); newDim.height = std::min(mMaxWinHeight, std::max(mMinWinHeight, newHeight)); - if (mMouseResize & TOP) + if (mouseResize & TOP) { newDim.y -= newDim.height - getHeight(); } } - if (mMouseResize & (LEFT | RIGHT)) + if (mouseResize & (LEFT | RIGHT)) { - int newWidth = newDim.width + ((mMouseResize & LEFT) ? -dx : dx); + int newWidth = newDim.width + ((mouseResize & LEFT) ? -dx : dx); newDim.width = std::min(mMaxWinWidth, std::max(mMinWinWidth, newWidth)); - if (mMouseResize & LEFT) + if (mouseResize & LEFT) { newDim.x -= newDim.width - getWidth(); } @@ -417,11 +508,11 @@ void Window::mouseDragged(gcn::MouseEvent &event) } // Update mouse offset when dragging bottom or right border - if (mMouseResize & BOTTOM) + if (mouseResize & BOTTOM) { mDragOffsetY += newDim.height - getHeight(); } - if (mMouseResize & RIGHT) + if (mouseResize & RIGHT) { mDragOffsetX += newDim.width - getWidth(); } @@ -469,3 +560,50 @@ void Window::resetToDefaultSize() setContentSize(mDefaultWidth, mDefaultHeight); updateContentSize(); } + +int Window::getResizeHandles(gcn::MouseEvent &event) +{ + int resizeHandles = 0; + const int y = event.getY(); + + if (mResizable && y > (int) mTitleBarHeight) + { + const int x = event.getX(); + + if (!getChildrenArea().isPointInRect(x, y) && + event.getSource() == this) + { + resizeHandles |= (x > getWidth() - resizeBorderWidth) ? RIGHT : + (x < resizeBorderWidth) ? LEFT : 0; + resizeHandles |= (y > getHeight() - resizeBorderWidth) ? BOTTOM : + (y < resizeBorderWidth) ? TOP : 0; + } + + if (event.getSource() == mGrip) + { + mDragOffsetX = x; + mDragOffsetY = y; + resizeHandles |= BOTTOM | RIGHT; + } + } + + return resizeHandles; +} + +void Window::fireWindowEvent(const WindowEvent &event) +{ + WindowListeners::iterator i_end = mListeners.end(); + WindowListeners::iterator i = mListeners.begin(); + + switch (event.getType()) + { + case WindowEvent::WINDOW_MOVED: + for (; i != i_end; ++i) + { (*i)->windowMoved(event); } + break; + case WindowEvent::WINDOW_RESIZED: + for (; i != i_end; ++i) + { (*i)->windowResized(event); } + break; + } +} diff --git a/src/gui/window.h b/src/gui/window.h index 1ba23fb2..ab266422 100644 --- a/src/gui/window.h +++ b/src/gui/window.h @@ -28,11 +28,14 @@ #include "../guichanfwd.h" +#include "windowlistener.h" + class ConfigListener; class GCContainer; class ImageRect; class ResizeGrip; class WindowContainer; +class Image; /** * A window. This window can be dragged around and has a title bar. Windows are @@ -119,16 +122,36 @@ class Window : public gcn::Window */ void setDimension(const gcn::Rectangle &dimension); + /** + * Sets the position of this window. + */ + void setPosition(int x, int y); + + /** + * Sets the window x coordinate. + */ + void setX(int x); + + /** + * Sets the window y coordinate. + */ + void setY(int y); + /** * Sets the location relative to the given widget. */ void setLocationRelativeTo(gcn::Widget *widget); /** - * Sets whether of not the window can be resized. + * Sets whether or not the window can be resized. */ void setResizable(bool resize); + /** + * Sets whether or not the window has a close button. + */ + void setCloseButton(bool flag); + /** * Returns whether the window can be resized. */ @@ -155,9 +178,14 @@ class Window : public gcn::Window void setMaxHeight(unsigned int height); /** - * Sets whether the window is sticky. - * A sticky window will not have its visibility set to false - * on a general setVisible(false) call. + * Sets flag to show a title or not. + */ + void setShowTitle(bool flag) + { mShowTitle = flag; } + + /** + * Sets whether the window is sticky. A sticky window will not have + * its visibility set to false on a general setVisible(false) call. */ void setSticky(bool sticky); @@ -167,10 +195,9 @@ class Window : public gcn::Window bool isSticky(); /** - * Overloads window setVisible by guichan to allow sticky window - * Handling + * Overloads window setVisible by Guichan to allow sticky window + * handling. */ - void setVisible(bool visible); /** @@ -198,6 +225,24 @@ class Window : public gcn::Window */ void mouseDragged(gcn::MouseEvent &event); + /** + * Implements custom cursor image changing context, based on mouse + * relative position. + */ + void mouseMoved(gcn::MouseEvent &event); + + /** + * When the mouse button has been let go, this ensures that the mouse + * custom cursor is restored back to it's standard image. + */ + void mouseReleased(gcn::MouseEvent &event); + + /** + * When the mouse leaves the window this ensures that the custom cursor + * is restored back to it's standard image. + */ + void mouseExited(gcn::MouseEvent &event); + /** * Read the x, y, and width and height for resizables in the config * based on the given string. @@ -216,11 +261,25 @@ class Window : public gcn::Window int defaultWidth, int defaultHeight); /** - * Reset the win pos and size to default. - * Don't forget to set defaults first. + * Reset the win pos and size to default. Don't forget to set defaults + * first. */ void resetToDefaultSize(); + /** + * Adds a listener to the list that's notified when the window is + * moved or resized. + */ + void addWindowListener(WindowListener *listener) + { mListeners.push_back(listener); } + + /** + * Removes a listener from the list that's notified when the window is + * moved or resized. + */ + void removeWindowListener(WindowListener *listener) + { mListeners.remove(listener); } + enum ResizeHandles { TOP = 0x01, @@ -233,13 +292,23 @@ class Window : public gcn::Window static WindowContainer *windowContainer; private: + /** + * Determines if the mouse is in a resize area and returns appropriate + * resize handles. Also initializes drag offset in case the resize + * grip is used. + * + * @see ResizeHandles + */ + int getResizeHandles(gcn::MouseEvent &event); + GCContainer *mChrome; /**< Contained container */ ResizeGrip *mGrip; /**< Resize grip */ Window *mParent; /**< The parent window */ std::string mConfigName; /**< Name used for saving window-related data */ + bool mShowTitle; /**< Window has a title bar */ bool mModal; /**< Window is modal */ bool mResizable; /**< Window can be resized */ - int mMouseResize; /**< Window is being resized */ + bool mCloseButton; /**< Window has a close button */ bool mSticky; /**< Window resists minimization */ int mMinWinWidth; /**< Minimum window width */ int mMinWinHeight; /**< Minimum window height */ @@ -255,8 +324,10 @@ class Window : public gcn::Window */ static ConfigListener *windowConfigListener; + static int mouseResize; /**< Active resize handles */ static int instances; /**< Number of Window instances */ static ImageRect border; /**< The window border and background */ + static Image *closeImage; /**< Close Button Image */ /** * The width of the resize border. Is independent of the actual window @@ -264,6 +335,14 @@ class Window : public gcn::Window * where two borders are moved at the same time. */ static const int resizeBorderWidth = 10; + + private: + /** + * Sends out a window event to the list of selection listeners. + */ + void fireWindowEvent(const WindowEvent &event); + + WindowListeners mListeners; }; #endif diff --git a/src/gui/windowlistener.h b/src/gui/windowlistener.h new file mode 100644 index 00000000..08aab71d --- /dev/null +++ b/src/gui/windowlistener.h @@ -0,0 +1,86 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_WINDOW_LISTENER_H_ +#define _TMW_WINDOW_LISTENER_H_ + +#include +#include + +/** + * An event that characterizes a window move or resize. + * + * \ingroup GUI + */ +class WindowEvent : public gcn::Event +{ + public: + /** + * Constructor. + */ + WindowEvent(gcn::Window *source, int type): + gcn::Event(source) + { + mType = type; + } + + /** + * Returns the event type. + */ + int getType() const + { return mType; } + + enum WindowEventType + { + WINDOW_MOVED, + WINDOW_RESIZED + }; +}; + +/** + * The listener that's notified when a window is moved or resized. + * + * \ingroup GUI + */ +class WindowListener +{ + public: + /** + * Virtual destructor. + */ + virtual ~WindowListener() {} + + /** + * Called whenever the window is moved. + */ + virtual void windowMoved(const WindowEvent &event) {} + + /** + * Called whenever the window is resized. + */ + virtual void windowResized(const WindowEvent &event) {} +}; + +typedef std::list WindowListeners; + +#endif diff --git a/src/imageparticle.cpp b/src/imageparticle.cpp index 35cc21ad..17581a2a 100644 --- a/src/imageparticle.cpp +++ b/src/imageparticle.cpp @@ -31,12 +31,12 @@ ImageParticle::ImageParticle(Map *map, Image *image): Particle(map), mImage(image) { - mImage->incRef(); + if (mImage) mImage->incRef(); } ImageParticle::~ImageParticle() { - mImage->decRef(); + if (mImage) mImage->decRef(); } void ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const @@ -44,8 +44,8 @@ void ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const if (!mAlive) return; - int screenX = (int) mPosX + offsetX - mImage->getWidth() / 2; - int screenY = (int) mPosY - (int) mPosZ + offsetY - mImage->getHeight()/2; + int screenX = (int) mPos.x + offsetX - mImage->getWidth() / 2; + int screenY = (int) mPos.y - (int)mPos.z + offsetY - mImage->getHeight()/2; // Check if on screen if (screenX + mImage->getWidth() < 0 || diff --git a/src/itemshortcut.cpp b/src/itemshortcut.cpp new file mode 100644 index 00000000..8a514c7e --- /dev/null +++ b/src/itemshortcut.cpp @@ -0,0 +1,87 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "itemshortcut.h" + +#include "localplayer.h" +#include "configuration.h" + +#include "utils/tostring.h" + +ItemShortcut::ItemShortcut *itemShortcut; + +ItemShortcut::ItemShortcut(): + mItemSelected(NULL) +{ + for (int i = 0; i < SHORTCUT_ITEMS; i++) + { + mItems[i] = NULL; + } +} + +ItemShortcut::~ItemShortcut() +{ + save(); +} + +void ItemShortcut::load() +{ + for (int i = 0; i < SHORTCUT_ITEMS; i++) + { + int itemId = (int) config.getValue("itemShortcut" + toString(i), -1); + + if (itemId != -1) + { + ItemPtr item = player_node->searchForItem(itemId); + if (item) + { + mItems[i] = item; + } + } + } +} + +void ItemShortcut::save() +{ + for (int i = 0; i < SHORTCUT_ITEMS; i++) + { + if (mItems[i]) + { + config.setValue("shortcut" + toString(i), mItems[i]->getId()); + } + else + { + config.setValue("shortcut" + toString(i), -1); + } + } +} + +void ItemShortcut::useItem(int index) +{ + if (mItems[index]) + { + if (mItems[index]->getQuantity()) { + // TODO: Fix this (index vs. pointer mismatch) + //player_node->useItem(mItems[index]); + } + } +} diff --git a/src/itemshortcut.h b/src/itemshortcut.h new file mode 100644 index 00000000..d211c7f3 --- /dev/null +++ b/src/itemshortcut.h @@ -0,0 +1,130 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _TMW_ITEMSHORTCUT_H__ +#define _TMW_ITEMSHORTCUT_H__ + +#include "item.h" + +#define SHORTCUT_ITEMS 10 + +/** + * The item pointer + */ +typedef Item* ItemPtr; + +class ItemShortcut +{ + public: + /** + * Constructor. + */ + ItemShortcut(); + + /** + * Destructor. + */ + ~ItemShortcut(); + + /** + * Load the configuration information. + */ + void load(); + + /** + * Returns the shortcut item specified by the index. + * + * @param index Index of the shortcut item. + */ + ItemPtr getItem(int index) const + { return mItems[index]; } + + /** + * Returns the amount of shortcut items. + */ + int getItemCount() const + { return SHORTCUT_ITEMS; } + + /** + * Returns the item that is currently selected. + */ + ItemPtr getItemSelected() const + { return mItemSelected; } + + /** + * Adds the selected item to the items specified by the index. + * + * @param index Index of the items. + */ + void setItem(int index) + { mItems[index] = mItemSelected; } + + /** + * Adds an item to the items store specified by the index. + * + * @param index Index of the items. + * @param item Item to store. + */ + void setItems(int index, Item *item) + { mItems[index] = item; } + + /** + * Set the item that is selected. + * + * @param item The item that is to be assigned. + */ + void setItemSelected(ItemPtr item) + { mItemSelected = item; } + + /** + * A flag to check if the item is selected. + */ + bool isItemSelected() + { return (mItemSelected) ? true : false; } + + /** + * Remove a item from the shortcut. + */ + void removeItem(int index) + { mItems[index] = NULL; } + + /** + * Try to use the item specified by the index. + * + * @param index Index of the item shortcut. + */ + void useItem(int index); + + private: + /** + * Save the configuration information. + */ + void save(); + + ItemPtr mItems[SHORTCUT_ITEMS]; /**< the items stored */ + ItemPtr mItemSelected; /**< the item held by cursor */ + +}; + +extern ItemShortcut *itemShortcut; + +#endif diff --git a/src/keyboardconfig.cpp b/src/keyboardconfig.cpp new file mode 100644 index 00000000..271961c8 --- /dev/null +++ b/src/keyboardconfig.cpp @@ -0,0 +1,144 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "keyboardconfig.h" +#include "configuration.h" +#include "log.h" + +#include + +#include "gui/setup_keyboard.h" + +struct KeyData +{ + const char *configField; + int defaultValue; + const char *caption; +}; + +// keyData must be in same order as enum keyAction. +static KeyData const keyData[KeyboardConfig::KEY_TOTAL] = { + {"keyMoveUp", SDLK_UP, "Move Up"}, + {"keyMoveDown", SDLK_DOWN, "Move Down"}, + {"keyMoveLeft", SDLK_LEFT, "Move Left"}, + {"keyMoveRight", SDLK_RIGHT, "Move Right"}, + {"keyAttack", SDLK_LCTRL, "Attack"}, + {"keyTarget", SDLK_LSHIFT, "Target"}, + {"keyTargetClosest", SDLK_a, "Target Closest"}, + {"keyPickup", SDLK_z, "Pickup"}, + {"keyHideWindows", SDLK_h, "Hide Windows"}, + {"keyBeingSit", SDLK_s, "Sit"}, + {"keyShortcut0", SDLK_0, "Item Shortcut 0"}, + {"keyShortcut1", SDLK_1, "Item Shortcut 1"}, + {"keyShortcut2", SDLK_2, "Item Shortcut 2"}, + {"keyShortcut3", SDLK_3, "Item Shortcut 3"}, + {"keyShortcut4", SDLK_4, "Item Shortcut 4"}, + {"keyShortcut5", SDLK_5, "Item Shortcut 5"}, + {"keyShortcut6", SDLK_6, "Item Shortcut 6"}, + {"keyShortcut7", SDLK_7, "Item Shortcut 7"}, + {"keyShortcut8", SDLK_8, "Item Shortcut 8"}, + {"keyShortcut9", SDLK_9, "Item Shortcut 9"} +}; + +void KeyboardConfig::init() +{ + for (int i = 0; i < KEY_TOTAL; i++) + { + mKey[i].configField = keyData[i].configField; + mKey[i].defaultValue = keyData[i].defaultValue; + mKey[i].caption = keyData[i].caption; + mKey[i].value = KEY_NO_VALUE; + } + mNewKeyIndex = KEY_NO_VALUE; + mEnabled = true; + + retrieve(); +} + +void KeyboardConfig::retrieve() +{ + for (int i = 0; i < KEY_TOTAL; i++) + { + mKey[i].value = (int) config.getValue( + mKey[i].configField, mKey[i].defaultValue); + } +} + +void KeyboardConfig::store() +{ + for (int i = 0; i < KEY_TOTAL; i++) + { + config.setValue(mKey[i].configField, mKey[i].value); + } +} + +void KeyboardConfig::makeDefault() +{ + for (int i = 0; i < KEY_TOTAL; i++) + { + mKey[i].value = mKey[i].defaultValue; + } +} + +bool KeyboardConfig::hasConflicts() +{ + int i, j; + for (i = 0; i < KEY_TOTAL; i++) + { + for (j = 0; j < KEY_TOTAL; j++) + { + if (i != j && mKey[i].value == mKey[j].value) + { + return true; + } + } + } + return false; +} + +void KeyboardConfig::callbackNewKey() +{ + mSetupKey->newKeyCallback(mNewKeyIndex); +} + +int KeyboardConfig::getKeyIndex(int keyValue) const +{ + for (int i = 0; i < KEY_TOTAL; i++) + { + if(keyValue == mKey[i].value) + { + return i; + } + } + return KEY_NO_VALUE; +} + +bool KeyboardConfig::isKeyActive(int index) +{ + return mActiveKeys[ mKey[index].value]; +} + +void KeyboardConfig::refreshActiveKeys() +{ + mActiveKeys = SDL_GetKeyState(NULL); +} diff --git a/src/keyboardconfig.h b/src/keyboardconfig.h new file mode 100644 index 00000000..46394fa5 --- /dev/null +++ b/src/keyboardconfig.h @@ -0,0 +1,185 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_KEYBOARDCONFIG_H +#define _TMW_KEYBOARDCONFIG_H + +#include + +#include "gui/setup_keyboard.h" + +#include + +/** + * Each key represents a key function. Such as 'Move up', 'Attack' etc. + */ +struct KeyFunction +{ + const char* configField; /** Field index that is in the config file. */ + int defaultValue; /** The default key value used. */ + std::string caption; /** The caption value for the key function. */ + int value; /** The actual value that is used. */ +}; + +class KeyboardConfig +{ + public: + /** + * Initializes the keyboard config explicitly. + */ + void init(); + + /** + * Retrieve the key values from config file. + */ + void retrieve(); + + /** + * Store the key values to config file. + */ + void store(); + + /** + * Make the keys their default values. + */ + void makeDefault(); + + /** + * Determines if any key assignments are the same as each other. + */ + bool hasConflicts(); + + /** + * Calls a function back so the key re-assignment(s) can be seen. + */ + void callbackNewKey(); + + /** + * Obtain the value stored in memory. + */ + int getKeyValue(int index) const + { return mKey[index].value; } + + /** + * Get the index of the new key to be assigned. + */ + int getNewKeyIndex() const + { return mNewKeyIndex; } + + /** + * Get the enable flag, which will stop the user from doing actions. + */ + bool isEnabled() const + { return mEnabled; } + + /** + * Get the key caption, providing more meaning to the user. + */ + const std::string &getKeyCaption(int index) const + { return mKey[index].caption; } + + /** + * Get the key function index by providing the keys value. + */ + int getKeyIndex(int keyValue) const; + + /** + * Set the enable flag, which will stop the user from doing actions. + */ + void setEnabled(bool flag) + { mEnabled = flag; } + + /** + * Set the index of the new key to be assigned. + */ + void setNewKeyIndex(int value) + { mNewKeyIndex = value; } + + /** + * Set the value of the new key. + */ + void setNewKey(int value) + { mKey[mNewKeyIndex].value = value; } + + /** + * Set a reference to the key setup window. + */ + void setSetupKeyboard(Setup_Keyboard *setupKey) + { mSetupKey = setupKey; } + + /** + * Checks if the key is active, by providing the key function index. + */ + bool isKeyActive(int index); + + /** + * Takes a snapshot of all the active keys. + */ + void refreshActiveKeys(); + + /** + * All the key functions. + * KEY_NO_VALUE is used in initialization, and should be unchanged. + * KEY_TOTAL should always be last (used as a conditional in loops). + * The key assignment view gets arranged according to the order of + * these values. + */ + enum KeyAction { + KEY_NO_VALUE = -1, + KEY_MOVE_UP, + KEY_MOVE_DOWN, + KEY_MOVE_LEFT, + KEY_MOVE_RIGHT, + KEY_ATTACK, + KEY_TARGET, + KEY_TARGET_CLOSEST, + KEY_PICKUP, + KEY_HIDE_WINDOWS, + KEY_SIT, + KEY_SHORTCUT_0, + KEY_SHORTCUT_1, + KEY_SHORTCUT_2, + KEY_SHORTCUT_3, + KEY_SHORTCUT_4, + KEY_SHORTCUT_5, + KEY_SHORTCUT_6, + KEY_SHORTCUT_7, + KEY_SHORTCUT_8, + KEY_SHORTCUT_9, + KEY_TOTAL + }; + + private: + int mNewKeyIndex; /**< Index of new key to be assigned */ + bool mEnabled; /**< Flag to respond to key input */ + + Setup_Keyboard *mSetupKey; /**< Reference to setup window */ + + KeyFunction mKey[KEY_TOTAL]; /**< Pointer to all the key data */ + + Uint8 *mActiveKeys; /**< Stores a list of all the keys */ +}; + +extern KeyboardConfig keyboard; + +#endif diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 95e7a478..f4ad7587 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -29,11 +29,19 @@ #include "inventory.h" #include "item.h" #include "main.h" +#include "particle.h" #include "sound.h" #include "log.h" #include "net/gameserver/player.h" +#include "gui/gui.h" + +#include "net/messageout.h" +#include "net/protocol.h" + +#include "utils/tostring.h" + LocalPlayer *player_node = NULL; LocalPlayer::LocalPlayer(): @@ -46,6 +54,7 @@ LocalPlayer::LocalPlayer(): mLevel(1), mMoney(0), mTotalWeight(1), mMaxWeight(1), mHP(1), mMaxHP(1), + mXp(0), mTarget(NULL), mPickUpTarget(NULL), mTrading(false), mLastAction(-1), mWalkingDir(0), @@ -112,6 +121,17 @@ LocalPlayer::moveInvItem(Item *item, int newIndex) item->getInvIndex(), newIndex, item->getQuantity()); } +Item* LocalPlayer::searchForItem(int itemId) +{ + for (int i = 0; i < INVENTORY_SIZE; i++) + { + if (itemId == mInventory->getItem(i)->getId()) { + return mInventory->getItem(i); + } + } + return NULL; +} + void LocalPlayer::equipItem(Item *item) { Net::GameServer::Player::equip(item->getInvIndex()); @@ -302,10 +322,14 @@ void LocalPlayer::attack() setAction(ATTACK); - if (getWeapon() == 2) - sound.playSfx("sfx/bow_shoot_1.ogg"); - else + if (mEquippedWeapon) + { + std::string soundFile = mEquippedWeapon->getSound(EQUIP_EVENT_STRIKE); + if (soundFile != "") sound.playSfx(soundFile); + } + else { sound.playSfx("sfx/fist-swish.ogg"); + } Net::GameServer::Player::attack(getSpriteDirection()); } @@ -329,3 +353,16 @@ void LocalPlayer::raiseAttribute(size_t attr) mAttributeBase.at(attr)++; // TODO: Inform the server about our desire to raise the attribute } + +void LocalPlayer::setXp(int xp) +{ + if (mMap && xp > mXp) + { + const std::string text = toString(xp - mXp) + " xp"; + + // Show XP number + particleEngine->addTextRiseFadeOutEffect(text, hitYellowFont, + mPx + 16, mPy - 16); + } + mXp = xp; +} diff --git a/src/localplayer.h b/src/localplayer.h index 4f38fdad..ff7bf0b7 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -151,6 +151,14 @@ class LocalPlayer : public Player */ void moveInvItem(Item *item, int newIndex); + /** + * Searches for the specified item by it's identification. + * + * @param itemId The id of the item to be searched. + * @return Item found on success, NULL on failure. + */ + Item* searchForItem(int itemId); + /** * Equips an item. */ @@ -237,6 +245,19 @@ class LocalPlayer : public Player int getHP() const { return mHP; } + /** + * Sets the amount of XP. Shows XP gaining effect if the player is on + * a map. + */ + void setXp(int xp); + + /** + * Returns the amount of experience points. + */ + int getXp() const { return mXp; } + + Uint32 mCharId; + int getMaxHP() const { return mMaxHP; } @@ -298,6 +319,7 @@ class LocalPlayer : public Player int mMaxWeight; int mHP; int mMaxHP; + int mXp; /**< Experience points. */ Being *mTarget; FloorItem *mPickUpTarget; diff --git a/src/main.cpp b/src/main.cpp index 1f4eafde..30fb7c1c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,8 +48,10 @@ #endif #include "configuration.h" +#include "keyboardconfig.h" #include "game.h" #include "graphics.h" +#include "itemshortcut.h" #include "lockedarray.h" #include "localplayer.h" #include "log.h" @@ -84,7 +86,6 @@ #include "net/gameserver/gameserver.h" -#include "resources/equipmentdb.h" #include "resources/image.h" #include "resources/itemdb.h" #include "resources/monsterdb.h" @@ -108,6 +109,7 @@ Music *bgm; Configuration config; /**< XML file configuration reader */ Logger *logger; /**< Log object */ +KeyboardConfig keyboard; Net::Connection *accountServerConnection = 0; Net::Connection *gameServerConnection = 0; @@ -189,7 +191,6 @@ void initConfiguration(const Options &options) config.setValue("fpslimit", 0); config.setValue("updatehost", "http://updates.themanaworld.org"); config.setValue("customcursor", 1); - config.setValue("homeDir", homeDir); // Checking if the configuration file exists... otherwise create it with // default options. @@ -319,6 +320,9 @@ void initEngine() // Initialize for drawing graphics->_beginDraw(); + // Initialize the item shortcuts. + itemShortcut = new ItemShortcut(); + gui = new Gui(graphics); state = STATE_CHOOSE_SERVER; /**< Initial game state */ @@ -337,12 +341,19 @@ void initEngine() errorMessage = err; logger->log("Warning: %s", err); } + + // Initialize keyboard + keyboard.init(); } /** Clear the engine */ void exit_engine() { + // Before config.write() since it writes the shortcuts to the config + delete itemShortcut; + config.write(); + delete gui; delete graphics; @@ -353,7 +364,6 @@ void exit_engine() sound.close(); // Unload XML databases - EquipmentDB::unload(); ItemDB::unload(); MonsterDB::unload(); @@ -457,7 +467,6 @@ void loadUpdates() const std::string updatesFile = "updates/resources2.txt"; ResourceManager *resman = ResourceManager::getInstance(); std::vector lines = resman->loadTextFile(updatesFile); - std::string homeDir = config.getValue("homeDir", ""); for (unsigned int i = 0; i < lines.size(); ++i) { @@ -895,7 +904,6 @@ int main(int argc, char *argv[]) false); // Load XML databases - EquipmentDB::load(); ItemDB::load(); MonsterDB::load(); state = STATE_LOGIN; @@ -1039,7 +1047,6 @@ int main(int argc, char *argv[]) } } } - } catch (...) { diff --git a/src/monster.cpp b/src/monster.cpp index 768bf16a..2522a3e1 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -57,7 +57,7 @@ Monster::setAction(Action action) break; case DEAD: currentAction = ACTION_DEAD; - sound.playSfx(getInfo().getSound(EVENT_DIE)); + sound.playSfx(getInfo().getSound(MONSTER_EVENT_DIE)); break; case ATTACK: currentAction = ACTION_ATTACK; @@ -87,10 +87,10 @@ Monster::handleAttack() const MonsterInfo &mi = getInfo(); - // TODO: It's not possible to determine hit or miss here, so this stuff probably needs - // to be moved somewhere else. We may lose synchronization between attack animation and - // the sound, unless we adapt the protocol... - sound.playSfx(mi.getSound(EVENT_HIT)); + // TODO: It's not possible to determine hit or miss here, so this stuff + // probably needs to be moved somewhere else. We may lose synchronization + // between attack animation and the sound, unless we adapt the protocol... + sound.playSfx(mi.getSound(MONSTER_EVENT_HIT)); } Being::TargetCursorSize diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 87972212..b88d443e 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -114,7 +114,7 @@ void BeingHandler::handleMessage(MessageIn &msg) dstBeing = beingManager->findBeing(id); - if (dstBeing == NULL) + if (!dstBeing) { // Being with id >= 110000000 and job 0 are better // known as ghosts, so don't create those. @@ -138,30 +138,32 @@ void BeingHandler::handleMessage(MessageIn &msg) dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; - dstBeing->setHairStyle(msg.readShort()); - dstBeing->setWeapon(msg.readShort()); + dstBeing->setHairStyle(msg->readShort()); + dstBeing->setVisibleEquipment( + Being::WEAPON_SPRITE, msg->readShort()); dstBeing->setVisibleEquipment( - Being::BOTTOMCLOTHES_SPRITE, msg.readShort()); + Being::BOTTOMCLOTHES_SPRITE, msg->readShort()); if (msg.getId() == SMSG_BEING_MOVE) { msg.readLong(); // server tick } - msg.readShort(); // shield - dstBeing->setVisibleEquipment(Being::HAIT_SPRITE, msg.readShort()); - dstBeing->setVisibleEquipment( - Being::TOPCLOTHES_SPRITE, msg.readShort()); - dstBeing->setHairColor(msg.readShort()); - msg.readShort(); // unknown - msg.readShort(); // head dir - msg.readShort(); // guild - msg.readShort(); // unknown - msg.readShort(); // unknown - msg.readShort(); // manner - msg.readShort(); // karma - msg.readByte(); // unknown - dstBeing->setSex(1 - msg.readByte()); // sex + msg->readShort(); // shield + headTop = msg->readShort(); + headMid = msg->readShort(); + dstBeing->setVisibleEquipment(Being::HAT_SPRITE, headTop); + dstBeing->setVisibleEquipment(Being::TOPCLOTHES_SPRITE, headMid); + dstBeing->setHairColor(msg->readShort()); + msg->readShort(); // unknown + msg->readShort(); // head dir + msg->readShort(); // guild + msg->readShort(); // unknown + msg->readShort(); // unknown + msg->readShort(); // manner + msg->readShort(); // karma + msg->readByte(); // unknown + dstBeing->setSex(1 - msg->readByte()); // sex if (msg.getId() == SMSG_BEING_MOVE) { @@ -256,10 +258,12 @@ void BeingHandler::handleMessage(MessageIn &msg) } Particle *levelupFX; if (msg->readLong() == 0) { // type - levelupFX = particleEngine->addEffect("graphics/particles/levelup.particle.xml", 0, 0); + levelupFX = particleEngine->addEffect( + "graphics/particles/levelup.particle.xml", 0, 0); } else { - levelupFX = particleEngine->addEffect("graphics/particles/skillup.particle.xml", 0, 0); + levelupFX = particleEngine->addEffect( + "graphics/particles/skillup.particle.xml", 0, 0); } beingManager->findBeing(id)->controlParticle(levelupFX); break; @@ -289,28 +293,26 @@ void BeingHandler::handleMessage(MessageIn &msg) dstBeing->setHairStyle(id); break; case 2: - dstBeing->setWeapon(id); + dstBeing->setVisibleEquipment(Being::WEAPON_SPRITE, id); break; case 3: // Change lower headgear for eAthena, pants for us dstBeing->setVisibleEquipment( - Being::BOTTOMCLOTHES_SPRITE, - id); + Being::BOTTOMCLOTHES_SPRITE, id); break; case 4: // Change upper headgear for eAthena, hat for us dstBeing->setVisibleEquipment( - Being::HAT_SPRITE, - id); + Being::HAT_SPRITE, id); break; case 5: // Change middle headgear for eathena, armor for us dstBeing->setVisibleEquipment( - Being::TOPCLOTHES_SPRITE, - id); + Being::TOPCLOTHES_SPRITE, id); break; case 6: dstBeing->setHairColor(id); break; default: - logger->log("c3: %i\n", id); // unsupported + logger->log("SMSG_BEING_CHANGE_LOOKS: unsupported type: " + "%d, id: %d", type, id); break; } } @@ -336,17 +338,18 @@ void BeingHandler::handleMessage(MessageIn &msg) dstBeing = beingManager->findBeing(id); - if (dstBeing == NULL) + if (!dstBeing) { dstBeing = beingManager->createBeing(id, job); } dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; - dstBeing->setHairStyle(msg.readShort()); - dstBeing->setWeaponById(msg.readShort()); // item id 1 - msg.readShort(); // item id 2 - headBottom = msg.readShort(); + dstBeing->setHairStyle(msg->readShort()); + dstBeing->setVisibleEquipment( + Being::WEAPON_SPRITE, msg->readShort()); + msg->readShort(); // item id 2 + headBottom = msg->readShort(); if (msg.getId() == SMSG_PLAYER_MOVE) { @@ -407,9 +410,9 @@ void BeingHandler::handleMessage(MessageIn &msg) case 0x0119: // Change in players look - logger->log("0x0119 %li %i %i %x %i\n", msg.readLong(), - msg.readShort(), msg.readShort(), msg.readShort(), - msg.readByte()); + logger->log("0x0119 %i %i %i %x %i", msg->readLong(), + msg->readShort(), msg->readShort(), msg->readShort(), + msg->readByte()); break; */ } @@ -428,11 +431,9 @@ static void handleLooks(Being *being, MessageIn &msg) if (mask & (1 << 7)) { // The equipment has to be cleared first. - being->setWeaponById(0); for (int i = 0; i < nb_slots; ++i) { - if (slots[i] != Being::WEAPON_SPRITE) - being->setVisibleEquipment(slots[i], 0); + being->setVisibleEquipment(slots[i], 0); } } @@ -441,10 +442,7 @@ static void handleLooks(Being *being, MessageIn &msg) { if (!(mask & (1 << i))) continue; int id = msg.readShort(); - if (slots[i] != Being::WEAPON_SPRITE) - being->setVisibleEquipment(slots[i], id); - else - being->setWeaponById(id); + being->setVisibleEquipment(slots[i], id); } } diff --git a/src/net/chathandler.cpp b/src/net/chathandler.cpp index 3efe3174..afdc2ab5 100644 --- a/src/net/chathandler.cpp +++ b/src/net/chathandler.cpp @@ -37,6 +37,7 @@ #include "../gui/chat.h" #include "../utils/tostring.h" +#include "../utils/trim.h" extern Being *player_node; @@ -167,6 +168,7 @@ void ChatHandler::handleMessage(MessageIn &msg) chatMsg = msg.readString(chatMsgLength); chatWindow->chatLog(chatMsg, BY_OTHER); chatMsg.erase(0, chatMsg.find(" : ", 0) + 3); + trim(chatMsg); being->setSpeech(chatMsg, SPEECH_TIME); break; diff --git a/src/net/inventoryhandler.cpp b/src/net/inventoryhandler.cpp index 354dd685..de74e8f5 100644 --- a/src/net/inventoryhandler.cpp +++ b/src/net/inventoryhandler.cpp @@ -31,6 +31,7 @@ #include "../equipment.h" #include "../inventory.h" #include "../item.h" +#include "../itemshortcut.h" #include "../localplayer.h" #include "../gui/chat.h" @@ -77,6 +78,7 @@ void InventoryHandler::handleMessage(MessageIn &msg) it->setQuantity(amount); } }; + itemShortcut->load(); break; } } diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp index b94b5128..afaeca69 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/playerhandler.cpp @@ -133,7 +133,8 @@ void PlayerHandler::handleMessage(MessageIn &msg) } else { - logger->log("Warning: server wants to update unknown attribute %d to %d", stat, value); + logger->log("Warning: server wants to update unknown " + "attribute %d to %d", stat, value); } } } break; diff --git a/src/particle.cpp b/src/particle.cpp index 805da102..148bbf6f 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -52,14 +52,12 @@ const float Particle::PARTICLE_SKY = 800.0f; Particle::Particle(Map *map): mAlive(true), - mPosX(0.0f), mPosY(0.0f), mPosZ(0.0f), mLifetimeLeft(-1), mLifetimePast(0), mFadeOut(0), mFadeIn(0), mAutoDelete(true), mMap(map), - mVectorX(0.0f), mVectorY(0.0f), mVectorZ(0.0f), mGravity(0.0f), mRandomnes(0), mBounce(0.0f), @@ -109,7 +107,7 @@ Particle::update() p++ ) { - (*p)->moveBy(mPosX, mPosY, mPosZ); + (*p)->moveBy(mPos.x, mPos.y, mPos.z); mChildParticles.push_back (*p); } } @@ -117,31 +115,28 @@ Particle::update() if (mMomentum != 1.0f) { - mVectorX *= mMomentum; - mVectorY *= mMomentum; - mVectorZ *= mMomentum; + mVelocity *= mMomentum; } if (mTarget && mAcceleration != 0.0f) { - float distX = (mPosX - mTarget->getPosX()) * SIN45; - float distY = mPosY - mTarget->getPosY(); - float distZ = mPosZ - mTarget->getPosZ(); + Vector dist = mPos - mTarget->getPosition(); + dist.x *= SIN45; float invHypotenuse; - switch(Particle::fastPhysics) + switch (Particle::fastPhysics) { case 1: invHypotenuse = fastInvSqrt( - distX * distX + distY * distY + distZ * distZ); + dist.x * dist.x + dist.y * dist.y + dist.z * dist.z); break; case 2: invHypotenuse = 2.0f / - fabs(distX) + fabs(distY) + fabs(distZ); + fabs(dist.x) + fabs(dist.y) + fabs(dist.z); break; default: invHypotenuse = 1.0f / sqrt( - distX * distX + distY * distY + distZ * distZ); + dist.x * dist.x + dist.y * dist.y + dist.z * dist.z); break; } @@ -152,25 +147,23 @@ Particle::update() mAlive = false; } float accFactor = invHypotenuse * mAcceleration; - mVectorX -= distX * accFactor; - mVectorY -= distY * accFactor; - mVectorZ -= distZ * accFactor; + mVelocity -= dist * accFactor; } } if (mRandomnes > 0) { - mVectorX += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f; - mVectorY += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f; - mVectorZ += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f; + mVelocity.x += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f; + mVelocity.y += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f; + mVelocity.z += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f; } - mVectorZ -= mGravity; + mVelocity.z -= mGravity; // Update position - mPosX += mVectorX; - mPosY += mVectorY * SIN45; - mPosZ += mVectorZ * SIN45; + mPos.x += mVelocity.x; + mPos.y += mVelocity.y * SIN45; + mPos.z += mVelocity.z * SIN45; // Update other stuff if (mLifetimeLeft > 0) @@ -179,14 +172,13 @@ Particle::update() } mLifetimePast++; - if (mPosZ > PARTICLE_SKY || mPosZ < 0.0f) + if (mPos.z > PARTICLE_SKY || mPos.z < 0.0f) { if (mBounce > 0.0f) { - mPosZ *= -mBounce; - mVectorX *= mBounce; - mVectorY *= mBounce; - mVectorZ *= -mBounce; + mPos.z *= -mBounce; + mVelocity *= mBounce; + mVelocity.z = -mVelocity.z; } else { mAlive = false; @@ -195,10 +187,8 @@ Particle::update() } // Update child particles - for ( ParticleIterator p = mChildParticles.begin(); - p != mChildParticles.end(); - - ) + for (ParticleIterator p = mChildParticles.begin(); + p != mChildParticles.end();) { if ((*p)->update()) { @@ -217,14 +207,9 @@ Particle::update() return true; } - -void Particle::draw(Graphics *graphics, int offsetX, int offsetY) const -{ -} - - Particle* -Particle::addEffect(std::string particleEffectFile, int pixelX, int pixelY) +Particle::addEffect(const std::string &particleEffectFile, + int pixelX, int pixelY) { Particle *newParticle = NULL; @@ -289,9 +274,9 @@ Particle::addEffect(std::string particleEffectFile, int pixelX, int pixelY) int offsetY = XML::getProperty(effectChildNode, "position-y", 0); int offsetZ = XML::getProperty(effectChildNode, "position-z", 0); - int particleX = (int)mPosX + pixelX + offsetX; - int particleY = (int)mPosY + pixelY + offsetY; - int particleZ = (int)mPosZ + offsetZ; + int particleX = (int) mPos.x + pixelX + offsetX; + int particleY = (int) mPos.y + pixelY + offsetY; + int particleZ = (int) mPos.z + offsetZ; int lifetime = XML::getProperty(effectChildNode, "lifetime", -1); @@ -317,17 +302,16 @@ Particle::addEffect(std::string particleEffectFile, int pixelX, int pixelY) Particle* -Particle::addTextSplashEffect(std::string text, +Particle::addTextSplashEffect(const std::string &text, int colorR, int colorG, int colorB, gcn::Font *font, int x, int y) { Particle *newParticle = new TextParticle(mMap, text, colorR, colorG, colorB, font); newParticle->setPosition(x, y, 0); - newParticle->setVector ( ((rand()%100) - 50) / 200.0f, // X vector - ((rand()%100) - 50) / 200.0f, // Y vector - ((rand()%100) / 200.0f) + 4.0f // Z vector - ); + newParticle->setVelocity(((rand() % 100) - 50) / 200.0f, // X + ((rand() % 100) - 50) / 200.0f, // Y + ((rand() % 100) / 200.0f) + 4.0f); // Z newParticle->setGravity(0.1f); newParticle->setBounce(0.5f); newParticle->setLifetime(200); @@ -338,14 +322,28 @@ Particle::addTextSplashEffect(std::string text, return newParticle; } +Particle* +Particle::addTextRiseFadeOutEffect(const std::string &text, gcn::Font *font, + int x, int y) +{ + Particle *newParticle = new TextParticle(mMap, text, 255, 255, 255, font); + newParticle->setPosition(x, y, 0); + newParticle->setVelocity(0.0f, 0.0f, 0.5f); + newParticle->setGravity(0.0015f); + newParticle->setLifetime(300); + newParticle->setFadeOut(50); + newParticle->setFadeIn(200); + + mChildParticles.push_back(newParticle); + + return newParticle; +} void Particle::setMap(Map *map) { mMap = map; if (mMap) setSpriteIterator(mMap->addSprite(this)); - - // TODO: Create map emitters based on emitter data in map data } diff --git a/src/particle.h b/src/particle.h index 9e9223c7..dd7c5ee2 100644 --- a/src/particle.h +++ b/src/particle.h @@ -31,7 +31,7 @@ #include "guichanfwd.h" #include "sprite.h" - +#include "vector.h" class Map; class Particle; @@ -67,43 +67,37 @@ class Particle : public Sprite ~Particle(); /** - * Deletes all child particles and emitters + * Deletes all child particles and emitters. */ void clear(); /** * Gives a particle the properties of an engine root particle and loads - * the particle-related config settings + * the particle-related config settings. */ void setupEngine(); /** * Updates particle position, returns false when the particle should - * be deleted + * be deleted. */ virtual bool update(); /** - * Draws the particle image + * Draws the particle image. */ virtual void - draw(Graphics *graphics, int offsetX, int offsetY) const; + draw(Graphics *graphics, int offsetX, int offsetY) const {} /** - * Necessary for sorting with the other sprites + * Necessary for sorting with the other sprites. */ virtual int getPixelY() const - { - return (int)(mPosY + mPosZ) - 64; - }; - - /* - Basic Particle properties: - */ + { return (int) (mPos.y + mPos.z) - 64; } /** * Sets the map the particle is on. @@ -115,15 +109,24 @@ class Particle : public Sprite * particleEffectFile. */ Particle* - addEffect(std::string particleEffectFile, int pixelX, int pixelY); + addEffect(const std::string &particleEffectFile, + int pixelX, int pixelY); /** * Creates a standalone text particle. */ Particle* - addTextSplashEffect(std::string text, int colorR, int colorG, int colorB, + addTextSplashEffect(const std::string &text, + int colorR, int colorG, int colorB, gcn::Font *font, int x, int y); + /** + * Creates a standalone text particle. + */ + Particle* + addTextRiseFadeOutEffect(const std::string &text, gcn::Font *font, + int x, int y); + /** * Adds an emitter to the particle. */ @@ -132,34 +135,31 @@ class Particle : public Sprite { mChildEmitters.push_back(emitter); } /** - * Sets the position in 3 dimensional space in pixels relative to map + * Sets the position in 3 dimensional space in pixels relative to map. */ void setPosition(float x, float y, float z) - { mPosX = x; mPosY = y; mPosZ = z; } + { mPos.x = x; mPos.y = y; mPos.z = z; } /** - * Sets the position in 2 dimensional space in pixels relative to map + * Sets the position in 2 dimensional space in pixels relative to map. */ void setPosition(float x, float y) - { mPosX = x; mPosY = y; } - - float getPosX() const - { return mPosX; } + { mPos.x = x; mPos.y = y; } - float getPosY() const - { return mPosY; } - - float getPosZ() const - { return mPosZ; } + /** + * Returns the particle position. + */ + const Vector& getPosition() const + { return mPos; } /** * Changes the particle position relative */ void moveBy(float x, float y, float z) - { mPosX += x; mPosY += y; mPosZ += z; } + { mPos.x += x; mPos.y += y; mPos.z += z; } /** * Sets the time in game ticks until the particle is destroyed. @@ -170,48 +170,48 @@ class Particle : public Sprite /** * Sets the age of the pixel in game ticks where the particle has - * faded in completely + * faded in completely. */ void - setFadeOut (int fadeOut) + setFadeOut(int fadeOut) { mFadeOut = fadeOut; } /** * Sets the remaining particle lifetime where the particle starts to - * fade out + * fade out. */ void - setFadeIn (int fadeIn) + setFadeIn(int fadeIn) { mFadeIn = fadeIn; } /** * Sets the sprite iterator of the particle on the current map to make - * it easier to remove the particle from the map when it is destroyed + * it easier to remove the particle from the map when it is destroyed. */ void setSpriteIterator(std::list::iterator spriteIterator) { mSpriteIterator = spriteIterator; } /** - * Gets the sprite iterator of the particle on the current map + * Gets the sprite iterator of the particle on the current map. */ std::list::iterator getSpriteIterator() const { return mSpriteIterator; } /** - * Sets the current velocity in 3 dimensional space + * Sets the current velocity in 3 dimensional space. */ void - setVector(float x, float y, float z) - { mVectorX = x; mVectorY = y; mVectorZ = z; } + setVelocity(float x, float y, float z) + { mVelocity.x = x; mVelocity.y = y; mVelocity.z = z; } /** - * Sets the downward acceleration + * Sets the downward acceleration. */ void - setGravity(float g) - { mGravity = g; } + setGravity(float gravity) + { mGravity = gravity; } /** * Sets the ammount of random vector changes @@ -237,8 +237,8 @@ class Particle : public Sprite /** * Sets the distance in pixel the particle can come near the target - * particle before it is destroyed. Does only make sense after a - * target particle has been set using setDestination. + * particle before it is destroyed. Does only make sense after a target + * particle has been set using setDestination. */ void setDieDistance(float dist) { mInvDieDistance = 1.0f / dist; } @@ -247,7 +247,7 @@ class Particle : public Sprite { return mAlive; } /** - * Manually marks the particle for deletion + * Manually marks the particle for deletion. */ void kill() { mAlive = false; mAutoDelete = true; } @@ -261,7 +261,7 @@ class Particle : public Sprite protected: bool mAlive; /**< Is the particle supposed to be drawn and updated?*/ - float mPosX, mPosY, mPosZ; /**< Position in 3 dimensonal space - pixel based relative to map */ + Vector mPos; /**< Position in pixels relative to map. */ int mLifetimeLeft; /**< Lifetime left in game ticks*/ int mLifetimePast; /**< Age of the particle in game ticks*/ int mFadeOut; /**< Lifetime in game ticks left where fading out begins*/ @@ -269,17 +269,19 @@ class Particle : public Sprite private: // generic properties - bool mAutoDelete; /**< May the particle request its deletion by the parent particle?*/ - Map *mMap; /**< Map the particle is on*/ + bool mAutoDelete; /**< May the particle request its deletion by the parent particle? */ + Map *mMap; /**< Map the particle is on. */ std::list::iterator mSpriteIterator; /**< iterator of the particle on the current map */ - Emitters mChildEmitters; /**< List of child emitters*/ - Particles mChildParticles; /**< List of particles controlled by this particle*/ - //dynamic particle - float mVectorX, mVectorY, mVectorZ; /**< Speed in 3 dimensional space in pixels per game-tick */ - float mGravity; /**< Downward acceleration in pixels per game-tick²*/ - int mRandomnes; /**< Ammount of random vector change*/ - float mBounce; /**< How much the particle bounces off when hitting the ground*/ - //follow-point particles + Emitters mChildEmitters; /**< List of child emitters. */ + Particles mChildParticles; /**< List of particles controlled by this particle */ + + // dynamic particle + Vector mVelocity; /**< Speed in pixels per game-tick. */ + float mGravity; /**< Downward acceleration in pixels per game-tick. */ + int mRandomnes; /**< Ammount of random vector change */ + float mBounce; /**< How much the particle bounces off when hitting the ground */ + + // follow-point particles Particle *mTarget; /**< The particle that attracts this particle*/ float mAcceleration; /**< Acceleration towards the target particle in pixels per game-tick²*/ float mInvDieDistance; /**< Distance in pixels from the target particle that causes the destruction of the particle*/ diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp index 60a98cc5..035882b6 100644 --- a/src/particleemitter.cpp +++ b/src/particleemitter.cpp @@ -248,10 +248,9 @@ ParticleEmitter::readMinMax(xmlNodePtr propertyNode, T def) { MinMax retval; - def = (T)XML::getFloatProperty(propertyNode, "value", (double)def); - retval.set ( (T)XML::getFloatProperty(propertyNode, "min", (double)def), - (T)XML::getFloatProperty(propertyNode, "max", (double)def) - ); + def = (T) XML::getFloatProperty(propertyNode, "value", (double) def); + retval.set((T) XML::getFloatProperty(propertyNode, "min", (double) def), + (T) XML::getFloatProperty(propertyNode, "max", (double) def)); return retval; } @@ -284,19 +283,17 @@ ParticleEmitter::createParticles() newParticle->setPosition( - mParticlePosX.value(), - mParticlePosY.value(), - mParticlePosZ.value() - ); + mParticlePosX.value(), + mParticlePosY.value(), + mParticlePosZ.value()); float angleH = mParticleAngleHorizontal.value(); float angleV = mParticleAngleVertical.value(); float power = mParticlePower.value(); - newParticle->setVector( - cos(angleH) * cos(angleV) * power, - sin(angleH) * cos(angleV) * power, - sin(angleV) * power - ); + newParticle->setVelocity( + cos(angleH) * cos(angleV) * power, + sin(angleH) * cos(angleV) * power, + sin(angleV) * power); newParticle->setRandomnes(mParticleRandomnes.value()); newParticle->setGravity(mParticleGravity.value()); @@ -312,10 +309,9 @@ ParticleEmitter::createParticles() newParticle->setFadeOut(mParticleFadeOut.value()); newParticle->setFadeIn(mParticleFadeIn.value()); - for ( std::list::iterator i = mParticleChildEmitters.begin(); - i != mParticleChildEmitters.end(); - i++ - ) + for (std::list::iterator i = mParticleChildEmitters.begin(); + i != mParticleChildEmitters.end(); + i++) { newParticle->addEmitter(new ParticleEmitter(*i)); } diff --git a/src/player.cpp b/src/player.cpp index d3c27aa0..b63dcd5b 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -28,7 +28,8 @@ #include "graphics.h" #include "log.h" -#include "resources/equipmentdb.h" +#include "resources/itemdb.h" +#include "resources/iteminfo.h" #include "utils/tostring.h" @@ -37,7 +38,6 @@ Player::Player(Uint16 id, Uint16 job, Map *map): Being(id, job, map) { - setWeapon(0); } Being::Type @@ -93,8 +93,8 @@ Player::setSex(Uint8 sex) if (i != HAIR_SPRITE && mEquipmentSpriteIDs.at(i) != 0) { AnimatedSprite *newEqSprite = new AnimatedSprite( - "graphics/sprites/" + EquipmentDB::get( - mEquipmentSpriteIDs.at(i))->getSprite(sex)); + "graphics/sprites/" + ItemDB::get( + mEquipmentSpriteIDs.at(i)).getSprite(sex)); delete mSprites[i]; mSprites[i] = newEqSprite; } @@ -102,39 +102,6 @@ Player::setSex(Uint8 sex) } } -void -Player::setWeapon(Uint16 weapon) -{ - if (weapon != mWeapon) - { - AnimatedSprite *newWeaponSprite = NULL; - - switch (weapon) - { - case 0: - newWeaponSprite = - new AnimatedSprite("graphics/sprites/weapon-fist.xml"); - break; - case 1: - newWeaponSprite = - new AnimatedSprite("graphics/sprites/weapon-dagger.xml"); - break; - case 2: - newWeaponSprite = - new AnimatedSprite("graphics/sprites/weapon-bow.xml"); - break; - case 3: - newWeaponSprite = - new AnimatedSprite("graphics/sprites/weapon-scythe.xml"); - break; - } - - delete mSprites[WEAPON_SPRITE]; - mSprites[WEAPON_SPRITE] = newWeaponSprite; - } - Being::setWeapon(weapon); -} - void Player::setHairColor(Uint16 color) { @@ -189,11 +156,11 @@ Player::setVisibleEquipment(Uint8 slot, int id) if (mSex == 0) { equipmentSprite = new AnimatedSprite( - "graphics/sprites/" + EquipmentDB::get(id)->getSprite(0)); + "graphics/sprites/" + ItemDB::get(id).getSprite(0)); } else { equipmentSprite = new AnimatedSprite( - "graphics/sprites/" + EquipmentDB::get(id)->getSprite(1)); + "graphics/sprites/" + ItemDB::get(id).getSprite(1)); } equipmentSprite->setDirection(getSpriteDirection()); @@ -201,6 +168,11 @@ Player::setVisibleEquipment(Uint8 slot, int id) delete mSprites[slot]; mSprites[slot] = equipmentSprite; + if (slot == WEAPON_SPRITE) + { + mEquippedWeapon = &ItemDB::get(id); + } + setAction(mAction); } diff --git a/src/player.h b/src/player.h index 8aa84992..2c06bfba 100644 --- a/src/player.h +++ b/src/player.h @@ -59,9 +59,6 @@ class Player : public Being virtual void setVisibleEquipment(Uint8 slot, int id); - - virtual void - setWeapon(Uint16 weapon); }; #endif diff --git a/src/resources/equipmentdb.cpp b/src/resources/equipmentdb.cpp deleted file mode 100644 index 38ac6415..00000000 --- a/src/resources/equipmentdb.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* - * The Mana World - * Copyright 2006 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id$ - */ - -#include "equipmentdb.h" - -#include "resourcemanager.h" - -#include "../log.h" - -#include "../utils/dtor.h" -#include "../utils/xml.h" - -namespace -{ - EquipmentDB::EquipmentInfos mEquipmentInfos; - EquipmentInfo mUnknown; - bool mLoaded = false; -} - -void -EquipmentDB::load() -{ - if (mLoaded) - return; - - logger->log("Initializing equipment database..."); - mUnknown.setSprite("error.xml", 0); - mUnknown.setSprite("error.xml", 1); - - ResourceManager *resman = ResourceManager::getInstance(); - int size; - char *data = (char*)resman->loadFile("equipment.xml", size); - - if (!data) - { - logger->error("Equipment Database: Could not find equipment.xml!"); - } - - xmlDocPtr doc = xmlParseMemory(data, size); - free(data); - - if (!doc) - { - logger->error("Equipment Database: Error while parsing equipment database (equipment.xml)!"); - } - - xmlNodePtr rootNode = xmlDocGetRootElement(doc); - if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "equipments")) - { - logger->error("Equipment Database: equipment.xml is not a valid database file!"); - } - - //iterate s - for_each_xml_child_node(equipmentNode, rootNode) - { - if (!xmlStrEqual(equipmentNode->name, BAD_CAST "equipment")) - { - continue; - } - - EquipmentInfo *currentInfo = new EquipmentInfo(); - - currentInfo->setSlot (XML::getProperty(equipmentNode, "slot", 0)); - - //iterate s - for_each_xml_child_node(spriteNode, equipmentNode) - { - if (!xmlStrEqual(spriteNode->name, BAD_CAST "sprite")) - { - continue; - } - - std::string gender = XML::getProperty(spriteNode, "gender", "unisex"); - std::string filename = (const char*) spriteNode->xmlChildrenNode->content; - - if (gender == "male" || gender == "unisex") - { - currentInfo->setSprite(filename, 0); - } - - if (gender == "female" || gender == "unisex") - { - currentInfo->setSprite(filename, 1); - } - } - - setEquipment( XML::getProperty(equipmentNode, "id", 0), - currentInfo); - } - - mLoaded = true; -} - -void -EquipmentDB::unload() -{ - // kill EquipmentInfos - for_each ( mEquipmentInfos.begin(), mEquipmentInfos.end(), - make_dtor(mEquipmentInfos)); - mEquipmentInfos.clear(); - - mLoaded = false; -} - -EquipmentInfo* -EquipmentDB::get(int id) -{ - if (!mLoaded) { - logger->error("Error: Equipment database used before initialization!"); - } - - EquipmentInfoIterator i = mEquipmentInfos.find(id); - - if (i == mEquipmentInfos.end() ) - { - logger->log("EquipmentDB: Error, unknown equipment ID# %d", id); - return &mUnknown; - } - else - { - return i->second; - } -} - -void -EquipmentDB::setEquipment(int id, EquipmentInfo* equipmentInfo) -{ - if (mEquipmentInfos.find(id) != mEquipmentInfos.end()) { - logger->log("Warning: Equipment Piece with ID %d defined multiple times", - id); - delete equipmentInfo; - } - else { - mEquipmentInfos[id] = equipmentInfo; - }; -} diff --git a/src/resources/equipmentdb.h b/src/resources/equipmentdb.h deleted file mode 100644 index 1c1db7d1..00000000 --- a/src/resources/equipmentdb.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * The Mana World - * Copyright 2006 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id$ - */ - -#ifndef _TMW_EQUIPMENT_DB_H -#define _TMW_EQUIPMENT_DB_H - -#include - -#include "equipmentinfo.h" - -/** - * Equipment information database. - */ -namespace EquipmentDB -{ - /** - * Loads the equipment info from Items.xml - */ - void load(); - - /** - * Frees equipment data - */ - void unload(); - - void setEquipment(int id, EquipmentInfo* equipmentInfo); - - EquipmentInfo* get(int id); - - // Equipment database types - typedef std::map EquipmentInfos; - typedef EquipmentInfos::iterator EquipmentInfoIterator; -} - -#endif diff --git a/src/resources/equipmentinfo.h b/src/resources/equipmentinfo.h deleted file mode 100644 index 75ed1b8a..00000000 --- a/src/resources/equipmentinfo.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * The Mana World - * Copyright 2006 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * The Mana World is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: - */ - -#ifndef _TMW_EQUIPMENTINFO_H_ -#define _TMW_EQUIPMENTINFO_H_ - -#include -#include - -class EquipmentInfo -{ - public: - EquipmentInfo(): - mSlot (0) - { - }; - - void - setSlot (int slot) { mSlot = slot; }; - - const std::string& - getSprite(int gender) {return animationFiles[gender]; }; - - void - setSprite(std::string animationFile, int gender) {animationFiles[gender] = animationFile; }; - - private: - int mSlot; //not used at the moment but maybe useful on our own server - std::map animationFiles; -}; - -#endif diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index 7b16339c..18952ae9 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -18,9 +18,11 @@ * along with The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: + * $Id$ */ +#include + #include "itemdb.h" #include @@ -36,10 +38,13 @@ namespace { ItemDB::ItemInfos mItemInfos; - ItemInfo mUnknown; + ItemInfo *mUnknown; bool mLoaded = false; } +// Forward declarations +static void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node); +static void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node); void ItemDB::load() { @@ -47,11 +52,16 @@ void ItemDB::load() return; logger->log("Initializing item database..."); - mUnknown.setName("Unknown item"); + + mUnknown = new ItemInfo(); + mUnknown->setName("Unknown item"); + mUnknown->setImage(""); + mUnknown->setSprite("error.xml", 0); + mUnknown->setSprite("error.xml", 1); ResourceManager *resman = ResourceManager::getInstance(); int size; - char *data = (char*)resman->loadFile("items.xml", size); + char *data = (char*) resman->loadFile("items.xml", size); if (!data) { logger->error("ItemDB: Could not find items.xml!"); @@ -73,48 +83,66 @@ void ItemDB::load() for_each_xml_child_node(node, rootNode) { - if (!xmlStrEqual(node->name, BAD_CAST "item")) { + if (!xmlStrEqual(node->name, BAD_CAST "item")) continue; - } int id = XML::getProperty(node, "id", 0); - int art = XML::getProperty(node, "art", 0); + + if (id == 0) + { + logger->log("ItemDB: Invalid or missing item ID in items.xml!"); + continue; + } + else if (mItemInfos.find(id) != mItemInfos.end()) + { + logger->log("ItemDB: Redefinition of item ID %d", id); + } + int type = XML::getProperty(node, "type", 0); int weight = XML::getProperty(node, "weight", 0); + int view = XML::getProperty(node, "view", 0); int slot = XML::getProperty(node, "slot", 0); std::string name = XML::getProperty(node, "name", ""); std::string image = XML::getProperty(node, "image", ""); std::string description = XML::getProperty(node, "description", ""); std::string effect = XML::getProperty(node, "effect", ""); + std::string attackType = XML::getProperty(node, "attacktype", ""); - if (id && name != "") + if (id) { ItemInfo *itemInfo = new ItemInfo(); itemInfo->setImage(image); - itemInfo->setArt(art); - itemInfo->setName(name); + itemInfo->setName((name == "") ? "Unnamed" : name); itemInfo->setDescription(description); itemInfo->setEffect(effect); itemInfo->setType(type); + itemInfo->setView(view); itemInfo->setWeight(weight); itemInfo->setSlot(slot); - mItemInfos[id] = itemInfo; - } + itemInfo->setAttackType(attackType); + + for_each_xml_child_node(itemChild, node) + { + if (xmlStrEqual(itemChild->name, BAD_CAST "sprite")) + { + loadSpriteRef(itemInfo, itemChild); + } + else if (xmlStrEqual(itemChild->name, BAD_CAST "sound")) + { + loadSoundRef(itemInfo, itemChild); + } + } - if (id == 0) - { - logger->log("ItemDB: An item has no ID in items.xml!"); + mItemInfos[id] = itemInfo; } #define CHECK_PARAM(param, error_value) \ if (param == error_value) \ - logger->log("ItemDB: Missing" #param " parameter for item %i! %s", \ - id, name.c_str()) + logger->log("ItemDB: Missing " #param " attribute for item %i!",id) CHECK_PARAM(name, ""); CHECK_PARAM(image, ""); - // CHECK_PARAM(art, 0); // CHECK_PARAM(description, ""); // CHECK_PARAM(effect, ""); // CHECK_PARAM(type, 0); @@ -131,19 +159,65 @@ void ItemDB::load() void ItemDB::unload() { - for (ItemInfoIterator i = mItemInfos.begin(); i != mItemInfos.end(); i++) - { - delete i->second; - } - mItemInfos.clear(); + logger->log("Unloading item database..."); + + delete mUnknown; + mUnknown = NULL; + for_each(mItemInfos.begin(), mItemInfos.end(), make_dtor(mItemInfos)); + mItemInfos.clear(); mLoaded = false; } -const ItemInfo& -ItemDB::get(int id) +const ItemInfo& ItemDB::get(int id) { + assert(mLoaded); + ItemInfoIterator i = mItemInfos.find(id); - return (i != mItemInfos.end()) ? *(i->second) : mUnknown; + if (i == mItemInfos.end()) + { + logger->log("ItemDB: Error, unknown item ID# %d", id); + return *mUnknown; + } + else + { + return *(i->second); + } +} + +void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node) +{ + std::string gender = XML::getProperty(node, "gender", "unisex"); + std::string filename = (const char*) node->xmlChildrenNode->content; + + if (gender == "male" || gender == "unisex") + { + itemInfo->setSprite(filename, 0); + } + + if (gender == "female" || gender == "unisex") + { + itemInfo->setSprite(filename, 1); + } +} + +void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node) +{ + std::string event = XML::getProperty(node, "event", ""); + std::string filename = (const char*) node->xmlChildrenNode->content; + + if (event == "hit") + { + itemInfo->addSound(EQUIP_EVENT_HIT, filename); + } + else if (event == "strike") + { + itemInfo->addSound(EQUIP_EVENT_STRIKE, filename); + } + else + { + logger->log("ItemDB: Ignoring unknown sound event '%s'", + event.c_str()); + } } diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp index 3a41c657..b5b25ac0 100644 --- a/src/resources/iteminfo.cpp +++ b/src/resources/iteminfo.cpp @@ -25,11 +25,11 @@ #include "resourcemanager.h" #include "image.h" - +#include "itemdb.h" ItemInfo::~ItemInfo() { - if (mImage != NULL) + if (mImage) { mImage->decRef(); } @@ -38,19 +38,87 @@ ItemInfo::~ItemInfo() void ItemInfo::setImage(const std::string &image) { + if (mImage) + { + mImage->decRef(); + } + + ResourceManager *resman = ResourceManager::getInstance(); mImageName = "graphics/items/" + image; + mImage = ResourceManager::getInstance()->getImage(mImageName); - if (mImageName != "") + if (!mImage) { - if (mImage != NULL) - { - mImage->decRef(); - } + mImage = resman->getImage("graphics/gui/unknown-item.png"); + } +} - mImage = ResourceManager::getInstance()->getImage(mImageName); +const std::string& +ItemInfo::getSprite(int gender) const +{ + if (mView) + { + // Forward the request to the item defining how to view this item + return ItemDB::get(mView).getSprite(gender); } else { - mImage = NULL; + static const std::string empty = ""; + std::map::const_iterator i = + mAnimationFiles.find(gender); + + return (i != mAnimationFiles.end()) ? i->second : empty; + } +} + +void +ItemInfo::setAttackType(const std::string &attackType) +{ + if (attackType == "swing") + { + mAttackType = ACTION_ATTACK_SWING; + } + else if (attackType == "stab") + { + mAttackType = ACTION_ATTACK_STAB; + } + else if (attackType == "bow") + { + mAttackType = ACTION_ATTACK_BOW; } + else if (attackType == "throw") + { + mAttackType = ACTION_ATTACK_THROW; + } + else if (attackType == "none") + { + mAttackType = ACTION_DEFAULT; + } + else + { + mAttackType = ACTION_ATTACK; + } +} + +void +ItemInfo::addSound(EquipmentSoundEvent event, const std::string &filename) +{ + if (mSounds.find(event) == mSounds.end()) + { + mSounds[event] = new std::vector; + } + + mSounds[event]->push_back("sfx/" + filename); +} + + +const std::string& +ItemInfo::getSound(EquipmentSoundEvent event) const +{ + static const std::string empty = ""; + std::map*>::const_iterator i; + i = mSounds.find(event); + + return (i == mSounds.end()) ? empty : + i->second->at(rand() % i->second->size()); } diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h index e4f851bb..4fd1638e 100644 --- a/src/resources/iteminfo.h +++ b/src/resources/iteminfo.h @@ -24,12 +24,23 @@ #ifndef _TMW_ITEMINFO_H_ #define _TMW_ITEMINFO_H_ +#include #include +#include + +#include "spritedef.h" class Image; +enum EquipmentSoundEvent +{ + EQUIP_EVENT_STRIKE, + EQUIP_EVENT_HIT +}; + /** - * Defines a class for storing item infos. + * Defines a class for storing item infos. This includes information used when + * the item is equipped. */ class ItemInfo { @@ -40,10 +51,11 @@ class ItemInfo ItemInfo(): mImageName(""), mImage(NULL), - mArt(0), mType(0), mWeight(0), - mSlot(0) + mView(0), + mSlot(0), + mAttackType(ACTION_DEFAULT) { } @@ -52,73 +64,89 @@ class ItemInfo */ ~ItemInfo(); - void - setArt(short art) { mArt = art; } + void setName(const std::string &name) + { mName = name; } - short - getArt() const { return mArt; } + const std::string& getName() const + { return mName; } - void - setName(const std::string &name) { mName = name; } + void setImage(const std::string &image); - const std::string& - getName() const { return mName; } + Image* getImage() const + { return mImage; } - void - setImage(const std::string &image); + void setDescription(const std::string &description) + { mDescription = description; } - Image* - getImage() const { return mImage; } + const std::string& getDescription() const + { return mDescription; } - void - setDescription(const std::string &description) - { - mDescription = description; - } + void setEffect(const std::string &effect) + { mEffect = effect; } const std::string& - getDescription() const { return mDescription; } + getEffect() const { return mEffect; } - void - setEffect(const std::string &effect) { mEffect = effect; } + void setType(short type) + { mType = type; } - const std::string& - getEffect() const { return mEffect; } + short getType() const + { return mType; } + + void setWeight(short weight) + { mWeight = weight; } + + short getWeight() const + { return mWeight; } + + void setView(int view) + { mView = view; } + + void setSlot(char slot) + { mSlot = slot; } - void - setType(short type) { mType = type; } + char getSlot() const + { return mSlot; } - short - getType() const { return mType; } + void setSprite(const std::string &animationFile, int gender) + { mAnimationFiles[gender] = animationFile; } - void - setWeight(short weight) { mWeight = weight; } + const std::string& getSprite(int gender) const; - short - getWeight() const { return mWeight; } + void setAttackType(const std::string &attackType); - void - setSlot(char slot) { mSlot = slot; } + const SpriteAction getAttackType() const + { return mAttackType; } - char - getSlot() const { return mSlot; } + void addSound(EquipmentSoundEvent event, const std::string &filename); + + const std::string& getSound(EquipmentSoundEvent event) const; protected: - std::string mImageName; + std::string mImageName; /**< The filename of the icon image. */ /* TODO (BL): I do not think the item info should keep a reference to * the item icon. It would probably be better if this was kept in the * Item class, so that the images can be lazily instantiated and also * unloaded when no longer used. */ - Image *mImage; - short mArt; + Image *mImage; /**< The loaded icon image. */ std::string mName; - std::string mDescription; - std::string mEffect; - short mType; - short mWeight; - char mSlot; + std::string mDescription; /**< Short description. */ + std::string mEffect; /**< Description of effects. */ + short mType; /**< Item type (never used). */ + short mWeight; /**< Weight in grams. */ + int mView; /**< Item ID of how this item looks. */ + + // Equipment related members + char mSlot; /**< Equipment slot. */ + SpriteAction mAttackType; /**< Attack type, in case of weapon. */ + + /** Maps gender to sprite filenames. */ + std::map mAnimationFiles; + + /** Stores the names of sounds to be played at certain event. */ + std::map* > mSounds; }; #endif diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index 260d5aa9..940ded36 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -156,7 +156,7 @@ MapReader::readMap(const std::string &filename) if (buffer == NULL) { - logger->log("Map file not found (%s)\n", filename.c_str()); + logger->log("Map file not found (%s)", filename.c_str()); return NULL; } diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp index 339ed6ba..f4864eea 100644 --- a/src/resources/monsterdb.cpp +++ b/src/resources/monsterdb.cpp @@ -120,19 +120,19 @@ MonsterDB::load() if (event == "hit") { - currentInfo->addSound(EVENT_HIT, filename); + currentInfo->addSound(MONSTER_EVENT_HIT, filename); } else if (event == "miss") { - currentInfo->addSound(EVENT_MISS, filename); + currentInfo->addSound(MONSTER_EVENT_MISS, filename); } else if (event == "hurt") { - currentInfo->addSound(EVENT_HURT, filename); + currentInfo->addSound(MONSTER_EVENT_HURT, filename); } else if (event == "die") { - currentInfo->addSound(EVENT_DIE, filename); + currentInfo->addSound(MONSTER_EVENT_DIE, filename); } else { diff --git a/src/resources/monsterinfo.cpp b/src/resources/monsterinfo.cpp index 2a59419e..2e896237 100644 --- a/src/resources/monsterinfo.cpp +++ b/src/resources/monsterinfo.cpp @@ -33,15 +33,15 @@ MonsterInfo::MonsterInfo(): MonsterInfo::~MonsterInfo() { - //kill vectors in mSoundEffects - for_each ( mSounds.begin(), mSounds.end(), - make_dtor(mSounds)); + // kill vectors in mSoundEffects + for_each (mSounds.begin(), mSounds.end(), + make_dtor(mSounds)); mSounds.clear(); } void -MonsterInfo::addSound (SoundEvent event, std::string filename) +MonsterInfo::addSound(MonsterSoundEvent event, std::string filename) { if (mSounds.find(event) == mSounds.end()) { @@ -53,9 +53,9 @@ MonsterInfo::addSound (SoundEvent event, std::string filename) std::string -MonsterInfo::getSound (SoundEvent event) const +MonsterInfo::getSound(MonsterSoundEvent event) const { - std::map* >::const_iterator i; + std::map* >::const_iterator i; i = mSounds.find(event); diff --git a/src/resources/monsterinfo.h b/src/resources/monsterinfo.h index aa7db9f0..c9fbd4c9 100644 --- a/src/resources/monsterinfo.h +++ b/src/resources/monsterinfo.h @@ -31,12 +31,12 @@ #include "../being.h" -enum SoundEvent +enum MonsterSoundEvent { - EVENT_HIT, - EVENT_MISS, - EVENT_HURT, - EVENT_DIE + MONSTER_EVENT_HIT, + MONSTER_EVENT_MISS, + MONSTER_EVENT_HURT, + MONSTER_EVENT_DIE }; /** @@ -69,7 +69,7 @@ class MonsterInfo { mTargetCursorSize = targetCursorSize; } void - addSound(SoundEvent event, std::string filename); + addSound(MonsterSoundEvent event, std::string filename); const std::string& getName () const { return mName; }; @@ -81,13 +81,13 @@ class MonsterInfo getTargetCursorSize() const { return mTargetCursorSize; } std::string - getSound (SoundEvent event) const; + getSound(MonsterSoundEvent event) const; private: std::string mName; std::string mSprite; Being::TargetCursorSize mTargetCursorSize; - std::map* > mSounds; + std::map* > mSounds; }; #endif diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h index 6d335b02..55d7f459 100644 --- a/src/resources/spritedef.h +++ b/src/resources/spritedef.h @@ -24,11 +24,11 @@ #ifndef _TMW_SPRITEDEF_H #define _TMW_SPRITEDEF_H -#include "resource.h" - #include #include +#include "resource.h" + #include class Action; diff --git a/src/textparticle.cpp b/src/textparticle.cpp index dd01d2fe..4bc859cd 100644 --- a/src/textparticle.cpp +++ b/src/textparticle.cpp @@ -26,7 +26,8 @@ #include "graphics.h" TextParticle::TextParticle(Map *map, const std::string &text, - int colorR, int colorG, int colorB, gcn::Font *font): + int colorR, int colorG, int colorB, + gcn::Font *font): Particle(map), mText(text), mTextFont(font), @@ -41,8 +42,8 @@ void TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const if (!mAlive) return; - int screenX = (int)mPosX + offsetX; - int screenY = (int)mPosY - int(mPosZ) + offsetY; + int screenX = (int) mPos.x + offsetX; + int screenY = (int) mPos.y - (int) mPos.z + offsetY; int alpha = 255; @@ -50,7 +51,7 @@ void TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const { alpha *= mLifetimeLeft; alpha /= mFadeOut; - }; + } if (mLifetimePast < mFadeIn) { @@ -59,6 +60,6 @@ void TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const } graphics->setFont(mTextFont); - graphics->setColor(gcn::Color (mColorR, mColorG, mColorB, alpha)); + graphics->setColor(gcn::Color(mColorR, mColorG, mColorB, alpha)); graphics->drawText(mText, screenX, screenY, gcn::Graphics::CENTER); } diff --git a/src/textparticle.h b/src/textparticle.h index b365c885..34badb57 100644 --- a/src/textparticle.h +++ b/src/textparticle.h @@ -33,21 +33,26 @@ class TextParticle : public Particle { public: + /** + * Constructor. + */ TextParticle(Map *map, const std::string &text, - int colorR, int colorG, int colorB, gcn::Font *font); + int colorR, int colorG, int colorB, + gcn::Font *font); /** - * Draws the particle image + * Draws the particle image. */ virtual void draw(Graphics *graphics, int offsetX, int offsetY) const; // hack to improve text visibility - virtual int getPixelY() const { return (int)(mPosY + mPosZ); } + virtual int getPixelY() const + { return (int) (mPos.y + mPos.z); } private: - std::string mText; /**< Text of the particle */ - gcn::Font *mTextFont; /**< Font used for drawing the text */ - int mColorR, mColorG, mColorB; /**< Color used for drawing the text */ + std::string mText; /**< Text of the particle. */ + gcn::Font *mTextFont; /**< Font used for drawing the text. */ + int mColorR, mColorG, mColorB; /**< Color used for drawing the text. */ }; #endif diff --git a/src/utils/fastsqrt.h b/src/utils/fastsqrt.h index 78768149..b7b036e9 100644 --- a/src/utils/fastsqrt.h +++ b/src/utils/fastsqrt.h @@ -5,6 +5,8 @@ * http://www.math.purdue.edu/~clomont/Math/Papers/2003/InvSqrt.pdf * * Unfortunately the original creator of this function seems to be unknown. + * + * $Id$ */ float fastInvSqrt(float x) diff --git a/src/utils/minmax.h b/src/utils/minmax.h index 27eb2565..ea6ad9e0 100644 --- a/src/utils/minmax.h +++ b/src/utils/minmax.h @@ -18,6 +18,7 @@ * along with The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * $Id$ */ /** diff --git a/src/utils/trim.h b/src/utils/trim.h new file mode 100644 index 00000000..1b5311e6 --- /dev/null +++ b/src/utils/trim.h @@ -0,0 +1,53 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_UTILS_TRIM_H_ +#define _TMW_UTILS_TRIM_H_ + +#include + +/** + * Trims spaces off the end and the beginning of the given string. + * + * @param str the string to trim spaces off + */ +static void trim(std::string &str) +{ + std::string::size_type pos = str.find_last_not_of(' '); + if (pos != std::string::npos) + { + str.erase(pos + 1); + pos = str.find_first_not_of(' '); + if (pos != std::string::npos) + { + str.erase(0, pos); + } + } + else + { + // There is nothing else but whitespace in the string + str.clear(); + } +} + +#endif diff --git a/src/vector.h b/src/vector.h new file mode 100644 index 00000000..7a5da241 --- /dev/null +++ b/src/vector.h @@ -0,0 +1,134 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_VECTOR_H_ +#define _TMW_VECTOR_H_ + +/** + * Vector class. Represents either a 3D point in space, a velocity or a force. + * Provides several convenient operator overloads. + */ +class Vector +{ + public: + /** + * Constructor. + */ + Vector(): + x(0.0f), + y(0.0f), + z(0.0f) + {} + + /** + * Constructor. + */ + Vector(float x, float y, float z): + x(x), + y(y), + z(z) + {} + + /** + * Copy constructor. + */ + Vector(const Vector &v): + x(v.x), + y(v.y), + z(v.z) + {} + + /** + * Scale vector operator. + */ + Vector operator*(float c) const + { + return Vector(x * c, + y * c, + z * c); + } + + /** + * In-place scale vector operator. + */ + void operator*=(float c) + { + x *= c; + y *= c; + z *= c; + } + + /** + * Scale vector operator. + */ + Vector operator/(float c) const + { + return Vector(x / c, + y / c, + z / c); + } + + /** + * Add vector operator. + */ + Vector operator+(const Vector &v) const + { + return Vector(x + v.x, + y + v.y, + z + v.z); + } + + /** + * In-place add vector operator. + */ + void operator+=(const Vector &v) + { + x += v.x; + y += v.y; + z += v.z; + } + + /** + * Substract vector operator. + */ + Vector operator-(const Vector &v) const + { + return Vector(x - v.x, + y - v.y, + z - v.z); + } + + /** + * In-place substract vector operator. + */ + void operator-=(const Vector &v) + { + x -= v.x; + y -= v.y; + z -= v.z; + } + + float x, y, z; +}; + +#endif diff --git a/tools/adler32.c b/tools/adler32.c new file mode 100644 index 00000000..4e851713 --- /dev/null +++ b/tools/adler32.c @@ -0,0 +1,67 @@ +/* + * adler32.c (c) 2006 Bjorn Lindeijer + * License: GPL, v2 or later + * + * Calculates Adler-32 checksums for all files passed as argument. + * + * Usage: adler32 [file]... + */ + +#include +#include + +/** + * Calculates the Adler-32 checksum for the given file. + */ +unsigned long fadler32(FILE *file) +{ + // Obtain file size + fseek(file, 0, SEEK_END); + long fileSize = ftell(file); + rewind(file); + + // Calculate Adler-32 checksum + char *buffer = (char*) malloc(fileSize); + fread(buffer, 1, fileSize, file); + unsigned long adler = adler32(0L, Z_NULL, 0); + adler = adler32(adler, (Bytef*) buffer, fileSize); + free(buffer); + + return adler; +} + +/** + * Prints out usage and exists. + */ +void print_usage() +{ + printf("Usage: adler32 [file]...\n"); + exit(0); +} + +int main(int argc, char *argv[]) +{ + int i; /**< Loops through arguments. */ + + if (argc == 1) + { + print_usage(); + } + + for (i = 1; i < argc; ++i) + { + FILE *file = fopen(argv[i], "r"); + + if (!file) + { + printf("Error while opening '%s' for reading!\n", argv[i]); + exit(1); + } + + unsigned long adler = fadler32(file); + printf("%s %lx\n", argv[i], adler); + fclose(file); + } + + return 0; +} -- cgit v1.2.3-70-g09d2 From 546ae9ed020aefae6ee7470a92dff4901eceb53f Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Thu, 18 Oct 2007 11:06:01 +0000 Subject: Removed guess of being type from class number. Factored handler for new beings. --- ChangeLog | 6 ++++++ src/beingmanager.cpp | 27 ++++++++++++++++++--------- src/beingmanager.h | 2 +- src/net/beinghandler.cpp | 41 +++++++++++++++-------------------------- 4 files changed, 40 insertions(+), 36 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 2c35fb50..eabc1eaf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2007-10-18 Guillaume Melquiond + + * src/beingmanager.h, src/beingmanager.cpp, src/net/beinghandler.cpp: + Removed guess of being type from class number. Factored handler for new + beings. + 2007-10-15 Bjørn Lindeijer * src/gui/viewport.h, src/gui/viewport.cpp: Put drawing of debug path diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp index a5be17d2..56865841 100644 --- a/src/beingmanager.cpp +++ b/src/beingmanager.cpp @@ -21,6 +21,8 @@ * $Id$ */ +#include + #include "beingmanager.h" #include "localplayer.h" @@ -28,6 +30,7 @@ #include "npc.h" #include "player.h" +#include "net/protocol.h" #include "utils/dtor.h" class FindBeingFunctor @@ -59,18 +62,24 @@ void BeingManager::setPlayer(LocalPlayer *player) mBeings.push_back(player); } -Being* BeingManager::createBeing(Uint16 id, Uint16 job) +Being* BeingManager::createBeing(int id, int type, int subtype) { Being *being; - if (job < 10) - being = new Player(id, job, mMap); - else if (job >= 100 & job < 200) - being = new NPC(id, job, mMap); - else if (job >= 1000 && job < 1200) - being = new Monster(id, job, mMap); - else - being = new Being(id, job, mMap); + switch (type) + { + case OBJECT_PLAYER: + being = new Player(id, subtype, mMap); + break; + case OBJECT_NPC: + being = new NPC(id, subtype, mMap); + break; + case OBJECT_MONSTER: + being = new Monster(id, subtype, mMap); + break; + default: + assert(false); + } mBeings.push_back(being); return being; diff --git a/src/beingmanager.h b/src/beingmanager.h index f97a23f4..81f85622 100644 --- a/src/beingmanager.h +++ b/src/beingmanager.h @@ -48,7 +48,7 @@ class BeingManager /** * Create a being and add it to the list of beings. */ - Being* createBeing(Uint16 id, Uint16 job); + Being *createBeing(int id, int type, int subtype); /** * Remove a Being. diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index b88d443e..020d24af 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -449,18 +449,18 @@ static void handleLooks(Being *being, MessageIn &msg) void BeingHandler::handleBeingEnterMessage(MessageIn &msg) { - int type = msg.readByte(); // type + int type = msg.readByte(); int id = msg.readShort(); Being::Action action = (Being::Action)msg.readByte(); - Uint16 px = msg.readShort(); - Uint16 py = msg.readShort(); + int px = msg.readShort(); + int py = msg.readShort(); + Being *being; switch (type) { case OBJECT_PLAYER: { std::string name = msg.readString(); - Being *being; if (player_node->getName() == name) { being = player_node; @@ -468,41 +468,30 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) } else { - being = beingManager->createBeing(id, 0); + being = beingManager->createBeing(id, type, 0); being->setName(name); } being->setHairStyle(msg.readByte()); being->setHairColor(msg.readByte()); being->setSex(msg.readByte()); - being->mX = px; - being->mY = py; - being->setDestination(px, py); - being->setAction(action); handleLooks(being, msg); } break; case OBJECT_MONSTER: - { - int monsterId = msg.readShort(); - Being *being; - being = beingManager->createBeing(id, monsterId); - being->mX = px; - being->mY = py; - being->setDestination(px, py); - being->setAction(action); - } break; - case OBJECT_NPC: { - int npcId = msg.readShort(); - Being *being; - being = beingManager->createBeing(id, npcId); - being->mX = px; - being->mY = py; - being->setDestination(px, py); - being->setAction(action); + int subtype = msg.readShort(); + being = beingManager->createBeing(id, type, subtype); } break; + + default: + return; } + + being->mX = px; + being->mY = py; + being->setDestination(px, py); + being->setAction(action); } void BeingHandler::handleBeingLeaveMessage(MessageIn &msg) -- cgit v1.2.3-70-g09d2 From 54ac35bc5a1484757efeae9b342469b9a00fe2a2 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Thu, 18 Oct 2007 19:00:38 +0000 Subject: Removed player looks from generic beings. Prevented client termination on missing sprites. Merged weapon-type and attack-type fields for items. --- ChangeLog | 15 +++++++++ src/animatedsprite.cpp | 18 ++++------- src/animatedsprite.h | 4 +-- src/being.cpp | 26 ++-------------- src/being.h | 50 +----------------------------- src/gui/minimap.cpp | 12 +++++--- src/gui/viewport.cpp | 2 +- src/localplayer.cpp | 8 ++--- src/localplayer.h | 3 +- src/monster.cpp | 2 +- src/net/beinghandler.cpp | 15 ++++----- src/net/charserverhandler.cpp | 2 +- src/npc.cpp | 2 +- src/player.cpp | 64 +++++++++++++++++---------------------- src/player.h | 43 ++++++++++++++++++++------ src/resources/itemdb.cpp | 4 +-- src/resources/iteminfo.cpp | 45 +++++++++++++-------------- src/resources/iteminfo.h | 2 +- src/resources/resourcemanager.cpp | 7 +++++ src/resources/spritedef.cpp | 4 +-- 20 files changed, 143 insertions(+), 185 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index e7c46186..e01f8574 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,21 @@ * src/monster.cpp: Removed compatibility hack. * data/monsters.xml: Merged client and server monster data. * data/items.xml: Merged server item data. Removed obsolete fields. + * src/localplayer.cpp, src/localplayer.h: Moved equipment and inventory + storage to local player. Removed specific type. + * src/gui/viewport.cpp, src/gui/minimap.cpp: Changed identification of + local player to a check of player_node. + * src/animatedsprite.cpp, src/animatedsprite.h, src/npc.cpp, + src/player.cpp, src/monster.cpp: + * src/being.cpp, src/being.h, src/player.h, src/net/beinghandler.cpp, + src/net/charserverhandler.cpp: Removed hair style, hair color, gender, + and equipment from generic being. + * src/resources/spritedef.cpp: Added filename to fatal error messages. + * src/resources/resourcemanager.cpp: Prevented client from exiting on + missing sprite. + * src/resources/iteminfo.cpp, src/resources/iteminfo.h, + src/resources/itemdb.cpp, data/items.xml: Merged weapon_type and + attacktype field. 2007-10-15 Bjørn Lindeijer diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp index c1e89ff0..466779fd 100644 --- a/src/animatedsprite.cpp +++ b/src/animatedsprite.cpp @@ -54,20 +54,14 @@ AnimatedSprite::AnimatedSprite(SpriteDef *sprite): play(ACTION_STAND); } -AnimatedSprite::AnimatedSprite(const std::string& filename, int variant): - mDirection(DIRECTION_DOWN), - mLastTime(0), - mFrameIndex(0), - mFrameTime(0), - mAnimation(0), - mFrame(0) +AnimatedSprite *AnimatedSprite::load(const std::string& filename, int variant) { ResourceManager *resman = ResourceManager::getInstance(); - mSprite = resman->getSprite(filename, variant); - assert(mSprite); - - // Play the stand animation by default - play(ACTION_STAND); + SpriteDef *s = resman->getSprite(filename, variant); + if (!s) return NULL; + AnimatedSprite *as = new AnimatedSprite(s); + s->decRef(); + return as; } AnimatedSprite::~AnimatedSprite() diff --git a/src/animatedsprite.h b/src/animatedsprite.h index d77d08f5..a1fbe7a0 100644 --- a/src/animatedsprite.h +++ b/src/animatedsprite.h @@ -46,13 +46,13 @@ class AnimatedSprite AnimatedSprite(SpriteDef *sprite); /** - * A convenience constructor, which will request the sprite to animate + * An helper function, which will request the sprite to animate * from the resource manager. * * @param filename the file of the sprite to animate * @param variant the sprite variant */ - AnimatedSprite(const std::string& filename, int variant = 0); + static AnimatedSprite *load(std::string const &filename, int variant = 0); /** * Destructor. diff --git a/src/being.cpp b/src/being.cpp index 81bed667..d5f37371 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -46,26 +46,22 @@ int Being::instances = 0; ImageSet *Being::emotionSet = NULL; -Being::Being(Uint16 id, Uint16 job, Map *map): +Being::Being(int id, int job, Map *map): mJob(job), mX(0), mY(0), mAction(STAND), mWalkTime(0), mEmotion(0), mEmotionTime(0), mAttackSpeed(350), - mEquipment(new Equipment()), mId(id), - mSex(2), mWalkSpeed(150), mSpeedModifier(1024), mSpriteDirection(DIRECTION_DOWN), mDirection(DOWN), mMap(NULL), mEquippedWeapon(NULL), - mHairStyle(0), mHairColor(0), mSpeechTime(0), mPx(0), mPy(0), - mSprites(VECTOREND_SPRITE, NULL), - mEquipmentSpriteIDs(VECTOREND_SPRITE, 0) + mSprites(VECTOREND_SPRITE, NULL) { setMap(map); @@ -272,24 +268,6 @@ Being::setPath(const Path &path, int mod) } } -void -Being::setHairColor(Uint16 color) -{ - mHairColor = (color < NR_HAIR_COLORS) ? color : 0; -} - -void -Being::setHairStyle(Uint16 style) -{ - mHairStyle = (style < NR_HAIR_STYLES) ? style : 0; -} - -void -Being::setVisibleEquipment(Uint8 slot, int id) -{ - mEquipmentSpriteIDs[slot] = id; -} - void Being::setSpeech(const std::string &text, Uint32 time) { diff --git a/src/being.h b/src/being.h index fadf9656..fd17caf5 100644 --- a/src/being.h +++ b/src/being.h @@ -68,7 +68,6 @@ class Being : public Sprite public: enum Type { UNKNOWN, - LOCALPLAYER, PLAYER, NPC, MONSTER @@ -125,7 +124,7 @@ class Being : public Sprite /** * Constructor. */ - Being(Uint16 id, Uint16 job, Map *map); + Being(int id, int job, Map *map); /** * Destructor. @@ -189,48 +188,6 @@ class Being : public Sprite void setName(const std::string &name) { mName = name; } - /** - * Sets the hair color for this being. - */ - virtual void - setHairColor(Uint16 color); - - /** - * Gets the hair color for this being. - */ - Uint16 - getHairColor() const { return mHairColor; } - - /** - * Sets the hair style for this being. - */ - virtual void - setHairStyle(Uint16 style); - - /** - * Gets the hair style for this being. - */ - Uint16 - getHairStyle() const { return mHairStyle; } - - /** - * Sets visible equipments for this being. - */ - virtual void - setVisibleEquipment(Uint8 slot, int id); - - /** - * Sets the sex for this being. - */ - virtual void - setSex(Uint8 sex) { mSex = sex; } - - /** - * Gets the sex for this being. - */ - Uint8 - getSex() const { return mSex; } - /** * Makes this being take the next step of his path. */ @@ -364,8 +321,6 @@ class Being : public Sprite virtual Being::TargetCursorSize getTargetCursorSize() const { return TC_MEDIUM; } - std::auto_ptr mEquipment; - /** * Take control of a particle. */ @@ -378,7 +333,6 @@ class Being : public Sprite void setPath(const Path &path, int mod = 1024); Uint16 mId; /**< Unique being id */ - Uint8 mSex; /**< Character's gender */ Uint16 mWalkSpeed; /**< Walking speed */ Uint16 mSpeedModifier; /**< Modifier to keep course on sync (1024 = normal speed) */ Uint8 mSpriteDirection; /**< Facing direction */ @@ -391,12 +345,10 @@ class Being : public Sprite Path mPath; std::string mSpeech; - Uint16 mHairStyle, mHairColor; Uint32 mSpeechTime; Sint32 mPx, mPy; /**< Pixel coordinates */ std::vector mSprites; - std::vector mEquipmentSpriteIDs; std::list mChildParticleEffects; private: diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp index a8e9dafd..f78447cd 100644 --- a/src/gui/minimap.cpp +++ b/src/gui/minimap.cpp @@ -26,6 +26,7 @@ #include "../being.h" #include "../beingmanager.h" #include "../graphics.h" +#include "../localplayer.h" #include "../resources/image.h" @@ -86,12 +87,13 @@ void Minimap::draw(gcn::Graphics *graphics) int dotSize = 2; switch (being->getType()) { - case Being::LOCALPLAYER: - dotSize = 3; - graphics->setColor(gcn::Color(61, 209, 52)); - break; - case Being::PLAYER: + if (being == player_node) + { + dotSize = 3; + graphics->setColor(gcn::Color(61, 209, 52)); + break; + } graphics->setColor(gcn::Color(61, 52, 209)); break; diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index 915b618d..5c48c355 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -373,7 +373,7 @@ Viewport::mousePressed(gcn::MouseEvent &event) FloorItem *floorItem; if ((being = beingManager->findBeing(tilex, tiley)) && - being->getType() != Being::LOCALPLAYER) + being != player_node) { mPopupMenu->showPopup(event.getX(), event.getY(), being); return; diff --git a/src/localplayer.cpp b/src/localplayer.cpp index f4ad7587..346597a8 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -47,7 +47,8 @@ LocalPlayer *player_node = NULL; LocalPlayer::LocalPlayer(): Player(65535, 0, NULL), mAttackRange(0), - mInventory(new Inventory()), + mInventory(new Inventory), + mEquipment(new Equipment), mAttributeBase(NB_CHARACTER_ATTRIBUTES, 0), mAttributeEffective(NB_CHARACTER_ATTRIBUTES, 0), mAttributeIncreasePoints(0), @@ -94,11 +95,6 @@ void LocalPlayer::nextStep() Player::nextStep(); } -Being::Type LocalPlayer::getType() const -{ - return LOCALPLAYER; -} - void LocalPlayer::clearInventory() { mEquipment->clear(); diff --git a/src/localplayer.h b/src/localplayer.h index ff7bf0b7..6349f7ed 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -141,8 +141,6 @@ class LocalPlayer : public Player virtual void drawName(Graphics *, int, int) {}; - virtual Type getType() const; - void clearInventory(); Item* getInvItem(int index); @@ -305,6 +303,7 @@ class LocalPlayer : public Player float mLastAttackTime; /**< Used to synchronize the charge dialog */ std::auto_ptr mInventory; + std::auto_ptr mEquipment; protected: void walk(unsigned char dir); diff --git a/src/monster.cpp b/src/monster.cpp index fe78c878..bc964b0b 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -35,7 +35,7 @@ Monster::Monster(Uint16 id, Uint16 job, Map *map): Being(id, job, map) { - mSprites[BASE_SPRITE] = new AnimatedSprite( + mSprites[BASE_SPRITE] = AnimatedSprite::load( "graphics/sprites/" + getInfo().getSprite()); } diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 020d24af..6bd31c9f 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -418,7 +418,7 @@ void BeingHandler::handleMessage(MessageIn &msg) } } -static void handleLooks(Being *being, MessageIn &msg) +static void handleLooks(Player *being, MessageIn &msg) { // Order of sent slots. Has to be in sync with the server code. static int const nb_slots = 4; @@ -471,10 +471,11 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) being = beingManager->createBeing(id, type, 0); being->setName(name); } - being->setHairStyle(msg.readByte()); - being->setHairColor(msg.readByte()); - being->setSex(msg.readByte()); - handleLooks(being, msg); + Player *p = static_cast< Player * >(being); + p->setHairStyle(msg.readByte()); + p->setHairColor(msg.readByte()); + p->setGender(msg.readByte()); + handleLooks(p, msg); } break; case OBJECT_MONSTER: @@ -591,7 +592,7 @@ void BeingHandler::handleBeingActionChangeMessage(MessageIn &msg) void BeingHandler::handleBeingLooksChangeMessage(MessageIn &msg) { Being *being = beingManager->findBeing(msg.readShort()); - if (!being) return; - handleLooks(being, msg); + if (!being || being->getType() != Being::PLAYER) return; + handleLooks(static_cast< Player * >(being), msg); } diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp index 820aaea4..1cfd815b 100644 --- a/src/net/charserverhandler.cpp +++ b/src/net/charserverhandler.cpp @@ -216,7 +216,7 @@ CharServerHandler::readPlayerData(MessageIn &msg, int &slot) LocalPlayer *tempPlayer = new LocalPlayer; slot = msg.readByte(); // character slot tempPlayer->mName = msg.readString(); - tempPlayer->setSex(msg.readByte()); + tempPlayer->setGender(msg.readByte()); tempPlayer->setHairStyle(msg.readByte()); tempPlayer->setHairColor(msg.readByte()); tempPlayer->setLevel(msg.readByte()); diff --git a/src/npc.cpp b/src/npc.cpp index f65c8d19..980f1c8b 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -35,7 +35,7 @@ NPC *current_npc = 0; NPC::NPC(Uint16 id, Uint16 job, Map *map): Being(id, job, map) { - mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/npc.xml", + mSprites[BASE_SPRITE] = AnimatedSprite::load("graphics/sprites/npc.xml", job - 100); } diff --git a/src/player.cpp b/src/player.cpp index b63dcd5b..0fe6460c 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -35,8 +35,10 @@ #include "gui/gui.h" -Player::Player(Uint16 id, Uint16 job, Map *map): - Being(id, job, map) +Player::Player(int id, int job, Map *map): + Being(id, job, map), + mEquipmentSpriteIDs(VECTOREND_SPRITE, 0), + mGender(2), mHairStyle(0), mHairColor(0) { } @@ -57,8 +59,7 @@ Player::drawName(Graphics *graphics, int offsetX, int offsetY) graphics->drawText(mName, px + 15, py + 30, gcn::Graphics::CENTER); } -void -Player::setSex(Uint8 sex) +void Player::setGender(int sex) { // Players can only be male or female if (sex > 1) @@ -67,20 +68,20 @@ Player::setSex(Uint8 sex) sex = 0; } - if (sex != mSex) + if (sex != mGender) { - Being::setSex(sex); + mGender = sex; // Reload base sprite AnimatedSprite *newBaseSprite; if (sex == 0) { - newBaseSprite = new AnimatedSprite( + newBaseSprite = AnimatedSprite::load( "graphics/sprites/player_male_base.xml"); } else { - newBaseSprite = new AnimatedSprite( + newBaseSprite = AnimatedSprite::load( "graphics/sprites/player_female_base.xml"); } @@ -92,7 +93,7 @@ Player::setSex(Uint8 sex) { if (i != HAIR_SPRITE && mEquipmentSpriteIDs.at(i) != 0) { - AnimatedSprite *newEqSprite = new AnimatedSprite( + AnimatedSprite *newEqSprite = AnimatedSprite::load( "graphics/sprites/" + ItemDB::get( mEquipmentSpriteIDs.at(i)).getSprite(sex)); delete mSprites[i]; @@ -102,17 +103,17 @@ Player::setSex(Uint8 sex) } } -void -Player::setHairColor(Uint16 color) +void Player::setHairColor(int color) { if (color != mHairColor) { - Being::setHairColor(color); + mHairColor = color < NR_HAIR_COLORS ? color : 0; - AnimatedSprite *newHairSprite = new AnimatedSprite( - "graphics/sprites/hairstyle" + toString(mHairStyle) + ".xml", + AnimatedSprite *newHairSprite = AnimatedSprite::load( + "graphics/sprites/hairstyle" + toString(getHairStyle()) + ".xml", mHairColor); - newHairSprite->setDirection(getSpriteDirection()); + if (newHairSprite) + newHairSprite->setDirection(getSpriteDirection()); delete mSprites[HAIR_SPRITE]; mSprites[HAIR_SPRITE] = newHairSprite; @@ -121,17 +122,17 @@ Player::setHairColor(Uint16 color) } } -void -Player::setHairStyle(Uint16 style) +void Player::setHairStyle(int style) { if (style != mHairStyle) { - Being::setHairStyle(style); + mHairStyle = style < NR_HAIR_STYLES ? style : 0; - AnimatedSprite *newHairSprite = new AnimatedSprite( - "graphics/sprites/hairstyle" + toString(mHairStyle) + ".xml", + AnimatedSprite *newHairSprite = AnimatedSprite::load( + "graphics/sprites/hairstyle" + toString(getHairStyle()) + ".xml", mHairColor); - newHairSprite->setDirection(getSpriteDirection()); + if (newHairSprite) + newHairSprite->setDirection(getSpriteDirection()); delete mSprites[HAIR_SPRITE]; mSprites[HAIR_SPRITE] = newHairSprite; @@ -140,8 +141,7 @@ Player::setHairStyle(Uint16 style) } } -void -Player::setVisibleEquipment(Uint8 slot, int id) +void Player::setVisibleEquipment(int slot, int id) { // id = 0 means unequip if (id == 0) @@ -151,19 +151,11 @@ Player::setVisibleEquipment(Uint8 slot, int id) } else { - AnimatedSprite *equipmentSprite; - - if (mSex == 0) - { - equipmentSprite = new AnimatedSprite( - "graphics/sprites/" + ItemDB::get(id).getSprite(0)); - } - else { - equipmentSprite = new AnimatedSprite( - "graphics/sprites/" + ItemDB::get(id).getSprite(1)); - } + AnimatedSprite *equipmentSprite = AnimatedSprite::load( + "graphics/sprites/" + ItemDB::get(id).getSprite(mGender)); - equipmentSprite->setDirection(getSpriteDirection()); + if (equipmentSprite) + equipmentSprite->setDirection(getSpriteDirection()); delete mSprites[slot]; mSprites[slot] = equipmentSprite; @@ -176,5 +168,5 @@ Player::setVisibleEquipment(Uint8 slot, int id) setAction(mAction); } - Being::setVisibleEquipment(slot, id); + mEquipmentSpriteIDs[slot] = id; } diff --git a/src/player.h b/src/player.h index 2c06bfba..e6d3743a 100644 --- a/src/player.h +++ b/src/player.h @@ -40,7 +40,7 @@ class Player : public Being /** * Constructor. */ - Player(Uint16 id, Uint16 job, Map *map); + Player(int id, int job, Map *map); virtual Type getType() const; @@ -48,17 +48,42 @@ class Player : public Being virtual void drawName(Graphics *graphics, int offsetX, int offsetY); - virtual void - setSex(Uint8 sex); + /** + * Sets the sex for this player. + */ + void setGender(int); - virtual void - setHairColor(Uint16 color); + /** + * Gets the hair color for this player. + */ + int getHairColor() const + { return mHairColor; } - virtual void - setHairStyle(Uint16 style); + /** + * Sets the hair color for this player. + */ + void setHairColor(int color); - virtual void - setVisibleEquipment(Uint8 slot, int id); + /** + * Gets the hair style for this player. + */ + int getHairStyle() const + { return mHairStyle; } + + /** + * Sets the hair style for this player. + */ + void setHairStyle(int style); + + /** + * Sets visible equipments for this player. + */ + void setVisibleEquipment(int slot, int id); + + private: + + std::vector mEquipmentSpriteIDs; + Uint8 mGender, mHairStyle, mHairColor; }; #endif diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index 157e522c..4e978093 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -107,7 +107,7 @@ void ItemDB::load() std::string image = XML::getProperty(node, "image", ""); std::string description = XML::getProperty(node, "description", ""); std::string effect = XML::getProperty(node, "effect", ""); - std::string attackType = XML::getProperty(node, "attacktype", ""); + int weaponType = XML::getProperty(node, "weapon_type", 0); if (id) { @@ -120,7 +120,7 @@ void ItemDB::load() itemInfo->setView(view); itemInfo->setWeight(weight); itemInfo->setSlot(slot); - itemInfo->setAttackType(attackType); + itemInfo->setWeaponType(weaponType); for_each_xml_child_node(itemChild, node) { diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp index b5b25ac0..6654ccca 100644 --- a/src/resources/iteminfo.cpp +++ b/src/resources/iteminfo.cpp @@ -71,32 +71,29 @@ ItemInfo::getSprite(int gender) const } } -void -ItemInfo::setAttackType(const std::string &attackType) +void ItemInfo::setWeaponType(int type) { - if (attackType == "swing") - { - mAttackType = ACTION_ATTACK_SWING; - } - else if (attackType == "stab") - { - mAttackType = ACTION_ATTACK_STAB; - } - else if (attackType == "bow") - { - mAttackType = ACTION_ATTACK_BOW; - } - else if (attackType == "throw") - { - mAttackType = ACTION_ATTACK_THROW; - } - else if (attackType == "none") - { - mAttackType = ACTION_DEFAULT; - } - else + // See server item.hpp file for type values. + switch (type) { - mAttackType = ACTION_ATTACK; + case 0: // none + mAttackType = ACTION_DEFAULT; + break; + case 1: // knife + case 2: // sword + mAttackType = ACTION_ATTACK_STAB; + break; + case 8: // projectile + mAttackType = ACTION_ATTACK_THROW; + break; + case 10: // bow + mAttackType = ACTION_ATTACK_BOW; + break; + case 11: // sickle + mAttackType = ACTION_ATTACK_SWING; + break; + default: + mAttackType = ACTION_ATTACK; } } diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h index 4fd1638e..4cab66fa 100644 --- a/src/resources/iteminfo.h +++ b/src/resources/iteminfo.h @@ -113,7 +113,7 @@ class ItemInfo const std::string& getSprite(int gender) const; - void setAttackType(const std::string &attackType); + void setWeaponType(int); const SpriteAction getAttackType() const { return mAttackType; } diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index 448e7f80..5e3f3bc7 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -275,6 +275,13 @@ ResourceManager::getSprite(const std::string &path, int variant) return dynamic_cast(resIter->second); } + // FIXME: modify SpriteDef so that it gracefully fails on missing sprite. + if (!exists(path) || isDirectory(path)) + { + logger->log("Failed to load file: %s", path.c_str()); + return NULL; + } + SpriteDef *sprite = new SpriteDef(idPath, path, variant); sprite->incRef(); mResources[idPath] = sprite; diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp index 24156be1..d90d4067 100644 --- a/src/resources/spritedef.cpp +++ b/src/resources/spritedef.cpp @@ -73,13 +73,13 @@ SpriteDef::load(const std::string &animationFile, int variant) if (!doc) { logger->error( - "Animation: Error while parsing animation definition file!"); + "Animation: Error while parsing " + animationFile + " file!"); } xmlNodePtr rootNode = xmlDocGetRootElement(doc); if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "sprite")) { logger->error( - "Animation: this is not a valid animation definition file!"); + "Animation: this is not a valid " + animationFile + " file!"); } // Get the variant -- cgit v1.2.3-70-g09d2 From 8a60e11684e84807f3526b37afa8cbf6f103b8fd Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sat, 3 Nov 2007 09:58:25 +0000 Subject: Fixed double load of hair graphics. --- ChangeLog | 6 ++++++ src/gui/char_select.cpp | 13 +++++-------- src/net/beinghandler.cpp | 4 ++-- src/net/charserverhandler.cpp | 4 ++-- src/player.cpp | 45 ++++++++++++++----------------------------- src/player.h | 9 ++------- 6 files changed, 31 insertions(+), 50 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index b9aa344d..0bf5c443 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2007-11-03 Guillaume Melquiond + + * src/player.cpp, src/player.h, src/gui/char_select.cpp: Factored code. + * src/net/beinghandler.cpp, src/net/charserverhandler.cpp: Fixed double + load of hair graphics. + 2007-10-28 Matthias Hartmann * po/de.po: Updated german translation. diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp index c2306880..ccdf20c8 100644 --- a/src/gui/char_select.cpp +++ b/src/gui/char_select.cpp @@ -245,8 +245,7 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot): Window(_("Create Character"), true, parent), mSlot(slot) { mPlayer = new Player(0, 0, NULL); - mPlayer->setHairStyle(rand() % NR_HAIR_STYLES); - mPlayer->setHairColor(rand() % NR_HAIR_COLORS); + mPlayer->setHairStyle(rand() % NR_HAIR_STYLES, rand() % NR_HAIR_COLORS); mNameField = new TextField(""); mNameLabel = new gcn::Label(_("Name:")); @@ -373,18 +372,16 @@ CharCreateDialog::action(const gcn::ActionEvent &event) scheduleDelete(); } else if (event.getId() == "nextcolor") { - mPlayer->setHairColor((mPlayer->getHairColor() + 1) % NR_HAIR_COLORS); + mPlayer->setHairStyle(-1, mPlayer->getHairColor() + 1); } else if (event.getId() == "prevcolor") { - int prevColor = mPlayer->getHairColor() + NR_HAIR_COLORS - 1; - mPlayer->setHairColor(prevColor % NR_HAIR_COLORS); + mPlayer->setHairStyle(-1, mPlayer->getHairColor() + NR_HAIR_COLORS - 1); } else if (event.getId() == "nextstyle") { - mPlayer->setHairStyle((mPlayer->getHairStyle() + 1) % NR_HAIR_STYLES); + mPlayer->setHairStyle(mPlayer->getHairStyle() + 1, -1); } else if (event.getId() == "prevstyle") { - int prevStyle = mPlayer->getHairStyle() + NR_HAIR_STYLES - 1; - mPlayer->setHairStyle(prevStyle % NR_HAIR_STYLES); + mPlayer->setHairStyle(mPlayer->getHairStyle() + NR_HAIR_STYLES - 1, -1); } else if (event.getId() == "statslider") { UpdateSliders(); diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 6bd31c9f..56ec0192 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -472,8 +472,8 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) being->setName(name); } Player *p = static_cast< Player * >(being); - p->setHairStyle(msg.readByte()); - p->setHairColor(msg.readByte()); + int hs = msg.readByte(), hc = msg.readByte(); + p->setHairStyle(hs, hc); p->setGender(msg.readByte()); handleLooks(p, msg); } break; diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp index 1cfd815b..76311266 100644 --- a/src/net/charserverhandler.cpp +++ b/src/net/charserverhandler.cpp @@ -217,8 +217,8 @@ CharServerHandler::readPlayerData(MessageIn &msg, int &slot) slot = msg.readByte(); // character slot tempPlayer->mName = msg.readString(); tempPlayer->setGender(msg.readByte()); - tempPlayer->setHairStyle(msg.readByte()); - tempPlayer->setHairColor(msg.readByte()); + int hs = msg.readByte(), hc = msg.readByte(); + tempPlayer->setHairStyle(hs, hc); tempPlayer->setLevel(msg.readByte()); tempPlayer->setMoney(msg.readLong()); diff --git a/src/player.cpp b/src/player.cpp index 0fe6460c..062c1135 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -31,7 +31,7 @@ #include "resources/itemdb.h" #include "resources/iteminfo.h" -#include "utils/tostring.h" +#include "utils/strprintf.h" #include "gui/gui.h" @@ -103,42 +103,25 @@ void Player::setGender(int sex) } } -void Player::setHairColor(int color) +void Player::setHairStyle(int style, int color) { - if (color != mHairColor) - { - mHairColor = color < NR_HAIR_COLORS ? color : 0; - - AnimatedSprite *newHairSprite = AnimatedSprite::load( - "graphics/sprites/hairstyle" + toString(getHairStyle()) + ".xml", - mHairColor); - if (newHairSprite) - newHairSprite->setDirection(getSpriteDirection()); - - delete mSprites[HAIR_SPRITE]; - mSprites[HAIR_SPRITE] = newHairSprite; + style = style < 0 ? mHairStyle : style % NR_HAIR_STYLES; + color = color < 0 ? mHairColor : color % NR_HAIR_COLORS; + if (style == mHairStyle && color == mHairColor) return; - setAction(mAction); - } -} + mHairStyle = style; + mHairColor = color; -void Player::setHairStyle(int style) -{ - if (style != mHairStyle) - { - mHairStyle = style < NR_HAIR_STYLES ? style : 0; + AnimatedSprite *newHairSprite = AnimatedSprite::load + (strprintf("graphics/sprites/hairstyle%d.xml", style), color); - AnimatedSprite *newHairSprite = AnimatedSprite::load( - "graphics/sprites/hairstyle" + toString(getHairStyle()) + ".xml", - mHairColor); - if (newHairSprite) - newHairSprite->setDirection(getSpriteDirection()); + if (newHairSprite) + newHairSprite->setDirection(getSpriteDirection()); - delete mSprites[HAIR_SPRITE]; - mSprites[HAIR_SPRITE] = newHairSprite; + delete mSprites[HAIR_SPRITE]; + mSprites[HAIR_SPRITE] = newHairSprite; - setAction(mAction); - } + setAction(mAction); } void Player::setVisibleEquipment(int slot, int id) diff --git a/src/player.h b/src/player.h index e6d3743a..4d4f53f5 100644 --- a/src/player.h +++ b/src/player.h @@ -59,11 +59,6 @@ class Player : public Being int getHairColor() const { return mHairColor; } - /** - * Sets the hair color for this player. - */ - void setHairColor(int color); - /** * Gets the hair style for this player. */ @@ -71,9 +66,9 @@ class Player : public Being { return mHairStyle; } /** - * Sets the hair style for this player. + * Sets the hair style and color for this player. */ - void setHairStyle(int style); + void setHairStyle(int style, int color); /** * Sets visible equipments for this player. -- cgit v1.2.3-70-g09d2 From a5e6a44b51d4269ed6812c9a9e0b6a293d959a4d Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Wed, 21 Nov 2007 16:30:11 +0000 Subject: Renamed {read,write}{Byte,Short,Long} to {read,write}{Int8,Int16,Int32}. This is less confusing in 64-bit context and less conflicting with the 0.0 client. --- ChangeLog | 15 +++ src/localplayer.cpp | 4 +- src/net/accountserver/account.cpp | 24 ++-- src/net/accountserver/accountserver.cpp | 4 +- src/net/beinghandler.cpp | 196 ++++++++++++++++---------------- src/net/buysellhandler.cpp | 16 +-- src/net/charserverhandler.cpp | 22 ++-- src/net/chathandler.cpp | 28 ++--- src/net/chatserver/chatserver.cpp | 8 +- src/net/gameserver/gameserver.cpp | 2 +- src/net/gameserver/player.cpp | 46 ++++---- src/net/inventoryhandler.cpp | 8 +- src/net/itemhandler.cpp | 6 +- src/net/loginhandler.cpp | 6 +- src/net/logouthandler.cpp | 8 +- src/net/messagein.cpp | 10 +- src/net/messagein.h | 6 +- src/net/messageout.cpp | 10 +- src/net/messageout.h | 6 +- src/net/npchandler.cpp | 2 +- src/net/playerhandler.cpp | 14 +-- src/net/skillhandler.cpp | 26 ++--- src/net/tradehandler.cpp | 8 +- src/npc.cpp | 8 +- 24 files changed, 249 insertions(+), 234 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index f37db10b..a0c9aefe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,21 @@ * src/properties.h, src/net/charserverhandler.cpp, src/being.h: Small lingering changes made while merging to 0.0. + * src/localplayer.cpp, src/npc.cpp, + src/net/accountserver/accountserver.cpp, + src/net/accountserver/account.cpp, src/net/loginhandler.cpp, + src/net/messageout.cpp, src/net/buysellhandler.cpp, + src/net/messagein.h, src/net/beinghandler.cpp, + src/net/inventoryhandler.cpp, src/net/itemhandler.cpp, + src/net/tradehandler.cpp, src/net/charserverhandler.cpp, + src/net/logouthandler.cpp, src/net/messagein.cpp, + src/net/skillhandler.cpp, src/net/chathandler.cpp, + src/net/npchandler.cpp, src/net/gameserver/gameserver.cpp, + src/net/gameserver/player.cpp, src/net/messageout.h, + src/net/chatserver/chatserver.cpp, src/net/playerhandler.cpp: Renamed + {read,write}{Byte,Short,Long} to {read,write}{Int8,Int16,Int32}. This + is less confusing in 64-bit context and less conflicting with the 0.0 + client. 2007-11-21 Guillaume Melquiond diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 059bd0f4..d01b613e 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -286,7 +286,7 @@ void LocalPlayer::emote(Uint8 emotion) // XXX Convert for new server /* MessageOut outMsg(0x00bf); - outMsg.writeByte(emotion); + outMsg.writeInt8(emotion); */ } @@ -340,7 +340,7 @@ void LocalPlayer::revive() // XXX Convert for new server /* MessageOut outMsg(0x00b2); - outMsg.writeByte(0); + outMsg.writeInt8(0); */ } diff --git a/src/net/accountserver/account.cpp b/src/net/accountserver/account.cpp index a90f75b8..f0778b1d 100644 --- a/src/net/accountserver/account.cpp +++ b/src/net/accountserver/account.cpp @@ -37,16 +37,16 @@ void Net::AccountServer::Account::createCharacter( MessageOut msg(PAMSG_CHAR_CREATE); msg.writeString(name); - msg.writeByte(hairStyle); - msg.writeByte(hairColor); - msg.writeByte(gender); - msg.writeShort(strength); - msg.writeShort(agility); - msg.writeShort(vitality); - msg.writeShort(intelligence); - msg.writeShort(dexterity); - msg.writeShort(willpower); - msg.writeShort(charisma); + msg.writeInt8(hairStyle); + msg.writeInt8(hairColor); + msg.writeInt8(gender); + msg.writeInt16(strength); + msg.writeInt16(agility); + msg.writeInt16(vitality); + msg.writeInt16(intelligence); + msg.writeInt16(dexterity); + msg.writeInt16(willpower); + msg.writeInt16(charisma); Net::AccountServer::connection->send(msg); } @@ -55,7 +55,7 @@ void Net::AccountServer::Account::deleteCharacter(char slot) { MessageOut msg(PAMSG_CHAR_DELETE); - msg.writeByte(slot); + msg.writeInt8(slot); Net::AccountServer::connection->send(msg); } @@ -64,7 +64,7 @@ void Net::AccountServer::Account::selectCharacter(char slot) { MessageOut msg(PAMSG_CHAR_SELECT); - msg.writeByte(slot); + msg.writeInt8(slot); Net::AccountServer::connection->send(msg); } diff --git a/src/net/accountserver/accountserver.cpp b/src/net/accountserver/accountserver.cpp index 92d803e6..651758a6 100644 --- a/src/net/accountserver/accountserver.cpp +++ b/src/net/accountserver/accountserver.cpp @@ -36,7 +36,7 @@ void Net::AccountServer::login(Net::Connection *connection, int version, MessageOut msg(PAMSG_LOGIN); - msg.writeLong(version); + msg.writeInt32(version); msg.writeString(username); msg.writeString(password); @@ -51,7 +51,7 @@ void Net::AccountServer::registerAccount(Net::Connection *connection, MessageOut msg(PAMSG_REGISTER); - msg.writeLong(version); // client version + msg.writeInt32(version); // client version msg.writeString(username); msg.writeString(password); msg.writeString(email); diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 56ec0192..a9f992af 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -105,12 +105,12 @@ void BeingHandler::handleMessage(MessageIn &msg) case SMSG_BEING_VISIBLE: case SMSG_BEING_MOVE: // Information about a being in range - id = msg.readLong(); - speed = msg.readShort(); - msg.readShort(); // unknown - msg.readShort(); // unknown - msg.readShort(); // option - job = msg.readShort(); // class + id = msg.readInt32(); + speed = msg.readInt16(); + msg.readInt16(); // unknown + msg.readInt16(); // unknown + msg.readInt16(); // option + job = msg.readInt16(); // class dstBeing = beingManager->findBeing(id); @@ -138,32 +138,32 @@ void BeingHandler::handleMessage(MessageIn &msg) dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; - dstBeing->setHairStyle(msg->readShort()); + dstBeing->setHairStyle(msg->readInt16()); dstBeing->setVisibleEquipment( - Being::WEAPON_SPRITE, msg->readShort()); + Being::WEAPON_SPRITE, msg->readInt16()); dstBeing->setVisibleEquipment( - Being::BOTTOMCLOTHES_SPRITE, msg->readShort()); + Being::BOTTOMCLOTHES_SPRITE, msg->readInt16()); if (msg.getId() == SMSG_BEING_MOVE) { - msg.readLong(); // server tick + msg.readInt32(); // server tick } - msg->readShort(); // shield - headTop = msg->readShort(); - headMid = msg->readShort(); + msg->readInt16(); // shield + headTop = msg->readInt16(); + headMid = msg->readInt16(); dstBeing->setVisibleEquipment(Being::HAT_SPRITE, headTop); dstBeing->setVisibleEquipment(Being::TOPCLOTHES_SPRITE, headMid); - dstBeing->setHairColor(msg->readShort()); - msg->readShort(); // unknown - msg->readShort(); // head dir - msg->readShort(); // guild - msg->readShort(); // unknown - msg->readShort(); // unknown - msg->readShort(); // manner - msg->readShort(); // karma - msg->readByte(); // unknown - dstBeing->setSex(1 - msg->readByte()); // sex + dstBeing->setHairColor(msg->readInt16()); + msg->readInt16(); // unknown + msg->readInt16(); // head dir + msg->readInt16(); // guild + msg->readInt16(); // unknown + msg->readInt16(); // unknown + msg->readInt16(); // manner + msg->readInt16(); // karma + msg->readInt8(); // unknown + dstBeing->setSex(1 - msg->readInt8()); // sex if (msg.getId() == SMSG_BEING_MOVE) { @@ -181,19 +181,19 @@ void BeingHandler::handleMessage(MessageIn &msg) //dstBeing->setDirection(dir); } - msg.readByte(); // unknown - msg.readByte(); // unknown - msg.readByte(); // unknown / sit + msg.readInt8(); // unknown + msg.readInt8(); // unknown + msg.readInt8(); // unknown / sit break; case SMSG_BEING_REMOVE: // A being should be removed or has died - dstBeing = beingManager->findBeing(msg.readLong()); + dstBeing = beingManager->findBeing(msg.readInt32()); if (!dstBeing) break; - if (msg.readByte() == 1) + if (msg.readInt8() == 1) { dstBeing->setAction(Being::DEAD); } @@ -209,15 +209,15 @@ void BeingHandler::handleMessage(MessageIn &msg) break; case SMSG_BEING_ACTION: - srcBeing = beingManager->findBeing(msg.readLong()); - dstBeing = beingManager->findBeing(msg.readLong()); - msg.readLong(); // server tick - msg.readLong(); // src speed - msg.readLong(); // dst speed - param1 = msg.readShort(); - msg.readShort(); // param 2 - type = msg.readByte(); - msg.readShort(); // param 3 + srcBeing = beingManager->findBeing(msg.readInt32()); + dstBeing = beingManager->findBeing(msg.readInt32()); + msg.readInt32(); // server tick + msg.readInt32(); // src speed + msg.readInt32(); // dst speed + param1 = msg.readInt16(); + msg.readInt16(); // param 2 + type = msg.readInt8(); + msg.readInt16(); // param 3 switch (type) { @@ -247,7 +247,7 @@ void BeingHandler::handleMessage(MessageIn &msg) break; case SMSG_BEING_LEVELUP: - id = (Uint32) msg->readLong(); + id = (Uint32) msg->readInt32(); if (id == player_node->getId()) { logger->log("Level up"); @@ -257,7 +257,7 @@ void BeingHandler::handleMessage(MessageIn &msg) logger->log("Someone else went level up"); } Particle *levelupFX; - if (msg->readLong() == 0) { // type + if (msg->readInt32() == 0) { // type levelupFX = particleEngine->addEffect( "graphics/particles/levelup.particle.xml", 0, 0); } @@ -269,24 +269,24 @@ void BeingHandler::handleMessage(MessageIn &msg) break; case SMSG_BEING_EMOTION: - if (!(dstBeing = beingManager->findBeing(msg.readLong()))) + if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) { break; } - dstBeing->mEmotion = msg.readByte(); + dstBeing->mEmotion = msg.readInt8(); dstBeing->mEmotionTime = EMOTION_TIME; break; case SMSG_BEING_CHANGE_LOOKS: { - if (!(dstBeing = beingManager->findBeing(msg.readLong()))) + if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) { break; } - int type = msg.readByte(); - int id = msg.readByte(); + int type = msg.readInt8(); + int id = msg.readInt8(); switch (type) { case 1: @@ -319,7 +319,7 @@ void BeingHandler::handleMessage(MessageIn &msg) break; case SMSG_BEING_NAME_RESPONSE: - if ((dstBeing = beingManager->findBeing(msg.readLong()))) + if ((dstBeing = beingManager->findBeing(msg.readInt32()))) { dstBeing->setName(msg.readString(24)); } @@ -329,12 +329,12 @@ void BeingHandler::handleMessage(MessageIn &msg) case SMSG_PLAYER_UPDATE_2: case SMSG_PLAYER_MOVE: // An update about a player, potentially including movement. - id = msg.readLong(); - speed = msg.readShort(); - msg.readShort(); // option 1 - msg.readShort(); // option 2 - msg.readShort(); // option - job = msg.readShort(); + id = msg.readInt32(); + speed = msg.readInt16(); + msg.readInt16(); // option 1 + msg.readInt16(); // option 2 + msg.readInt16(); // option + job = msg.readInt16(); dstBeing = beingManager->findBeing(id); @@ -345,27 +345,27 @@ void BeingHandler::handleMessage(MessageIn &msg) dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; - dstBeing->setHairStyle(msg->readShort()); + dstBeing->setHairStyle(msg->readInt16()); dstBeing->setVisibleEquipment( - Being::WEAPON_SPRITE, msg->readShort()); - msg->readShort(); // item id 2 - headBottom = msg->readShort(); + Being::WEAPON_SPRITE, msg->readInt16()); + msg->readInt16(); // item id 2 + headBottom = msg->readInt16(); if (msg.getId() == SMSG_PLAYER_MOVE) { - msg.readLong(); // server tick + msg.readInt32(); // server tick } - headTop = msg.readShort(); - headMid = msg.readShort(); - dstBeing->setHairColor(msg.readShort()); - msg.readShort(); // unknown - msg.readShort(); // head dir - msg.readLong(); // guild - msg.readLong(); // emblem - msg.readShort(); // manner - msg.readByte(); // karma - dstBeing->setSex(1 - msg.readByte()); // sex + headTop = msg.readInt16(); + headMid = msg.readInt16(); + dstBeing->setHairColor(msg.readInt16()); + msg.readInt16(); // unknown + msg.readInt16(); // head dir + msg.readInt32(); // guild + msg.readInt32(); // emblem + msg.readInt16(); // manner + msg.readInt8(); // karma + dstBeing->setSex(1 - msg.readInt8()); // sex dstBeing->setVisibleEquipment( Being::BOTTOMCLOTHES_SPRITE, headBottom); dstBeing->setVisibleEquipment(Being::HAT_SPRITE, headTop); @@ -386,23 +386,23 @@ void BeingHandler::handleMessage(MessageIn &msg) //dstBeing->setDirection(dir); } - msg.readByte(); // unknown - msg.readByte(); // unknown + msg.readInt8(); // unknown + msg.readInt8(); // unknown if (msg.getId() == SMSG_PLAYER_UPDATE_1) { - if (msg.readByte() == 2) + if (msg.readInt8() == 2) { dstBeing->setAction(Being::SIT); } } else if (msg.getId() == SMSG_PLAYER_MOVE) { - msg.readByte(); // unknown + msg.readInt8(); // unknown } - msg.readByte(); // Lv - msg.readByte(); // unknown + msg.readInt8(); // Lv + msg.readInt8(); // unknown dstBeing->mWalkTime = tick_time; dstBeing->mFrame = 0; @@ -410,9 +410,9 @@ void BeingHandler::handleMessage(MessageIn &msg) case 0x0119: // Change in players look - logger->log("0x0119 %i %i %i %x %i", msg->readLong(), - msg->readShort(), msg->readShort(), msg->readShort(), - msg->readByte()); + logger->log("0x0119 %i %i %i %x %i", msg->readInt32(), + msg->readInt16(), msg->readInt16(), msg->readInt16(), + msg->readInt8()); break; */ } @@ -426,7 +426,7 @@ static void handleLooks(Player *being, MessageIn &msg) { Being::WEAPON_SPRITE, Being::HAT_SPRITE, Being::TOPCLOTHES_SPRITE, Being::BOTTOMCLOTHES_SPRITE }; - int mask = msg.readByte(); + int mask = msg.readInt8(); if (mask & (1 << 7)) { @@ -441,7 +441,7 @@ static void handleLooks(Player *being, MessageIn &msg) for (int i = 0; i < nb_slots; ++i) { if (!(mask & (1 << i))) continue; - int id = msg.readShort(); + int id = msg.readInt16(); being->setVisibleEquipment(slots[i], id); } } @@ -449,11 +449,11 @@ static void handleLooks(Player *being, MessageIn &msg) void BeingHandler::handleBeingEnterMessage(MessageIn &msg) { - int type = msg.readByte(); - int id = msg.readShort(); - Being::Action action = (Being::Action)msg.readByte(); - int px = msg.readShort(); - int py = msg.readShort(); + int type = msg.readInt8(); + int id = msg.readInt16(); + Being::Action action = (Being::Action)msg.readInt8(); + int px = msg.readInt16(); + int py = msg.readInt16(); Being *being; switch (type) @@ -472,16 +472,16 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) being->setName(name); } Player *p = static_cast< Player * >(being); - int hs = msg.readByte(), hc = msg.readByte(); + int hs = msg.readInt8(), hc = msg.readInt8(); p->setHairStyle(hs, hc); - p->setGender(msg.readByte()); + p->setGender(msg.readInt8()); handleLooks(p, msg); } break; case OBJECT_MONSTER: case OBJECT_NPC: { - int subtype = msg.readShort(); + int subtype = msg.readInt16(); being = beingManager->createBeing(id, type, subtype); } break; @@ -497,7 +497,7 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) void BeingHandler::handleBeingLeaveMessage(MessageIn &msg) { - Being *being = beingManager->findBeing(msg.readShort()); + Being *being = beingManager->findBeing(msg.readInt16()); if (!being) return; beingManager->destroyBeing(being); @@ -507,8 +507,8 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) { while (msg.getUnreadLength()) { - int id = msg.readShort(); - int flags = msg.readByte(); + int id = msg.readInt16(); + int flags = msg.readInt8(); Being *being = beingManager->findBeing(id); int sx = 0, sy = 0, dx = 0, dy = 0, speed = 0; if (flags & MOVING_POSITION) @@ -517,12 +517,12 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) msg.readCoordinates(sx2, sy2); sx = sx2 * 32 + 16; sy = sy2 * 32 + 16; - speed = msg.readByte(); + speed = msg.readInt8(); } if (flags & MOVING_DESTINATION) { - dx = msg.readShort(); - dy = msg.readShort(); + dx = msg.readInt16(); + dy = msg.readInt16(); if (!(flags & MOVING_POSITION)) { sx = dx; @@ -561,19 +561,19 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) void BeingHandler::handleBeingAttackMessage(MessageIn &msg) { - Being *being = beingManager->findBeing(msg.readShort()); + Being *being = beingManager->findBeing(msg.readInt16()); if (!being) return; being->setAction(Being::ATTACK); - being->setDirection(msg.readByte()); + being->setDirection(msg.readInt8()); } void BeingHandler::handleBeingsDamageMessage(MessageIn &msg) { while (msg.getUnreadLength()) { - Being *being = beingManager->findBeing(msg.readShort()); - int damage = msg.readShort(); + Being *being = beingManager->findBeing(msg.readInt16()); + int damage = msg.readInt16(); if (being) { being->takeDamage(damage); @@ -583,15 +583,15 @@ void BeingHandler::handleBeingsDamageMessage(MessageIn &msg) void BeingHandler::handleBeingActionChangeMessage(MessageIn &msg) { - Being* being = beingManager->findBeing(msg.readShort()); + Being* being = beingManager->findBeing(msg.readInt16()); if (!being) return; - being->setAction((Being::Action) msg.readByte()); + being->setAction((Being::Action) msg.readInt8()); } void BeingHandler::handleBeingLooksChangeMessage(MessageIn &msg) { - Being *being = beingManager->findBeing(msg.readShort()); + Being *being = beingManager->findBeing(msg.readInt16()); if (!being || being->getType() != Being::PLAYER) return; handleLooks(static_cast< Player * >(being), msg); } diff --git a/src/net/buysellhandler.cpp b/src/net/buysellhandler.cpp index 9b96ced7..57806edc 100644 --- a/src/net/buysellhandler.cpp +++ b/src/net/buysellhandler.cpp @@ -53,7 +53,7 @@ BuySellHandler::BuySellHandler() void BuySellHandler::handleMessage(MessageIn &msg) { - Being *being = beingManager->findBeing(msg.readShort()); + Being *being = beingManager->findBeing(msg.readInt16()); if (!being || being->getType() != Being::NPC) { return; @@ -70,7 +70,7 @@ void BuySellHandler::handleMessage(MessageIn &msg) sellDialog->setVisible(false); sellDialog->reset(); buySellDialog->setVisible(true); - current_npc = dynamic_cast(beingManager->findBeing(msg.readLong())); + current_npc = dynamic_cast(beingManager->findBeing(msg.readInt32())); break; #endif @@ -81,9 +81,9 @@ void BuySellHandler::handleMessage(MessageIn &msg) while (msg.getUnreadLength()) { - int itemId = msg.readShort(); - int amount = msg.readShort(); - int value = msg.readShort(); + int itemId = msg.readInt16(); + int amount = msg.readInt16(); + int value = msg.readInt16(); buyDialog->addItem(itemId, amount, value); } break; @@ -95,9 +95,9 @@ void BuySellHandler::handleMessage(MessageIn &msg) while (msg.getUnreadLength()) { - int itemId = msg.readShort(); - int amount = msg.readShort(); - int value = msg.readShort(); + int itemId = msg.readInt16(); + int amount = msg.readInt16(); + int value = msg.readInt16(); sellDialog->addItem(itemId, amount, value); } break; diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp index 0082db4c..bbfa82a4 100644 --- a/src/net/charserverhandler.cpp +++ b/src/net/charserverhandler.cpp @@ -65,7 +65,7 @@ void CharServerHandler::handleMessage(MessageIn &msg) case APMSG_CHAR_DELETE_RESPONSE: { - int errMsg = msg.readByte(); + int errMsg = msg.readInt8(); // Character deletion successful if (errMsg == ERRMSG_OK) { @@ -117,7 +117,7 @@ void CharServerHandler::handleMessage(MessageIn &msg) void CharServerHandler::handleCharCreateResponse(MessageIn &msg) { - int errMsg = msg.readByte(); + int errMsg = msg.readInt8(); // Character creation failed if (errMsg != ERRMSG_OK) @@ -168,15 +168,15 @@ void CharServerHandler::handleCharCreateResponse(MessageIn &msg) void CharServerHandler::handleCharSelectResponse(MessageIn &msg) { - int errMsg = msg.readByte(); + int errMsg = msg.readInt8(); if (errMsg == ERRMSG_OK) { token = msg.readString(32); std::string gameServer = msg.readString(); - unsigned short gameServerPort = msg.readShort(); + unsigned short gameServerPort = msg.readInt16(); std::string chatServer = msg.readString(); - unsigned short chatServerPort = msg.readShort(); + unsigned short chatServerPort = msg.readInt16(); logger->log("Game server: %s:%d", gameServer.c_str(), gameServerPort); logger->log("Chat server: %s:%d", chatServer.c_str(), chatServerPort); @@ -210,17 +210,17 @@ void CharServerHandler::handleCharSelectResponse(MessageIn &msg) LocalPlayer* CharServerHandler::readPlayerData(MessageIn &msg, int &slot) { LocalPlayer *tempPlayer = new LocalPlayer; - slot = msg.readByte(); // character slot + slot = msg.readInt8(); // character slot tempPlayer->mName = msg.readString(); - tempPlayer->setGender(msg.readByte()); - int hs = msg.readByte(), hc = msg.readByte(); + tempPlayer->setGender(msg.readInt8()); + int hs = msg.readInt8(), hc = msg.readInt8(); tempPlayer->setHairStyle(hs, hc); - tempPlayer->setLevel(msg.readByte()); - tempPlayer->setMoney(msg.readLong()); + tempPlayer->setLevel(msg.readInt8()); + tempPlayer->setMoney(msg.readInt32()); for (int i = 0; i < 7; i++) { - tempPlayer->setAttributeBase(i, msg.readByte()); + tempPlayer->setAttributeBase(i, msg.readInt8()); } return tempPlayer; diff --git a/src/net/chathandler.cpp b/src/net/chathandler.cpp index 713b8f22..9fe231e6 100644 --- a/src/net/chathandler.cpp +++ b/src/net/chathandler.cpp @@ -73,7 +73,7 @@ void ChatHandler::handleMessage(MessageIn &msg) switch (msg.getId()) { case GPMSG_SAY: - being = beingManager->findBeing(msg.readShort()); + being = beingManager->findBeing(msg.readInt16()); chatMsg = msg.readString(); if (being) { @@ -86,9 +86,9 @@ void ChatHandler::handleMessage(MessageIn &msg) } break; case CPMSG_REGISTER_CHANNEL_RESPONSE: - if(msg.readByte() == ERRMSG_OK) + if(msg.readInt8() == ERRMSG_OK) { - channelId = msg.readShort(); + channelId = msg.readInt16(); std::string channelName = msg.readString(); chatWindow->chatLog("Registered Channel " + channelName, BY_SERVER); chatWindow->addChannel(channelId, channelName); @@ -100,9 +100,9 @@ void ChatHandler::handleMessage(MessageIn &msg) } break; case CPMSG_ENTER_CHANNEL_RESPONSE: - if(msg.readByte() == ERRMSG_OK) + if(msg.readInt8() == ERRMSG_OK) { - channelId = msg.readShort(); + channelId = msg.readInt16(); channelName = msg.readString(); std::string announcement = msg.readString(); std::vector userList; @@ -126,7 +126,7 @@ void ChatHandler::handleMessage(MessageIn &msg) { channelName = msg.readString(); std::ostringstream numUsers; - numUsers << msg.readShort(); + numUsers << msg.readInt16(); if(channelName != "") { channelName += " - "; @@ -138,7 +138,7 @@ void ChatHandler::handleMessage(MessageIn &msg) break; case CPMSG_PUBMSG: - channelId = msg.readShort(); + channelId = msg.readInt16(); userNick = msg.readString(); chatMsg = msg.readString(); @@ -146,9 +146,9 @@ void ChatHandler::handleMessage(MessageIn &msg) break; case CPMSG_QUIT_CHANNEL_RESPONSE: - if(msg.readByte() == ERRMSG_OK) + if(msg.readInt8() == ERRMSG_OK) { - channelId = msg.readShort(); + channelId = msg.readInt16(); // remove the chat tab chatWindow->removeChannel(channelId); } @@ -156,8 +156,8 @@ void ChatHandler::handleMessage(MessageIn &msg) /* // Received speech from being case SMSG_BEING_CHAT: - chatMsgLength = msg.readShort() - 8; - being = beingManager->findBeing(msg.readLong()); + chatMsgLength = msg.readInt16() - 8; + being = beingManager->findBeing(msg.readInt32()); if (!being || chatMsgLength <= 0) { @@ -173,7 +173,7 @@ void ChatHandler::handleMessage(MessageIn &msg) case SMSG_PLAYER_CHAT: case SMSG_GM_CHAT: - chatMsgLength = msg.readShort() - 4; + chatMsgLength = msg.readInt16() - 4; if (chatMsgLength <= 0) { @@ -200,13 +200,13 @@ void ChatHandler::handleMessage(MessageIn &msg) break; case SMSG_WHO_ANSWER: - chatWindow->chatLog("Online users: " + toString(msg.readLong()), + chatWindow->chatLog("Online users: " + toString(msg.readInt32()), BY_SERVER); break; case 0x010c: // Display MVP player - msg.readLong(); // id + msg.readInt32(); // id chatWindow->chatLog("MVP player", BY_SERVER); break; */ diff --git a/src/net/chatserver/chatserver.cpp b/src/net/chatserver/chatserver.cpp index f24e4cd5..93fdc828 100644 --- a/src/net/chatserver/chatserver.cpp +++ b/src/net/chatserver/chatserver.cpp @@ -55,7 +55,7 @@ void Net::ChatServer::chat(short channel, const std::string &text) MessageOut msg(PCMSG_CHAT); msg.writeString(text); - msg.writeShort(channel); + msg.writeInt16(channel); connection->send(msg); } @@ -86,7 +86,7 @@ void Net::ChatServer::registerChannel(const std::string &name, { MessageOut msg(PCMSG_REGISTER_CHANNEL); - msg.writeByte(isPrivate); + msg.writeInt8(isPrivate); msg.writeString(name); msg.writeString(announcement); msg.writeString(password); @@ -98,7 +98,7 @@ void Net::ChatServer::unregisterChannel(short channel) { MessageOut msg(PCMSG_UNREGISTER_CHANNEL); - msg.writeShort(channel); + msg.writeInt16(channel); connection->send(msg); } @@ -117,7 +117,7 @@ void Net::ChatServer::quitChannel(short channel) { MessageOut msg(PCMSG_QUIT_CHANNEL); - msg.writeShort(channel); + msg.writeInt16(channel); connection->send(msg); } diff --git a/src/net/gameserver/gameserver.cpp b/src/net/gameserver/gameserver.cpp index 8f8ad8ac..e451d473 100644 --- a/src/net/gameserver/gameserver.cpp +++ b/src/net/gameserver/gameserver.cpp @@ -45,7 +45,7 @@ void Net::GameServer::logout(bool reconnectAccount) { MessageOut msg(PGMSG_DISCONNECT); - msg.writeByte((unsigned char) reconnectAccount); + msg.writeInt8((unsigned char) reconnectAccount); Net::GameServer::connection->send(msg); } diff --git a/src/net/gameserver/player.cpp b/src/net/gameserver/player.cpp index 95f7dff9..bb3567d3 100644 --- a/src/net/gameserver/player.cpp +++ b/src/net/gameserver/player.cpp @@ -39,90 +39,90 @@ void Net::GameServer::Player::say(const std::string &text) void Net::GameServer::Player::walk(int x, int y) { MessageOut msg(PGMSG_WALK); - msg.writeShort(x); - msg.writeShort(y); + msg.writeInt16(x); + msg.writeInt16(y); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::pickUp(int x, int y) { MessageOut msg(PGMSG_PICKUP); - msg.writeShort(x); - msg.writeShort(y); + msg.writeInt16(x); + msg.writeInt16(y); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::moveItem(int oldSlot, int newSlot, int amount) { MessageOut msg(PGMSG_MOVE_ITEM); - msg.writeByte(oldSlot); - msg.writeByte(newSlot); - msg.writeByte(amount); + msg.writeInt8(oldSlot); + msg.writeInt8(newSlot); + msg.writeInt8(amount); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::drop(int slot, int amount) { MessageOut msg(PGMSG_DROP); - msg.writeByte(slot); - msg.writeByte(amount); + msg.writeInt8(slot); + msg.writeInt8(amount); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::equip(int slot) { MessageOut msg(PGMSG_EQUIP); - msg.writeByte(slot); + msg.writeInt8(slot); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::unequip(int slot) { MessageOut msg(PGMSG_UNEQUIP); - msg.writeByte(slot); + msg.writeInt8(slot); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::useItem(int slot) { MessageOut msg(PGMSG_USE_ITEM); - msg.writeByte(slot); + msg.writeInt8(slot); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::attack(int direction) { MessageOut msg(PGMSG_ATTACK); - msg.writeByte(direction); + msg.writeInt8(direction); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::changeAction(Being::Action action) { MessageOut msg(PGMSG_ACTION_CHANGE); - msg.writeByte(action); + msg.writeInt8(action); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::talkToNPC(int id, bool restart) { MessageOut msg(restart ? PGMSG_NPC_TALK : PGMSG_NPC_TALK_NEXT); - msg.writeShort(id); + msg.writeInt16(id); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::selectFromNPC(int id, int choice) { MessageOut msg(PGMSG_NPC_SELECT); - msg.writeShort(id); - msg.writeByte(choice); + msg.writeInt16(id); + msg.writeInt8(choice); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::requestTrade(int id) { MessageOut msg(PGMSG_TRADE_REQUEST); - msg.writeShort(id); + msg.writeInt16(id); Net::GameServer::connection->send(msg); } @@ -135,22 +135,22 @@ void Net::GameServer::Player::acceptTrade(bool accept) void Net::GameServer::Player::tradeItem(int slot, int amount) { MessageOut msg(PGMSG_TRADE_ADD_ITEM); - msg.writeByte(slot); - msg.writeByte(amount); + msg.writeInt8(slot); + msg.writeInt8(amount); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::tradeMoney(int amount) { MessageOut msg(PGMSG_TRADE_SET_MONEY); - msg.writeLong(amount); + msg.writeInt32(amount); Net::GameServer::connection->send(msg); } void Net::GameServer::Player::tradeWithNPC(int item, int amount) { MessageOut msg(PGMSG_NPC_BUYSELL); - msg.writeShort(item); - msg.writeShort(amount); + msg.writeInt16(item); + msg.writeInt16(amount); Net::GameServer::connection->send(msg); } diff --git a/src/net/inventoryhandler.cpp b/src/net/inventoryhandler.cpp index 6fdb827d..d48a77a5 100644 --- a/src/net/inventoryhandler.cpp +++ b/src/net/inventoryhandler.cpp @@ -58,21 +58,21 @@ void InventoryHandler::handleMessage(MessageIn &msg) case GPMSG_INVENTORY: while (msg.getUnreadLength()) { - int slot = msg.readByte(); + int slot = msg.readInt8(); if (slot == 255) { - player_node->setMoney(msg.readLong()); + player_node->setMoney(msg.readInt32()); continue; } - int id = msg.readShort(); + int id = msg.readInt16(); if (slot < EQUIPMENT_SIZE) { player_node->mEquipment->setEquipment(slot, id); } else if (slot >= 32 && slot < 32 + INVENTORY_SIZE) { - int amount = id ? msg.readByte() : 0; + int amount = id ? msg.readInt8() : 0; player_node->setInvItem(slot - 32, id, amount); } }; diff --git a/src/net/itemhandler.cpp b/src/net/itemhandler.cpp index 7c4d3940..ea65bc3b 100644 --- a/src/net/itemhandler.cpp +++ b/src/net/itemhandler.cpp @@ -48,9 +48,9 @@ void ItemHandler::handleMessage(MessageIn &msg) { while (msg.getUnreadLength()) { - int itemId = msg.readShort(); - int x = msg.readShort(); - int y = msg.readShort(); + int itemId = msg.readInt16(); + int x = msg.readInt16(); + int y = msg.readInt16(); int id = (x << 16) | y; // dummy id if (itemId) diff --git a/src/net/loginhandler.cpp b/src/net/loginhandler.cpp index 90f2dbd5..260c117d 100644 --- a/src/net/loginhandler.cpp +++ b/src/net/loginhandler.cpp @@ -45,7 +45,7 @@ void LoginHandler::handleMessage(MessageIn &msg) { case APMSG_LOGIN_RESPONSE: { - int errMsg = msg.readByte(); + int errMsg = msg.readInt8(); // Successful login if (errMsg == ERRMSG_OK) { @@ -77,7 +77,7 @@ void LoginHandler::handleMessage(MessageIn &msg) break; case APMSG_REGISTER_RESPONSE: { - int errMsg = msg.readByte(); + int errMsg = msg.readInt8(); // Successful registration if (errMsg == ERRMSG_OK) { @@ -109,7 +109,7 @@ void LoginHandler::handleMessage(MessageIn &msg) break; case APMSG_RECONNECT_RESPONSE: { - int errMsg = msg.readByte(); + int errMsg = msg.readInt8(); // Successful login if (errMsg == ERRMSG_OK) { diff --git a/src/net/logouthandler.cpp b/src/net/logouthandler.cpp index d8b9d435..c7629490 100644 --- a/src/net/logouthandler.cpp +++ b/src/net/logouthandler.cpp @@ -48,7 +48,7 @@ void LogoutHandler::handleMessage(MessageIn &msg) { case APMSG_LOGOUT_RESPONSE: { - int errMsg = msg.readByte(); + int errMsg = msg.readInt8(); // Successful logout if (errMsg == ERRMSG_OK) @@ -86,7 +86,7 @@ void LogoutHandler::handleMessage(MessageIn &msg) break; case APMSG_UNREGISTER_RESPONSE: { - int errMsg = msg.readByte(); + int errMsg = msg.readInt8(); // Successful unregistration if (errMsg == ERRMSG_OK) { @@ -110,7 +110,7 @@ void LogoutHandler::handleMessage(MessageIn &msg) break; case GPMSG_DISCONNECT_RESPONSE: { - int errMsg = msg.readByte(); + int errMsg = msg.readInt8(); // Successful logout if (errMsg == ERRMSG_OK) { @@ -156,7 +156,7 @@ void LogoutHandler::handleMessage(MessageIn &msg) break; case CPMSG_DISCONNECT_RESPONSE: { - int errMsg = msg.readByte(); + int errMsg = msg.readInt8(); // Successful logout if (errMsg == ERRMSG_OK) { diff --git a/src/net/messagein.cpp b/src/net/messagein.cpp index e90084ff..b5d5b97a 100644 --- a/src/net/messagein.cpp +++ b/src/net/messagein.cpp @@ -33,10 +33,10 @@ MessageIn::MessageIn(const char *data, unsigned int length): mPos(0) { // Read the message ID - mId = readShort(); + mId = readInt16(); } -int MessageIn::readByte() +int MessageIn::readInt8() { int value = -1; if (mPos < mLength) @@ -47,7 +47,7 @@ int MessageIn::readByte() return value; } -int MessageIn::readShort() +int MessageIn::readInt16() { int value = -1; if (mPos + 2 <= mLength) @@ -60,7 +60,7 @@ int MessageIn::readShort() return value; } -int MessageIn::readLong() +int MessageIn::readInt32() { int value = -1; if (mPos + 4 <= mLength) @@ -88,7 +88,7 @@ std::string MessageIn::readString(int length) { // Get string length if (length < 0) { - length = readShort(); + length = readInt16(); } // Make sure the string isn't erroneus diff --git a/src/net/messagein.h b/src/net/messagein.h index 37103f2c..3cc45a23 100644 --- a/src/net/messagein.h +++ b/src/net/messagein.h @@ -43,9 +43,9 @@ class MessageIn int getId() { return mId; } /**< Returns the message ID. */ - int readByte(); /**< Reads a byte. */ - int readShort(); /**< Reads a short. */ - int readLong(); /**< Reads a long. */ + int readInt8(); /**< Reads a byte. */ + int readInt16(); /**< Reads a short. */ + int readInt32(); /**< Reads a long. */ /** * Reads a 3-byte block containing tile-based coordinates. diff --git a/src/net/messageout.cpp b/src/net/messageout.cpp index 208196e2..10f1b1d4 100644 --- a/src/net/messageout.cpp +++ b/src/net/messageout.cpp @@ -33,7 +33,7 @@ MessageOut::MessageOut(short id): mDataSize(0), mPos(0) { - writeShort(id); + writeInt16(id); } MessageOut::~MessageOut() @@ -51,14 +51,14 @@ MessageOut::expand(size_t bytes) } void -MessageOut::writeByte(char value) +MessageOut::writeInt8(char value) { expand(mPos + 1); mData[mPos] = value; mPos += 1; } -void MessageOut::writeShort(short value) +void MessageOut::writeInt16(short value) { expand(mPos + 2); uint16_t t = ENET_HOST_TO_NET_16(value); @@ -67,7 +67,7 @@ void MessageOut::writeShort(short value) } void -MessageOut::writeLong(long value) +MessageOut::writeInt32(long value) { expand(mPos + 4); uint32_t t = ENET_HOST_TO_NET_32(value); @@ -82,7 +82,7 @@ MessageOut::writeString(const std::string &string, int length) if (length < 0) { // Write the length at the start if not fixed - writeShort(stringLength); + writeInt16(stringLength); length = stringLength; } else if (length < stringLength) diff --git a/src/net/messageout.h b/src/net/messageout.h index 82412a30..032db190 100644 --- a/src/net/messageout.h +++ b/src/net/messageout.h @@ -45,9 +45,9 @@ class MessageOut */ ~MessageOut(); - void writeByte(char value); /**< Writes a byte. */ - void writeShort(short value); /**< Writes a short. */ - void writeLong(long value); /**< Writes a long. */ + void writeInt8(char value); /**< Writes a byte. */ + void writeInt16(short value); /**< Writes a short. */ + void writeInt32(long value); /**< Writes a long. */ /** * Writes a string. If a fixed length is not given (-1), it is stored diff --git a/src/net/npchandler.cpp b/src/net/npchandler.cpp index 9cc93df1..a838c844 100644 --- a/src/net/npchandler.cpp +++ b/src/net/npchandler.cpp @@ -47,7 +47,7 @@ NPCHandler::NPCHandler() void NPCHandler::handleMessage(MessageIn &msg) { - Being *being = beingManager->findBeing(msg.readShort()); + Being *being = beingManager->findBeing(msg.readInt16()); if (!being || being->getType() != Being::NPC) { return; diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp index afaeca69..f6f7a8fa 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/playerhandler.cpp @@ -107,7 +107,7 @@ void PlayerHandler::handleMessage(MessageIn &msg) { // TODO: Implement reconnecting to another game server std::string token = msg.readString(32); std::string address = msg.readString(); - int port = msg.readShort(); + int port = msg.readInt16(); logger->log("Changing server to %s:%d", address.c_str(), port); } break; @@ -116,9 +116,9 @@ void PlayerHandler::handleMessage(MessageIn &msg) logger->log("ATTRIBUTE UPDATE:"); while (msg.getUnreadLength()) { - int stat = msg.readByte(); - int base = msg.readShort(); - int value = msg.readShort(); + int stat = msg.readInt8(); + int base = msg.readInt16(); + int value = msg.readInt16(); logger->log("%d set to %d %d", stat, base, value); if (stat == BASE_ATTR_HP) @@ -141,7 +141,7 @@ void PlayerHandler::handleMessage(MessageIn &msg) /* case SMSG_PLAYER_ARROW_MESSAGE: { - Sint16 type = msg.readShort(); + Sint16 type = msg.readInt16(); switch (type) { case 0: @@ -162,8 +162,8 @@ void PlayerHandler::handleMapChangeMessage(MessageIn &msg) { std::string mapName = msg.readString(); - unsigned short x = msg.readShort(); - unsigned short y = msg.readShort(); + unsigned short x = msg.readInt16(); + unsigned short y = msg.readInt16(); logger->log("Changing map to %s (%d, %d)", mapName.c_str(), x, y); diff --git a/src/net/skillhandler.cpp b/src/net/skillhandler.cpp index 50150ca8..8a19fe45 100644 --- a/src/net/skillhandler.cpp +++ b/src/net/skillhandler.cpp @@ -45,20 +45,20 @@ void SkillHandler::handleMessage(MessageIn &msg) { #if 0 case SMSG_PLAYER_SKILLS: - msg.readShort(); // length + msg.readInt16(); // length skillCount = (msg.getLength() - 4) / 37; skillDialog->cleanList(); for (int k = 0; k < skillCount; k++) { - Sint16 skillId = msg.readShort(); - msg.readShort(); // target type - msg.readShort(); // unknown - Sint16 level = msg.readShort(); - Sint16 sp = msg.readShort(); - msg.readShort(); // range + Sint16 skillId = msg.readInt16(); + msg.readInt16(); // target type + msg.readInt16(); // unknown + Sint16 level = msg.readInt16(); + Sint16 sp = msg.readInt16(); + msg.readInt16(); // range std::string skillName = msg.readString(24); - Sint8 up = msg.readByte(); + Sint8 up = msg.readInt8(); if (level != 0 || up != 0) { @@ -76,11 +76,11 @@ void SkillHandler::handleMessage(MessageIn &msg) // Action failed (ex. sit because you have not reached the // right level) CHATSKILL action; - action.skill = msg.readShort(); - action.bskill = msg.readShort(); - action.unused = msg.readShort(); // unknown - action.success = msg.readByte(); - action.reason = msg.readByte(); + action.skill = msg.readInt16(); + action.bskill = msg.readInt16(); + action.unused = msg.readInt16(); // unknown + action.success = msg.readInt8(); + action.reason = msg.readInt8(); if (action.success != SKILL_FAILED && action.bskill == BSKILL_EMOTE) { diff --git a/src/net/tradehandler.cpp b/src/net/tradehandler.cpp index db07b786..b659f8a4 100644 --- a/src/net/tradehandler.cpp +++ b/src/net/tradehandler.cpp @@ -76,7 +76,7 @@ void TradeHandler::handleMessage(MessageIn &msg) { case GPMSG_TRADE_REQUEST: { - Being *being = beingManager->findBeing(msg.readShort()); + Being *being = beingManager->findBeing(msg.readInt16()); if (!being) { Net::GameServer::Player::acceptTrade(false); @@ -92,13 +92,13 @@ void TradeHandler::handleMessage(MessageIn &msg) case GPMSG_TRADE_ADD_ITEM: { - int type = msg.readShort(); - int amount = msg.readByte(); + int type = msg.readInt16(); + int amount = msg.readInt8(); tradeWindow->addItem(type, false, amount); } break; case GPMSG_TRADE_SET_MONEY: - tradeWindow->setMoney(msg.readLong()); + tradeWindow->setMoney(msg.readInt32()); break; case GPMSG_TRADE_START: diff --git a/src/npc.cpp b/src/npc.cpp index 980f1c8b..8e0b00a5 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -85,8 +85,8 @@ NPC::buy() // XXX Convert for new server /* MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST); - outMsg.writeLong(mId); - outMsg.writeByte(0); + outMsg.writeInt32(mId); + outMsg.writeInt8(0); */ } @@ -96,7 +96,7 @@ NPC::sell() // XXX Convert for new server /* MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST); - outMsg.writeLong(mId); - outMsg.writeByte(1); + outMsg.writeInt32(mId); + outMsg.writeInt8(1); */ } -- cgit v1.2.3-70-g09d2 From 1f2b8d3d4c36c3cf30187633e4cf5bb5d0012e7c Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Tue, 18 Dec 2007 01:27:27 +0000 Subject: Updated attribute system to the latest design decisions (removed charisma, kept agility in) --- ChangeLog | 9 +++++++++ src/gui/char_select.cpp | 16 +++++++--------- src/gui/char_select.h | 8 ++++---- src/gui/status.cpp | 17 ++++++----------- src/gui/status.h | 8 ++++---- src/localplayer.h | 1 - src/net/accountserver/account.cpp | 3 +-- src/net/accountserver/account.h | 2 +- src/net/beinghandler.cpp | 1 + 9 files changed, 33 insertions(+), 32 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 1e259291..aca00a69 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-12-18 Philipp Sehmisch + + * src/gui/char_select.cpp, src/gui/char_select.h, + src/gui/status.cpp, src/gui/status.h, src/localplayer.h, + src/net/accountserver/account.cpp, + src/net/accountserver/account.h, src/net/beinghandler.cpp: + Updated attribute system to the latest design decisions + (removed charisma, kept agility in) + 2007-12-09 Björn Steinbrink * src/CMakeLists.txt: Add missing source files. diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp index ccdf20c8..96140bb5 100644 --- a/src/gui/char_select.cpp +++ b/src/gui/char_select.cpp @@ -264,8 +264,7 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot): mAttributeLabel[3] = new gcn::Label(_("Vitality:")); mAttributeLabel[4] = new gcn::Label(_("Intelligence:")); mAttributeLabel[5] = new gcn::Label(_("Willpower:")); - mAttributeLabel[6] = new gcn::Label(_("Charisma:")); - for (int i=0; i<7; i++) + for (int i=0; i<6; i++) { mAttributeLabel[i]->setWidth(70); mAttributeSlider[i] = new Slider(1, 20); @@ -289,7 +288,7 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot): mPrevHairStyleButton->setPosition(90, 64); mNextHairStyleButton->setPosition(165, 64); mHairStyleLabel->setPosition(5, 70); - for (int i=0; i<7; i++) + for (int i=0; i<6; i++) { mAttributeSlider[i]->setValue(10); mAttributeSlider[i]->setDimension(gcn::Rectangle( 75, 140 + i*20, @@ -319,7 +318,7 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot): add(mNextHairStyleButton); add(mPrevHairStyleButton); add(mHairStyleLabel); - for (int i=0; i<7; i++) + for (int i=0; i<6; i++) { add(mAttributeSlider[i]); add(mAttributeValue[i]); @@ -359,8 +358,7 @@ CharCreateDialog::action(const gcn::ActionEvent &event) (int) mAttributeSlider[2]->getValue(), // DEX (int) mAttributeSlider[3]->getValue(), // VIT (int) mAttributeSlider[4]->getValue(), // INT - (int) mAttributeSlider[5]->getValue(), // WILL - (int) mAttributeSlider[6]->getValue() // CHAR + (int) mAttributeSlider[5]->getValue() // WILL ); } else { @@ -398,7 +396,7 @@ CharCreateDialog::getName() void CharCreateDialog::UpdateSliders() { - for (int i = 0; i < 7; i++) + for (int i = 0; i < 6; i++) { // Update captions mAttributeValue[i]->setCaption( @@ -407,7 +405,7 @@ void CharCreateDialog::UpdateSliders() } // Update distributed points - int pointsLeft = 70 - getDistributedPoints(); + int pointsLeft = 60 - getDistributedPoints(); if (pointsLeft == 0) { mAttributesLeft->setCaption(_("Character stats OK")); @@ -439,7 +437,7 @@ int CharCreateDialog::getDistributedPoints() { int points = 0; - for (int i = 0; i < 7; i++) + for (int i = 0; i < 6; i++) { points += (int) mAttributeSlider[i]->getValue(); } diff --git a/src/gui/char_select.h b/src/gui/char_select.h index 5d0b42fa..f2d6cbc4 100644 --- a/src/gui/char_select.h +++ b/src/gui/char_select.h @@ -140,9 +140,9 @@ class CharCreateDialog : public Window, public gcn::ActionListener gcn::Button *mPrevHairStyleButton; gcn::Label *mHairStyleLabel; - gcn::Slider *mAttributeSlider[7]; - gcn::Label *mAttributeLabel[7]; - gcn::Label *mAttributeValue[7]; + gcn::Slider *mAttributeSlider[6]; + gcn::Label *mAttributeLabel[6]; + gcn::Label *mAttributeValue[6]; gcn::Label *mAttributesLeft; gcn::Button *mCreateButton; @@ -153,7 +153,7 @@ class CharCreateDialog : public Window, public gcn::ActionListener int mSlot; - static const int mMaxPoints = 70; + static const int mMaxPoints = 60; int mUsedPoints; }; diff --git a/src/gui/status.cpp b/src/gui/status.cpp index 323a6b16..b0a92665 100644 --- a/src/gui/status.cpp +++ b/src/gui/status.cpp @@ -108,7 +108,7 @@ StatusWindow::StatusWindow(LocalPlayer *player): mStatsReflexPoints = new gcn::Label("% Reflex:"); */ // New labels - for (int i = 0; i < 7; i++) { + for (int i = 0; i < 6; i++) { mStatsLabel[i] = new gcn::Label(); mStatsDisplayLabel[i] = new gcn::Label(); mPointsLabel[i] = new gcn::Label("0"); @@ -131,7 +131,7 @@ StatusWindow::StatusWindow(LocalPlayer *player): int totalLabelY = mStatsTotalLabel->getY(); mStatsCostLabel->setPosition(170, totalLabelY); - for (int i = 0; i < 7; i++) + for (int i = 0; i < 6; i++) { mStatsLabel[i]->setPosition(5, mStatsTotalLabel->getY() + (i * 23) + 15); @@ -163,7 +163,7 @@ StatusWindow::StatusWindow(LocalPlayer *player): add(mStatsTitleLabel); add(mStatsTotalLabel); add(mStatsCostLabel); - for(int i = 0; i < 7; i++) + for(int i = 0; i < 6; i++) { add(mStatsLabel[i]); add(mStatsDisplayLabel[i]); @@ -224,19 +224,18 @@ void StatusWindow::update() // Stats Part // ---------- - const std::string attrNames[7] = { + const std::string attrNames[6] = { "Strength", "Agility", "Dexterity", "Vitality", "Intelligence", - "Willpower", - "Charisma" + "Willpower" }; int statusPoints = mPlayer->getAttributeIncreasePoints(); // Update labels - for (int i = 0; i < 7; i++) + for (int i = 0; i < 6; i++) { mStatsLabel[i]->setCaption(attrNames[i]); mStatsDisplayLabel[i]->setCaption( @@ -331,9 +330,5 @@ void StatusWindow::action(const gcn::ActionEvent &event) { mPlayer->raiseAttribute(LocalPlayer::WIL); } - else if (eventId == "CHR") - { - mPlayer->raiseAttribute(LocalPlayer::CHR); - } } } diff --git a/src/gui/status.h b/src/gui/status.h index 62cd8805..f3475263 100644 --- a/src/gui/status.h +++ b/src/gui/status.h @@ -90,15 +90,15 @@ class StatusWindow : public Window, public gcn::ActionListener /** * Stats captions. */ - gcn::Label *mStatsLabel[7]; - gcn::Label *mPointsLabel[7]; - gcn::Label *mStatsDisplayLabel[7]; + gcn::Label *mStatsLabel[6]; + gcn::Label *mPointsLabel[6]; + gcn::Label *mStatsDisplayLabel[6]; gcn::Label *mRemainingStatsPointsLabel; /** * Stats buttons. */ - gcn::Button *mStatsButton[7]; + gcn::Button *mStatsButton[6]; }; extern StatusWindow *statusWindow; diff --git a/src/localplayer.h b/src/localplayer.h index ddf5878e..b72438da 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -76,7 +76,6 @@ enum CHAR_ATTR_VITALITY, CHAR_ATTR_INTELLIGENCE, CHAR_ATTR_WILLPOWER, - CHAR_ATTR_CHARISMA, CHAR_ATTR_END, CHAR_ATTR_NB = CHAR_ATTR_END - CHAR_ATTR_BEGIN, diff --git a/src/net/accountserver/account.cpp b/src/net/accountserver/account.cpp index f0778b1d..9f3bfe5c 100644 --- a/src/net/accountserver/account.cpp +++ b/src/net/accountserver/account.cpp @@ -32,7 +32,7 @@ void Net::AccountServer::Account::createCharacter( const std::string &name, char hairStyle, char hairColor, char gender, short strength, short agility, short vitality, - short intelligence, short dexterity, short willpower, short charisma) + short intelligence, short dexterity, short willpower) { MessageOut msg(PAMSG_CHAR_CREATE); @@ -46,7 +46,6 @@ void Net::AccountServer::Account::createCharacter( msg.writeInt16(intelligence); msg.writeInt16(dexterity); msg.writeInt16(willpower); - msg.writeInt16(charisma); Net::AccountServer::connection->send(msg); } diff --git a/src/net/accountserver/account.h b/src/net/accountserver/account.h index 8af75eb9..6a8c4e08 100644 --- a/src/net/accountserver/account.h +++ b/src/net/accountserver/account.h @@ -35,7 +35,7 @@ namespace Net void createCharacter(const std::string &name, char hairStyle, char hairColor, char gender, short strength, short agility, short vitality, - short intelligence, short dexterity, short willpower, short charisma); + short intelligence, short dexterity, short willpower); void deleteCharacter(char slot); diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index a9f992af..37c02dc3 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -101,6 +101,7 @@ void BeingHandler::handleMessage(MessageIn &msg) handleBeingLooksChangeMessage(msg); break; + /* case SMSG_BEING_VISIBLE: case SMSG_BEING_MOVE: -- cgit v1.2.3-70-g09d2 From 90c0fb74a317e9c4181d35fead0c7c67e653d9ad Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Thu, 24 Jan 2008 01:50:13 +0000 Subject: Fixed broken communication of attack directions. --- ChangeLog | 5 +++++ src/net/beinghandler.cpp | 9 ++++++++- src/resources/spritedef.h | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index b41d69b4..edc1b310 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2007-01-24 Philipp Sehmisch + + * src/net/beinghandler.cpp, src/resources/spritedef.h: Fixed + broken communication of attack directions. + 2007-01-20 Philipp Sehmisch * data/items.xml: Added max-per-slot property to all items. diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 37c02dc3..879c8a46 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -566,7 +566,14 @@ void BeingHandler::handleBeingAttackMessage(MessageIn &msg) if (!being) return; being->setAction(Being::ATTACK); - being->setDirection(msg.readInt8()); + int direction = msg.readInt8(); + switch (direction) + { + case DIRECTION_UP: being->setDirection(Being::UP); break; + case DIRECTION_DOWN: being->setDirection(Being::DOWN); break; + case DIRECTION_LEFT: being->setDirection(Being::LEFT); break; + case DIRECTION_RIGHT: being->setDirection(Being::RIGHT); break; + } } void BeingHandler::handleBeingsDamageMessage(MessageIn &msg) diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h index 4f316875..5eeaf744 100644 --- a/src/resources/spritedef.h +++ b/src/resources/spritedef.h @@ -57,8 +57,8 @@ enum SpriteAction enum SpriteDirection { DIRECTION_DEFAULT = 0, - DIRECTION_DOWN, DIRECTION_UP, + DIRECTION_DOWN, DIRECTION_LEFT, DIRECTION_RIGHT, DIRECTION_INVALID -- cgit v1.2.3-70-g09d2 From 8f28636093d75b33cc5071e659291ac2ff54db8b Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Mon, 18 Feb 2008 19:17:57 +0000 Subject: Merged revisions 3762-3772,3776-3782 via svnmerge from https://themanaworld.svn.sourceforge.net/svnroot/themanaworld/tmw/branches/0.0 ........ r3762 | crush_tmw | 2007-12-04 00:25:25 +0100 (Tue, 04 Dec 2007) | 1 line Added/renamed some headgears for the christmas event. ........ r3763 | crush_tmw | 2007-12-04 14:51:20 +0100 (Tue, 04 Dec 2007) | 1 line tophead -> tophat ........ r3764 | b_lindeijer | 2007-12-05 21:20:25 +0100 (Wed, 05 Dec 2007) | 3 lines Fix drawing of very high fringe tiles by keeping track of the maximum tile height. ........ r3765 | crush_tmw | 2007-12-07 01:50:15 +0100 (Fri, 07 Dec 2007) | 1 line Added a new drop item for the christmas event. ........ r3768 | crush_tmw | 2007-12-09 20:45:53 +0100 (Sun, 09 Dec 2007) | 1 line New versions of funky hat and elf hat by QOAL. ........ r3769 | crush_tmw | 2007-12-10 03:22:59 +0100 (Mon, 10 Dec 2007) | 1 line Simplified player subsprite handling by treating equipment, hairstyle and base sprites alike. Implementing female hairstyles is now a purely content-sided task. ........ r3770 | crush_tmw | 2007-12-10 03:50:15 +0100 (Mon, 10 Dec 2007) | 1 line Added an option to show log messages in the chat console. ........ r3771 | crush_tmw | 2007-12-10 17:12:56 +0100 (Mon, 10 Dec 2007) | 1 line Implemented female hairstyles. ........ r3772 | b_lindeijer | 2007-12-10 21:42:11 +0100 (Mon, 10 Dec 2007) | 2 lines Include cassert header. ........ r3777 | crush_tmw | 2007-12-14 18:33:45 +0100 (Fri, 14 Dec 2007) | 1 line Fixed some errors with the filenames of the new items (unrelated to my eAthena problems). ........ r3778 | crush_tmw | 2007-12-14 19:21:39 +0100 (Fri, 14 Dec 2007) | 1 line fixed some more screwups with the new items. ........ r3780 | crush_tmw | 2007-12-14 19:40:12 +0100 (Fri, 14 Dec 2007) | 1 line Put new items in equipment.xml for backward compatibility with the last client release. ........ r3782 | b_lindeijer | 2007-12-17 16:59:04 +0100 (Mon, 17 Dec 2007) | 2 lines Fixed the item tags. ........ --- ChangeLog | 105 ++++++++++++++++++++++++++++++++++++++ src/being.cpp | 12 ++++- src/being.h | 8 +++ src/game.cpp | 5 ++ src/gui/chat.cpp | 3 ++ src/gui/chat.h | 3 +- src/gui/itemshortcutcontainer.cpp | 1 + src/gui/itemshortcutcontainer.h | 4 +- src/gui/itemshortcutwindow.cpp | 1 + src/gui/itemshortcutwindow.h | 1 + src/itemshortcut.cpp | 4 +- src/itemshortcut.h | 23 ++++----- src/log.cpp | 10 +++- src/log.h | 8 +++ src/map.cpp | 88 +++++++++++++------------------- src/map.h | 12 ++--- src/net/beinghandler.cpp | 28 +++++----- src/net/connection.cpp | 8 +++ src/player.cpp | 63 ++++++++--------------- src/player.h | 16 ++++-- 20 files changed, 265 insertions(+), 138 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 0798b7ea..73e1b2be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -173,6 +173,14 @@ Updated attribute system to the latest design decisions (removed charisma, kept agility in) +2007-12-14 Philipp Sehmisch + + * data/graphics/sprites/head-mask.png, + data/graphics/sprites/head-mask.xml, + data/graphics/sprites/head-mushroom.xml, + data/graphics/sprites/head-shroom.xml, data/items.xml, + data/equipment.xml: Fixed some problems with the new items. + 2007-12-12 Philipp Sehmisch * data/graphics/tiles/cave.png, data/graphics/tiles/cave_x2.png: @@ -194,10 +202,107 @@ tools/tmxcopy/zlibutils.h: Added my tmxcopy tool for copying parts of maps to other maps. +2007-12-10 Bjørn Lindeijer + + * src/being.cpp: Include cassert header. + +2007-12-10 Philipp Sehmisch + + * src/being.cpp, src/being.h, src/net/beinghandler.cpp, + src/net/charserverhandler.cpp, src/net/equipmenthandler.cpp, + src/player.cpp, src/player.h, data/items.xml: Simplified player + subsprite handling by treating equipment, hairstyle and base + sprites alike. This also enables gender-specific hairstyles. + * src/game.cpp, src/gui/chat.cpp, src/gui/chat.h, src/log.cpp, + src/log.h: Added an option to show log messages in the chat console. + * data/items.xml, + data/graphics/sprites/hairstyle1.png, + data/graphics/sprites/hairstyle1.xml, + data/graphics/sprites/hairstyle1-male.png, + data/graphics/sprites/hairstyle1-male.xml, + data/graphics/sprites/hairstyle1-female.png, + data/graphics/sprites/hairstyle1-female.xml, + data/graphics/sprites/hairstyle2.png, + data/graphics/sprites/hairstyle2.xml, + data/graphics/sprites/hairstyle2-male.png, + data/graphics/sprites/hairstyle2-male.xml, + data/graphics/sprites/hairstyle2-female.png, + data/graphics/sprites/hairstyle2-female.xml, + data/graphics/sprites/hairstyle3.png, + data/graphics/sprites/hairstyle3.xml, + data/graphics/sprites/hairstyle3-male.png, + data/graphics/sprites/hairstyle3-male.xml, + data/graphics/sprites/hairstyle3-female.png, + data/graphics/sprites/hairstyle3-female.xml, + data/graphics/sprites/hairstyle4.png, + data/graphics/sprites/hairstyle4.xml, + data/graphics/sprites/hairstyle4-male.png, + data/graphics/sprites/hairstyle4-male.xml, + data/graphics/sprites/hairstyle4-female.png, + data/graphics/sprites/hairstyle4-female.xml, + data/graphics/sprites/hairstyle5.png, + data/graphics/sprites/hairstyle5.xml, + data/graphics/sprites/hairstyle5-male.png, + data/graphics/sprites/hairstyle5-male.xml, + data/graphics/sprites/hairstyle5-female.png, + data/graphics/sprites/hairstyle5-female.xml, + data/graphics/sprites/hairstyle6.png, + data/graphics/sprites/hairstyle6.xml, + data/graphics/sprites/hairstyle6-male.png, + data/graphics/sprites/hairstyle6-male.xml, + data/graphics/sprites/hairstyle6-female.png, + data/graphics/sprites/hairstyle6-female.xml, + data/graphics/sprites/hairstyle7.png, + data/graphics/sprites/hairstyle7.xml, + data/graphics/sprites/hairstyle7-male.png, + data/graphics/sprites/hairstyle7-male.xml, + data/graphics/sprites/hairstyle7-female.png, + data/graphics/sprites/hairstyle7-female.xml: + Implemented female hairstyles. + +2007-12-09 Philipp Sehmisch + + * data/graphics/sprites/head-funkywinter.png, + data/graphics/sprites/head-funkywinter.xml, + data/graphics/sprites/head-xmaself.png, + data/graphics/sprites/head-xmaself.xml: New versions of funky hat + and elf hat by QOAL. + 2007-12-09 Björn Steinbrink * src/CMakeLists.txt: Add missing source files. +2007-12-07 Philipp Sehmisch + + * data/graphics/items/generic-santacookie.png, + data/items.xml: Added a new drop item for the christmas event. + +2007-12-05 Bjørn Lindeijer + + * src/map.cpp, src/map.h: Fix drawing of very high fringe tiles by + keeping track of the maximum tile height. + * src/itemshortcut.h, src/gui/itemshortcutcontainer.h, + src/gui/itemshortcutcontainer.cpp, src/gui/itemshortcutwindow.cpp, + src/gui/itemshortcutwindow.h, src/itemshortcut.cpp: Random cleanups. + +2007-12-04 Philipp Sehmisch + + * data/graphics/sprites/head-funkywinter.png, + data/graphics/sprites/head-funkywinter.xml, + data/graphics/sprites/head-mask.png, + data/graphics/sprites/head-mask.xml, + data/graphics/sprites/head-mushroom.png, + data/graphics/sprites/head-mushroom.xml, + data/graphics/sprites/head-shroom.png, + data/graphics/sprites/head-shroom.xml, + data/graphics/sprites/head-tophat.png, + data/graphics/sprites/head-tophat.xml, + data/graphics/sprites/head-xmaself.png, + data/graphics/sprites/head-xmaself.xml, + data/graphics/items/armor-head-xmaself.png, + data/graphics/items/armor-head-mask.png, + data/items.xml: Added/renamed some headgears for the christmas event. + 2007-11-21 Bjørn Lindeijer * src/properties.h, src/net/charserverhandler.cpp, src/being.h: Small diff --git a/src/being.cpp b/src/being.cpp index 22c56a6d..20684d8d 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -61,7 +61,9 @@ Being::Being(int id, int job, Map *map): mEquippedWeapon(NULL), mSpeechTime(0), mPx(0), mPy(0), - mSprites(VECTOREND_SPRITE, NULL) + mSprites(VECTOREND_SPRITE, NULL), + mSpriteIDs(VECTOREND_SPRITE, 0), + mSpriteColors(VECTOREND_SPRITE, "") { setMap(map); @@ -285,6 +287,14 @@ Being::setPath(const Path &path, int mod) } } +void +Being::setSprite(int slot, int id, const std::string &color) +{ + assert(slot >= BASE_SPRITE && slot < VECTOREND_SPRITE); + mSpriteIDs[slot] = id; + mSpriteColors[slot] = color; +} + void Being::setSpeech(const std::string &text, Uint32 time) { diff --git a/src/being.h b/src/being.h index 7c114cd9..a2d977db 100644 --- a/src/being.h +++ b/src/being.h @@ -188,6 +188,12 @@ class Being : public Sprite void setName(const std::string &name) { mName = name; } + /** + * Sets visible equipments for this being. + */ + virtual void + setSprite(int slot, int id, const std::string &color = ""); + /** * Makes this being take the next step of his path. */ @@ -349,6 +355,8 @@ class Being : public Sprite Sint32 mPx, mPy; /**< Pixel coordinates */ std::vector mSprites; + std::vector mSpriteIDs; + std::vector mSpriteColors; std::list mChildParticleEffects; private: diff --git a/src/game.cpp b/src/game.cpp index 9455e47a..7ae21009 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -197,6 +197,11 @@ void createGuiWindows() miniStatusWindow->setVisible(true); menuWindow->setVisible(true); itemShortcutWindow->setVisible(true); + + if (config.getValue("logToChat", 0)) + { + logger->setChatWindow(chatWindow); + } } /** diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp index f750df99..e9bed822 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -165,6 +165,9 @@ ChatWindow::chatLog(std::string line, int own, std::string channelName) tmp.nick += "Server: "; lineColor = "##7"; // Equiv. to BrowserBox::PINK break; + case BY_LOGGER: + lineColor = "##8"; // Equiv. to BrowserBox::GREY + break; } // Get the current system time diff --git a/src/gui/chat.h b/src/gui/chat.h index 304d5500..19795dd3 100644 --- a/src/gui/chat.h +++ b/src/gui/chat.h @@ -45,7 +45,8 @@ enum BY_GM = 0, BY_PLAYER = 1, BY_OTHER = 2, - BY_SERVER = 3 + BY_SERVER = 3, + BY_LOGGER }; #if 0 diff --git a/src/gui/itemshortcutcontainer.cpp b/src/gui/itemshortcutcontainer.cpp index 6a5d94fc..d86a99ef 100644 --- a/src/gui/itemshortcutcontainer.cpp +++ b/src/gui/itemshortcutcontainer.cpp @@ -18,6 +18,7 @@ * along with The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * $Id$ */ #include "itemshortcutcontainer.h" diff --git a/src/gui/itemshortcutcontainer.h b/src/gui/itemshortcutcontainer.h index 4b154cbb..c69525e0 100644 --- a/src/gui/itemshortcutcontainer.h +++ b/src/gui/itemshortcutcontainer.h @@ -18,6 +18,7 @@ * along with The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * $Id$ */ #ifndef _TMW_ITEMSHORTCUTCONTAINER_H__ @@ -26,8 +27,6 @@ #include #include -#include - class Image; class Item; @@ -109,7 +108,6 @@ class ItemShortcutContainer : public gcn::Widget, public gcn::MouseListener int mGridWidth, mGridHeight; bool mItemClicked; Item *mItemMoved; - }; #endif diff --git a/src/gui/itemshortcutwindow.cpp b/src/gui/itemshortcutwindow.cpp index dd97a7db..cf266290 100644 --- a/src/gui/itemshortcutwindow.cpp +++ b/src/gui/itemshortcutwindow.cpp @@ -18,6 +18,7 @@ * along with The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * $Id$ */ #include "itemshortcutwindow.h" diff --git a/src/gui/itemshortcutwindow.h b/src/gui/itemshortcutwindow.h index 83bc348d..1dde8686 100644 --- a/src/gui/itemshortcutwindow.h +++ b/src/gui/itemshortcutwindow.h @@ -18,6 +18,7 @@ * along with The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * $Id$ */ #ifndef _TMW_ITEMSHORTCUTWINDOW_H diff --git a/src/itemshortcut.cpp b/src/itemshortcut.cpp index 8a514c7e..12ae95f2 100644 --- a/src/itemshortcut.cpp +++ b/src/itemshortcut.cpp @@ -18,10 +18,12 @@ * along with The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * $Id$ */ #include "itemshortcut.h" +#include "item.h" #include "localplayer.h" #include "configuration.h" @@ -51,7 +53,7 @@ void ItemShortcut::load() if (itemId != -1) { - ItemPtr item = player_node->searchForItem(itemId); + Item* item = player_node->searchForItem(itemId); if (item) { mItems[i] = item; diff --git a/src/itemshortcut.h b/src/itemshortcut.h index d211c7f3..fecb7d86 100644 --- a/src/itemshortcut.h +++ b/src/itemshortcut.h @@ -18,20 +18,19 @@ * along with The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * $Id$ */ #ifndef _TMW_ITEMSHORTCUT_H__ #define _TMW_ITEMSHORTCUT_H__ -#include "item.h" - #define SHORTCUT_ITEMS 10 +class Item; + /** - * The item pointer + * The class which keeps track of the item shortcuts. */ -typedef Item* ItemPtr; - class ItemShortcut { public: @@ -55,7 +54,7 @@ class ItemShortcut * * @param index Index of the shortcut item. */ - ItemPtr getItem(int index) const + Item* getItem(int index) const { return mItems[index]; } /** @@ -67,7 +66,7 @@ class ItemShortcut /** * Returns the item that is currently selected. */ - ItemPtr getItemSelected() const + Item* getItemSelected() const { return mItemSelected; } /** @@ -92,20 +91,20 @@ class ItemShortcut * * @param item The item that is to be assigned. */ - void setItemSelected(ItemPtr item) + void setItemSelected(Item* item) { mItemSelected = item; } /** * A flag to check if the item is selected. */ bool isItemSelected() - { return (mItemSelected) ? true : false; } + { return mItemSelected; } /** * Remove a item from the shortcut. */ void removeItem(int index) - { mItems[index] = NULL; } + { mItems[index] = 0; } /** * Try to use the item specified by the index. @@ -120,8 +119,8 @@ class ItemShortcut */ void save(); - ItemPtr mItems[SHORTCUT_ITEMS]; /**< the items stored */ - ItemPtr mItemSelected; /**< the item held by cursor */ + Item* mItems[SHORTCUT_ITEMS]; /**< The items stored. */ + Item* mItemSelected; /**< The item held by cursor. */ }; diff --git a/src/log.cpp b/src/log.cpp index 63a34776..96630a96 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -34,8 +34,11 @@ #include "log.h" +#include "gui/chat.h" + Logger::Logger(): - mLogToStandardOut(false) + mLogToStandardOut(false), + mChatWindow(NULL) { } @@ -100,6 +103,11 @@ void Logger::log(const char *log_text, ...) std::cout << timeStr.str() << buf << std::endl; } + if (mChatWindow) + { + mChatWindow->chatLog(buf, BY_LOGGER); + } + // Delete temporary buffer delete[] buf; } diff --git a/src/log.h b/src/log.h index 36328527..dd1c0f91 100644 --- a/src/log.h +++ b/src/log.h @@ -25,6 +25,8 @@ #include #include +class ChatWindow; + /** * The Log Class : Useful to write debug or info messages */ @@ -51,6 +53,11 @@ class Logger */ void setLogToStandardOut(bool value) { mLogToStandardOut = value; } + /** + * Enables logging to chat window + */ + void setChatWindow(ChatWindow *window) { mChatWindow = window; } + /** * Enters a message in the log. The message will be timestamped. */ @@ -65,6 +72,7 @@ class Logger private: std::ofstream mLogFile; bool mLogToStandardOut; + ChatWindow *mChatWindow; }; extern Logger *logger; diff --git a/src/map.cpp b/src/map.cpp index ac570627..c2b0b9a1 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -65,6 +65,7 @@ struct Location Map::Map(int width, int height, int tileWidth, int tileHeight): mWidth(width), mHeight(height), mTileWidth(tileWidth), mTileHeight(tileHeight), + mMaxTileHeight(height), mOnClosedList(1), mOnOpenList(2), mLastScrollX(0.0f), mLastScrollY(0.0f) { @@ -87,8 +88,7 @@ Map::~Map() for_each(mOverlays.begin(), mOverlays.end(), make_dtor(mOverlays)); } -void -Map::initializeOverlays() +void Map::initializeOverlays() { ResourceManager *resman = ResourceManager::getInstance(); @@ -114,10 +114,12 @@ Map::initializeOverlays() } } -void -Map::addTileset(Tileset *tileset) +void Map::addTileset(Tileset *tileset) { mTilesets.push_back(tileset); + + if (tileset->getHeight() > mMaxTileHeight) + mMaxTileHeight = tileset->getHeight(); } bool spriteCompare(const Sprite *a, const Sprite *b) @@ -125,13 +127,9 @@ bool spriteCompare(const Sprite *a, const Sprite *b) return a->getPixelY() < b->getPixelY(); } -void -Map::draw(Graphics *graphics, int scrollX, int scrollY, int layer) +void Map::draw(Graphics *graphics, int scrollX, int scrollY, int layer) { - int startX = scrollX / 32; - int startY = scrollY / 32; - int endX = (graphics->getWidth() + scrollX + 31) / 32; - int endY = (graphics->getHeight() + scrollY + 31) / 32; + int endPixelY = graphics->getHeight() + scrollY + mTileHeight - 1; // If drawing the fringe layer, make sure sprites are sorted SpriteIterator si; @@ -139,13 +137,14 @@ Map::draw(Graphics *graphics, int scrollX, int scrollY, int layer) { mSprites.sort(spriteCompare); si = mSprites.begin(); - - // Increase endY to account for high fringe tiles - // TODO: Improve this hack so that it'll dynamically account for the - // highest tile. - endY += 2; + endPixelY += mMaxTileHeight - mTileHeight; } + int startX = scrollX / mTileWidth; + int startY = scrollY / mTileHeight; + int endX = (graphics->getWidth() + scrollX + mTileWidth - 1) / mTileWidth; + int endY = endPixelY / mTileHeight; + if (startX < 0) startX = 0; if (startY < 0) startY = 0; if (endX > mWidth) endX = mWidth; @@ -169,8 +168,9 @@ Map::draw(Graphics *graphics, int scrollX, int scrollY, int layer) Image *img = getTile(x, y, layer); if (img) { graphics->drawImage(img, - x * 32 - scrollX, - y * 32 - scrollY + 32 - img->getHeight()); + x * mTileWidth - scrollX, + y * mTileHeight - scrollY + + mTileHeight - img->getHeight()); } } } @@ -186,8 +186,8 @@ Map::draw(Graphics *graphics, int scrollX, int scrollY, int layer) } } -void -Map::drawOverlay(Graphics *graphics, float scrollX, float scrollY, int detail) +void Map::drawOverlay(Graphics *graphics, + float scrollX, float scrollY, int detail) { static int lastTick = tick_time; @@ -226,8 +226,7 @@ Map::drawOverlay(Graphics *graphics, float scrollX, float scrollY, int detail) }; } -void -Map::setTileWithGid(int x, int y, int layer, int gid) +void Map::setTileWithGid(int x, int y, int layer, int gid) { if (layer == 3) { @@ -251,19 +250,17 @@ class ContainsGidFunctor int gid; } containsGid; -Tileset* -Map::getTilesetWithGid(int gid) +Tileset* Map::getTilesetWithGid(int gid) const { containsGid.gid = gid; - TilesetIterator i = find_if(mTilesets.begin(), mTilesets.end(), + Tilesets::const_iterator i = find_if(mTilesets.begin(), mTilesets.end(), containsGid); return (i == mTilesets.end()) ? NULL : *i; } -Image* -Map::getTileWithGid(int gid) +Image* Map::getTileWithGid(int gid) const { Tileset *set = getTilesetWithGid(gid); @@ -274,20 +271,17 @@ Map::getTileWithGid(int gid) return NULL; } -void -Map::setWalk(int x, int y, bool walkable) +void Map::setWalk(int x, int y, bool walkable) { mMetaTiles[x + y * mWidth].walkable = walkable; } -bool -Map::getWalk(int x, int y) const +bool Map::getWalk(int x, int y) const { return !tileCollides(x, y) && !occupied(x, y); } -bool -Map::occupied(int x, int y) const +bool Map::occupied(int x, int y) const { Beings &beings = beingManager->getAll(); for (BeingIterator i = beings.begin(); i != beings.end(); i++) @@ -302,53 +296,45 @@ Map::occupied(int x, int y) const return false; } -bool -Map::tileCollides(int x, int y) const +bool Map::tileCollides(int x, int y) const { return !(contains(x, y) && mMetaTiles[x + y * mWidth].walkable); } -bool -Map::contains(int x, int y) const +bool Map::contains(int x, int y) const { return x >= 0 && y >= 0 && x < mWidth && y < mHeight; } -void -Map::setTile(int x, int y, int layer, Image *img) +void Map::setTile(int x, int y, int layer, Image *img) { mTiles[x + y * mWidth + layer * (mWidth * mHeight)] = img; } -Image* -Map::getTile(int x, int y, int layer) +Image* Map::getTile(int x, int y, int layer) const { return mTiles[x + y * mWidth + layer * (mWidth * mHeight)]; } -MetaTile* -Map::getMetaTile(int x, int y) +MetaTile* Map::getMetaTile(int x, int y) const { return &mMetaTiles[x + y * mWidth]; } -SpriteIterator -Map::addSprite(Sprite *sprite) +SpriteIterator Map::addSprite(Sprite *sprite) { mSprites.push_front(sprite); return mSprites.begin(); } -void -Map::removeSprite(SpriteIterator iterator) +void Map::removeSprite(SpriteIterator iterator) { mSprites.erase(iterator); } static int const basicCost = 100; -Path -Map::findPath(int startX, int startY, int destX, int destY) +Path Map::findPath(int startX, int startY, int destX, int destY) { // Path to be built up (empty by default) Path path; @@ -532,8 +518,7 @@ Map::findPath(int startX, int startY, int destX, int destY) return path; } -void -Map::addParticleEffect (std::string effectFile, int x, int y) +void Map::addParticleEffect (std::string effectFile, int x, int y) { ParticleEffectData newEffect; newEffect.file = effectFile; @@ -542,8 +527,7 @@ Map::addParticleEffect (std::string effectFile, int x, int y) particleEffects.push_back(newEffect); } -void -Map::initializeParticleEffects(Particle* particleEngine) +void Map::initializeParticleEffects(Particle* particleEngine) { for (std::list::iterator i = particleEffects.begin(); i != particleEffects.end(); diff --git a/src/map.h b/src/map.h index 17772847..d8cc2189 100644 --- a/src/map.h +++ b/src/map.h @@ -39,7 +39,6 @@ class Tileset; struct PATH_NODE; typedef std::vector Tilesets; -typedef Tilesets::iterator TilesetIterator; typedef std::list Sprites; typedef Sprites::iterator SpriteIterator; @@ -122,12 +121,12 @@ class Map : public Properties /** * Get tile ID. */ - Image *getTile(int x, int y, int layer); + Image *getTile(int x, int y, int layer) const; /** * Get tile reference. */ - MetaTile *getMetaTile(int x, int y); + MetaTile *getMetaTile(int x, int y) const; /** * Set walkability flag for a tile. @@ -202,14 +201,12 @@ class Map : public Properties * Converts a global tile id to the Image* pointing to the associated * tile image. */ - Image* - getTileWithGid(int gid); + Image* getTileWithGid(int gid) const; /** * Finds the tile set that a tile with the given global id is part of. */ - Tileset* - getTilesetWithGid(int gid); + Tileset* getTilesetWithGid(int gid) const; /** * Tells whether a tile is occupied by a being. @@ -223,6 +220,7 @@ class Map : public Properties int mWidth, mHeight; int mTileWidth, mTileHeight; + int mMaxTileHeight; MetaTile *mMetaTiles; Image **mTiles; diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 879c8a46..24db8454 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -140,9 +140,9 @@ void BeingHandler::handleMessage(MessageIn &msg) dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; dstBeing->setHairStyle(msg->readInt16()); - dstBeing->setVisibleEquipment( + dstBeing->setSprite( Being::WEAPON_SPRITE, msg->readInt16()); - dstBeing->setVisibleEquipment( + dstBeing->setSprite( Being::BOTTOMCLOTHES_SPRITE, msg->readInt16()); if (msg.getId() == SMSG_BEING_MOVE) @@ -153,8 +153,8 @@ void BeingHandler::handleMessage(MessageIn &msg) msg->readInt16(); // shield headTop = msg->readInt16(); headMid = msg->readInt16(); - dstBeing->setVisibleEquipment(Being::HAT_SPRITE, headTop); - dstBeing->setVisibleEquipment(Being::TOPCLOTHES_SPRITE, headMid); + dstBeing->setSprite(Being::HAT_SPRITE, headTop); + dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid); dstBeing->setHairColor(msg->readInt16()); msg->readInt16(); // unknown msg->readInt16(); // head dir @@ -294,18 +294,18 @@ void BeingHandler::handleMessage(MessageIn &msg) dstBeing->setHairStyle(id); break; case 2: - dstBeing->setVisibleEquipment(Being::WEAPON_SPRITE, id); + dstBeing->setSprite(Being::WEAPON_SPRITE, id); break; case 3: // Change lower headgear for eAthena, pants for us - dstBeing->setVisibleEquipment( + dstBeing->setSprite( Being::BOTTOMCLOTHES_SPRITE, id); break; case 4: // Change upper headgear for eAthena, hat for us - dstBeing->setVisibleEquipment( + dstBeing->setSprite( Being::HAT_SPRITE, id); break; case 5: // Change middle headgear for eathena, armor for us - dstBeing->setVisibleEquipment( + dstBeing->setSprite( Being::TOPCLOTHES_SPRITE, id); break; case 6: @@ -347,7 +347,7 @@ void BeingHandler::handleMessage(MessageIn &msg) dstBeing->setWalkSpeed(speed); dstBeing->mJob = job; dstBeing->setHairStyle(msg->readInt16()); - dstBeing->setVisibleEquipment( + dstBeing->setSprite( Being::WEAPON_SPRITE, msg->readInt16()); msg->readInt16(); // item id 2 headBottom = msg->readInt16(); @@ -367,10 +367,10 @@ void BeingHandler::handleMessage(MessageIn &msg) msg.readInt16(); // manner msg.readInt8(); // karma dstBeing->setSex(1 - msg.readInt8()); // sex - dstBeing->setVisibleEquipment( + dstBeing->setSprite( Being::BOTTOMCLOTHES_SPRITE, headBottom); - dstBeing->setVisibleEquipment(Being::HAT_SPRITE, headTop); - dstBeing->setVisibleEquipment(Being::TOPCLOTHES_SPRITE, headMid); + dstBeing->setSprite(Being::HAT_SPRITE, headTop); + dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid); if (msg.getId() == SMSG_PLAYER_MOVE) { @@ -434,7 +434,7 @@ static void handleLooks(Player *being, MessageIn &msg) // The equipment has to be cleared first. for (int i = 0; i < nb_slots; ++i) { - being->setVisibleEquipment(slots[i], 0); + being->setSprite(slots[i], 0); } } @@ -443,7 +443,7 @@ static void handleLooks(Player *being, MessageIn &msg) { if (!(mask & (1 << i))) continue; int id = msg.readInt16(); - being->setVisibleEquipment(slots[i], id); + being->setSprite(slots[i], id); } } diff --git a/src/net/connection.cpp b/src/net/connection.cpp index caaa0ce1..a016e07a 100644 --- a/src/net/connection.cpp +++ b/src/net/connection.cpp @@ -67,6 +67,14 @@ bool Net::Connection::connect(const std::string &address, short port) return false; } + ENetEvent event; + if (enet_host_service(mClient, &event, 10000) <= 0 || + event.type != ENET_EVENT_TYPE_CONNECT) + { + logger->log("Well...."); + return false; + } + return true; } diff --git a/src/player.cpp b/src/player.cpp index f928aeb1..050790e8 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -37,8 +37,9 @@ Player::Player(int id, int job, Map *map): Being(id, job, map), - mEquipmentSpriteIDs(VECTOREND_SPRITE, 0), - mGender(2), mHairStyle(0), mHairColor(0) + mGender(2), + mHairStyle(0), + mHairColor(0) { } @@ -59,45 +60,31 @@ Player::drawName(Graphics *graphics, int offsetX, int offsetY) graphics->drawText(mName, px + 15, py + 30, gcn::Graphics::CENTER); } -void Player::setGender(int sex) +void Player::setGender(int gender) { // Players can only be male or female - if (sex > 1) + if (gender > 1) { - logger->log("Warning: unsupported gender %i, assuming male.", sex); - sex = 0; + logger->log("Warning: unsupported gender %i, assuming male.", gender); + gender = 0; } - if (sex != mGender) + if (gender != mGender) { - mGender = sex; + mGender = gender; - // Reload base sprite - AnimatedSprite *newBaseSprite; - if (sex == 0) - { - newBaseSprite = AnimatedSprite::load( - "graphics/sprites/player_male_base.xml"); - } - else - { - newBaseSprite = AnimatedSprite::load( - "graphics/sprites/player_female_base.xml"); - } + /* Human base sprite. When implementing different races remove this + * line and set the base sprite when setting the race of the player + * character. + */ + setSprite(Being::BASE_SPRITE, -100); - delete mSprites[BASE_SPRITE]; - mSprites[BASE_SPRITE] = newBaseSprite; - - // Reload equipment + // Reload all subsprites for (int i = 1; i < VECTOREND_SPRITE; i++) { - if (i != HAIR_SPRITE && mEquipmentSpriteIDs.at(i) != 0) + if (mSpriteIDs.at(i) != 0) { - AnimatedSprite *newEqSprite = AnimatedSprite::load( - "graphics/sprites/" + ItemDB::get( - mEquipmentSpriteIDs.at(i)).getSprite(sex)); - delete mSprites[i]; - mSprites[i] = newEqSprite; + setSprite(i, mSpriteIDs.at(i), mSpriteColors.at(i)); } } } @@ -126,19 +113,12 @@ void Player::setHairStyle(int style, int color) "#460850,611967,e7b4ae", // dark purple }; - AnimatedSprite *newHairSprite = AnimatedSprite::load - (strprintf("graphics/sprites/hairstyle%d.xml|%s", style, colors[color])); - - if (newHairSprite) - newHairSprite->setDirection(getSpriteDirection()); - - delete mSprites[HAIR_SPRITE]; - mSprites[HAIR_SPRITE] = newHairSprite; + setSprite(HAIR_SPRITE, style * -1, colors[color]); setAction(mAction); } -void Player::setVisibleEquipment(int slot, int id) +void Player::setSprite(int slot, int id, const std::string &color) { // id = 0 means unequip if (id == 0) @@ -149,7 +129,8 @@ void Player::setVisibleEquipment(int slot, int id) else { AnimatedSprite *equipmentSprite = AnimatedSprite::load( - "graphics/sprites/" + ItemDB::get(id).getSprite(mGender)); + "graphics/sprites/" + ItemDB::get(id).getSprite(mGender) + + "|" + color); if (equipmentSprite) equipmentSprite->setDirection(getSpriteDirection()); @@ -165,5 +146,5 @@ void Player::setVisibleEquipment(int slot, int id) setAction(mAction); } - mEquipmentSpriteIDs[slot] = id; + Being::setSprite(slot, id, color); } diff --git a/src/player.h b/src/player.h index 4d4f53f5..eb642d20 100644 --- a/src/player.h +++ b/src/player.h @@ -49,7 +49,7 @@ class Player : public Being drawName(Graphics *graphics, int offsetX, int offsetY); /** - * Sets the sex for this player. + * Sets the gender for this player. */ void setGender(int); @@ -67,18 +67,24 @@ class Player : public Being /** * Sets the hair style and color for this player. + * + * NOTE: This method was necessary for convenience in the 0.0 client. + * It should be removed here since the server can provide the hair ID + * and coloring the same way it does for other equipment pieces. Then + * Being::setSprite can be used instead. */ void setHairStyle(int style, int color); /** * Sets visible equipments for this player. */ - void setVisibleEquipment(int slot, int id); + virtual void + setSprite(int slot, int id, const std::string &color = ""); private: - - std::vector mEquipmentSpriteIDs; - Uint8 mGender, mHairStyle, mHairColor; + Uint8 mGender; + Uint8 mHairStyle; + Uint8 mHairColor; }; #endif -- cgit v1.2.3-70-g09d2 From d3adc61aa4b4924f82d8cbc23bea26da7257da97 Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Fri, 22 Feb 2008 19:58:29 +0000 Subject: Handling gender with an enum everywhere. --- ChangeLog | 4 ++++ src/net/beinghandler.cpp | 2 +- src/net/charserverhandler.cpp | 2 +- src/player.cpp | 11 ++--------- src/player.h | 7 ++++--- src/resources/itemdb.cpp | 8 ++++---- src/resources/iteminfo.cpp | 2 +- src/resources/iteminfo.h | 6 ++++-- 8 files changed, 21 insertions(+), 21 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index fe4722d7..552e6ec7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,10 @@ on a patch by rodge) * src/gui/char_select.cpp, src/gui/char_select.h, src/player.h: Merged creation of female characters from Legend of Mazzeroth. + * src/net/beinghandler.cpp, src/net/charserverhandler.cpp, + src/player.cpp, src/player.h, src/resources/itemdb.cpp, + src/resources/iteminfo.cpp, src/resources/iteminfo.h: Handling gender + with an enum everywhere. 2008-02-21 Philipp Sehmisch diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 24db8454..38299b8d 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -475,7 +475,7 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) Player *p = static_cast< Player * >(being); int hs = msg.readInt8(), hc = msg.readInt8(); p->setHairStyle(hs, hc); - p->setGender(msg.readInt8()); + p->setGender(msg.readInt8() == GENDER_MALE ? GENDER_MALE : GENDER_FEMALE); handleLooks(p, msg); } break; diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp index c83b68f1..6cc9e384 100644 --- a/src/net/charserverhandler.cpp +++ b/src/net/charserverhandler.cpp @@ -212,7 +212,7 @@ LocalPlayer* CharServerHandler::readPlayerData(MessageIn &msg, int &slot) LocalPlayer *tempPlayer = new LocalPlayer; slot = msg.readInt8(); // character slot tempPlayer->mName = msg.readString(); - tempPlayer->setGender(msg.readInt8()); + tempPlayer->setGender(msg.readInt8() == GENDER_MALE ? GENDER_MALE : GENDER_FEMALE); int hs = msg.readInt8(), hc = msg.readInt8(); tempPlayer->setHairStyle(hs, hc); tempPlayer->setLevel(msg.readInt16()); diff --git a/src/player.cpp b/src/player.cpp index b1372925..b8789256 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -37,7 +37,7 @@ Player::Player(int id, int job, Map *map): Being(id, job, map), - mGender(2), + mGender(GENDER_UNSPECIFIED), mHairStyle(0), mHairColor(0) { @@ -60,15 +60,8 @@ Player::drawName(Graphics *graphics, int offsetX, int offsetY) graphics->drawText(mName, px + 15, py + 30, gcn::Graphics::CENTER); } -void Player::setGender(int gender) +void Player::setGender(Gender gender) { - // Players can only be male or female - if (gender > 1) - { - logger->log("Warning: unsupported gender %i, assuming male.", gender); - gender = 0; - } - if (gender != mGender) { mGender = gender; diff --git a/src/player.h b/src/player.h index 7e742a7a..f6ecbd59 100644 --- a/src/player.h +++ b/src/player.h @@ -31,7 +31,8 @@ class Map; enum Gender { GENDER_MALE = 0, - GENDER_FEMALE = 1 + GENDER_FEMALE = 1, + GENDER_UNSPECIFIED = 2 }; /** @@ -56,7 +57,7 @@ class Player : public Being /** * Sets the gender for this player. */ - void setGender(int); + void setGender(Gender); /** * Gets the hair color for this player. @@ -87,7 +88,7 @@ class Player : public Being setSprite(int slot, int id, const std::string &color = ""); private: - Uint8 mGender; + Gender mGender; Uint8 mHairStyle; Uint8 mHairColor; }; diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index 5f6846ba..d507987a 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -100,8 +100,8 @@ void ItemDB::load() mUnknown = new ItemInfo(); mUnknown->setName("Unknown item"); mUnknown->setImageName(""); - mUnknown->setSprite("error.xml", 0); - mUnknown->setSprite("error.xml", 1); + mUnknown->setSprite("error.xml", GENDER_MALE); + mUnknown->setSprite("error.xml", GENDER_FEMALE); ResourceManager *resman = ResourceManager::getInstance(); int size; @@ -241,12 +241,12 @@ void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node) if (gender == "male" || gender == "unisex") { - itemInfo->setSprite(filename, 0); + itemInfo->setSprite(filename, GENDER_MALE); } if (gender == "female" || gender == "unisex") { - itemInfo->setSprite(filename, 1); + itemInfo->setSprite(filename, GENDER_FEMALE); } } diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp index ad4c9797..4322db8d 100644 --- a/src/resources/iteminfo.cpp +++ b/src/resources/iteminfo.cpp @@ -26,7 +26,7 @@ #include "itemdb.h" const std::string& -ItemInfo::getSprite(int gender) const +ItemInfo::getSprite(Gender gender) const { if (mView) { diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h index 90675a17..43047094 100644 --- a/src/resources/iteminfo.h +++ b/src/resources/iteminfo.h @@ -30,6 +30,8 @@ #include "spritedef.h" +#include "../player.h" + enum EquipmentSoundEvent { EQUIP_EVENT_STRIKE, @@ -131,10 +133,10 @@ class ItemInfo void setView(int view) { mView = view; } - void setSprite(const std::string &animationFile, int gender) + void setSprite(const std::string &animationFile, Gender gender) { mAnimationFiles[gender] = animationFile; } - const std::string& getSprite(int gender) const; + const std::string& getSprite(Gender gender) const; void setWeaponType(int); -- cgit v1.2.3-70-g09d2 From 7dff43c3cc3733c7222e3f036b76e896aa86d4e9 Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Wed, 27 Feb 2008 13:54:18 +0000 Subject: Implemented provisorical player respawn. --- ChangeLog | 3 +++ src/net/beinghandler.cpp | 31 ++++++++++++++++++++++++++++++- src/net/gameserver/player.cpp | 11 +++++++++++ src/net/gameserver/player.h | 10 ++++++++++ src/net/protocol.h | 1 + 5 files changed, 55 insertions(+), 1 deletion(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 6a6fd91b..66be81d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,9 @@ po/tmw-pt.po, po/tmw-ru.po, po/tmw-sv.po, tmw.cbp: Fixed translation file names. * po/it.po: Some fixes by Shaili. + * src/net/beinghandler.cpp, src/net/gamehandler/player.cpp, + src/net/gamehandler/player.h, src/net/protocol.h: Implemented player + respawn. 2008-02-24 Philipp Sehmisch diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 38299b8d..28791975 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -37,6 +37,12 @@ #include "../particle.h" #include "../sound.h" +#include "../gui/ok_dialog.h" + +#include "../utils/gettext.h" + +#include "gameserver/player.h" + const int EMOTION_TIME = 150; /**< Duration of emotion icon */ BeingHandler::BeingHandler() @@ -592,9 +598,32 @@ void BeingHandler::handleBeingsDamageMessage(MessageIn &msg) void BeingHandler::handleBeingActionChangeMessage(MessageIn &msg) { Being* being = beingManager->findBeing(msg.readInt16()); + Being::Action action = (Being::Action) msg.readInt8(); if (!being) return; - being->setAction((Being::Action) msg.readInt8()); + being->setAction(action); + + if (action == Being::DEAD && being==player_node) + { + static char const *const deadMsg[] = + { + _("You are dead."), + _("We regret to inform you that your character was killed in battle."), + _("You are not that alive anymore."), + _("The cold hands of the grim reaper are grabbing for your soul."), + _("Game Over!"), + _("No, kids. Your character did not really die. It... err... went to a better place."), + _("Your plan of breaking your enemies weapon by bashing it with your throat failed."), + _("I guess this did not run too well."), + _("Do you want your possessions identified?"), // Nethack reference + _("Sadly, no trace of you was ever found..."), // Secret of Mana reference + + }; + std::string message(deadMsg[rand()%10]); + message.append(" Press OK to respawn"); + OkDialog *dlg = new OkDialog(_("You died"), message); + dlg->addActionListener(&(Net::GameServer::Player::respawnListener)); + } } void BeingHandler::handleBeingLooksChangeMessage(MessageIn &msg) diff --git a/src/net/gameserver/player.cpp b/src/net/gameserver/player.cpp index 67edc7ad..d8050d2b 100644 --- a/src/net/gameserver/player.cpp +++ b/src/net/gameserver/player.cpp @@ -29,6 +29,11 @@ #include "../messageout.h" #include "../protocol.h" +void RespawnRequestListener::action(const gcn::ActionEvent &event) +{ + Net::GameServer::Player::respawn(); +} + void Net::GameServer::Player::say(const std::string &text) { MessageOut msg(PGMSG_SAY); @@ -168,3 +173,9 @@ void Net::GameServer::Player::lowerAttribute(int attribute) msg.writeInt8(attribute); Net::GameServer::connection->send(msg); } + +void Net::GameServer::Player::respawn() +{ + MessageOut msg(PGMSG_RESPAWN); + Net::GameServer::connection->send(msg); +} diff --git a/src/net/gameserver/player.h b/src/net/gameserver/player.h index 7ebb2830..eea15c2b 100644 --- a/src/net/gameserver/player.h +++ b/src/net/gameserver/player.h @@ -26,8 +26,16 @@ #include "../../being.h" +#include + #include + +struct RespawnRequestListener : public gcn::ActionListener +{ + void action(const gcn::ActionEvent &event); +}; + namespace Net { namespace GameServer @@ -53,6 +61,8 @@ namespace Net void tradeWithNPC(int item, int amount); void raiseAttribute(int attribute); void lowerAttribute(int attribute); + void respawn(); + static RespawnRequestListener respawnListener; } } } diff --git a/src/net/protocol.h b/src/net/protocol.h index e6f5869b..eb65febe 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -90,6 +90,7 @@ enum { GPMSG_RAISE_ATTRIBUTE_RESPONSE = 0x0161, // B error, B attribute PGMSG_LOWER_ATTRIBUTE = 0x0170, // B attribute GPMSG_LOWER_ATTRIBUTE_RESPONSE = 0x0171, // B error, B attribute + PGMSG_RESPAWN = 0x0180, // - GPMSG_BEING_ENTER = 0x0200, // B type, W being id, B action, W*2 position // player: S name, B hair style, B hair color, B gender, B item bitmask, { W item id }* // monster: W type id -- cgit v1.2.3-70-g09d2 From 196f05bcc5b83bf583eb164cd788f9c3999995a4 Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Wed, 27 Feb 2008 14:53:03 +0000 Subject: made the string " Press OK to respawn." translateable. --- src/net/beinghandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net/beinghandler.cpp') diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 28791975..25d7b6a0 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -620,7 +620,7 @@ void BeingHandler::handleBeingActionChangeMessage(MessageIn &msg) }; std::string message(deadMsg[rand()%10]); - message.append(" Press OK to respawn"); + message.append(_(" Press OK to respawn")); OkDialog *dlg = new OkDialog(_("You died"), message); dlg->addActionListener(&(Net::GameServer::Player::respawnListener)); } -- cgit v1.2.3-70-g09d2 From f07cfeff7bcf84029b7117943eb948096647e4b2 Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Tue, 4 Mar 2008 06:14:00 +0000 Subject: Added HP regeneration and new death messages. --- ChangeLog | 6 ++++++ src/localplayer.h | 15 ++++++++------- src/net/beinghandler.cpp | 5 ++++- 3 files changed, 18 insertions(+), 8 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 7146d4f4..5b433fe5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-03-03 Philipp Sehmisch + + * src/localplayer.h: Added natural HP regeneration + * src/net/beinghandler.cpp: Added 3 new death messages which were + suggested by dabe and blueberry on the forum. + 2008-03-03 Philipp Sehmisch * src/gui/skill.cpp, src/gui/skill.h: Skill gui beautifications by diff --git a/src/localplayer.h b/src/localplayer.h index d850ed5f..9b4c7eb3 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -49,6 +49,7 @@ BASE_ATTR_BEGIN = 0, BASE_ATTR_EVADE, /**< Ability to avoid hits. */ BASE_ATTR_HIT, /**< Ability to hit stuff. */ BASE_ATTR_HP, /**< Hit Points (Base value: maximum, Modded value: current) */ + BASE_ATTR_HP_REGEN,/**< number of HP regenerated every 10 game ticks */ BASE_ATTR_END, BASE_ATTR_NB = BASE_ATTR_END - BASE_ATTR_BEGIN, @@ -150,34 +151,34 @@ class LocalPlayer : public Player */ virtual void drawName(Graphics *, int, int) {}; - + /** * Adds a guild to the local player. */ void addGuild(short guildId, bool inviteRights); - + /** * Removers a guild from the local player. */ void removeGuild(short guildId); - + /** * Finds a guild the local player belongs to, by the guildId * @return returns the guild associated with the guildId */ Guild* findGuildById(short guildId); - + /** * Finds a guild the local player belongs to, by the guild's name. * @return returns the guild with that name */ Guild* findGuildByName(const std::string &guildName); - + /** * Get number of guilds the player belongs to */ short getNumberOfGuilds(); - + /** * Check the player has permission to invite users */ @@ -367,7 +368,7 @@ class LocalPlayer : public Player protected: void walk(unsigned char dir); - + // Character guild information std::vector mGuilds; diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 25d7b6a0..3e55cce9 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -617,9 +617,12 @@ void BeingHandler::handleBeingActionChangeMessage(MessageIn &msg) _("I guess this did not run too well."), _("Do you want your possessions identified?"), // Nethack reference _("Sadly, no trace of you was ever found..."), // Secret of Mana reference + _("Annihilated."), // Final Fantasy VI reference + _("Looks like you got your head handed to you."), //Earthbound reference + _("You screwed up again, dump your body down the tubes and get you another one.") // Leisure Suit Larry 1 Reference }; - std::string message(deadMsg[rand()%10]); + std::string message(deadMsg[rand()%13]); message.append(_(" Press OK to respawn")); OkDialog *dlg = new OkDialog(_("You died"), message); dlg->addActionListener(&(Net::GameServer::Player::respawnListener)); -- cgit v1.2.3-70-g09d2 From 4e2ced304a2013808b2481cceb7622848b073e5b Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Sun, 9 Mar 2008 20:41:27 +0000 Subject: Implemented possibility to rotate particle emitters. Implemented interpretation of the attacktype parameter of attack messages and visualize monster attacks other than id 1 with a particle effect. Prepared to get attack particle effects and animation types from the monster database. --- ChangeLog | 12 ++++++++++++ src/being.cpp | 2 +- src/being.h | 2 +- src/monster.cpp | 27 ++++++++++++++++++++++++--- src/monster.h | 2 +- src/net/beinghandler.cpp | 9 +++++++-- src/particle.cpp | 4 ++-- src/particle.h | 2 +- src/particleemitter.cpp | 9 ++++----- src/particleemitter.h | 2 +- src/resources/monsterinfo.cpp | 15 +++++++++++++++ src/resources/monsterinfo.h | 8 ++++++++ src/utils/minmax.h | 21 +++++++++++++++++++++ 13 files changed, 98 insertions(+), 17 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 0df6b3fc..658239ba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2008-03-09 Philipp Sehmisch + + * src/particle.cpp, src/particle.h, src/particleemitter.cpp, + src/particleemitter.h, src/utils/minmax.h: Implemented possibility + to rotate particle emitters. + * src/being.cpp, src/being.h, src/monster.cpp, src/monster.h, + src/net/beinghandler.cpp, src/resources/monsterinfo.cpp, + src/resources/monsterinfo.h: Implemented interpretation of the + attacktype parameter of attack messages and visualize monster attacks + other than id 1 with a particle effect. Prepared to get attack particle + effects and animation types from the monster database. + 2008-03-06 David Athay * src/net/guildhandler.cpp, src/net/guildhandler.hpp: Fixed diff --git a/src/being.cpp b/src/being.cpp index 20684d8d..a55158c6 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -373,7 +373,7 @@ Being::controlParticle(Particle *particle) } void -Being::setAction(Action action) +Being::setAction(Action action, int attackType) { SpriteAction currentAction = ACTION_INVALID; switch (action) diff --git a/src/being.h b/src/being.h index a2d977db..0b56994e 100644 --- a/src/being.h +++ b/src/being.h @@ -262,7 +262,7 @@ class Being : public Sprite * Sets the current action. */ virtual void - setAction(Action action); + setAction(Action action, int attackType = 0); /** * Returns the direction the being is facing. diff --git a/src/monster.cpp b/src/monster.cpp index ae749017..5fbcfaea 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -25,6 +25,7 @@ #include "animatedsprite.h" #include "game.h" +#include "particle.h" #include "sound.h" #include "resources/monsterdb.h" @@ -50,9 +51,11 @@ Monster::getType() const } void -Monster::setAction(Action action) +Monster::setAction(Action action, int attackType) { SpriteAction currentAction = ACTION_INVALID; + int rotation = 0; + std::string particleEffect; switch (action) { @@ -64,8 +67,26 @@ Monster::setAction(Action action) sound.playSfx(getInfo().getSound(MONSTER_EVENT_DIE)); break; case ATTACK: - currentAction = ACTION_ATTACK; - mSprites[BASE_SPRITE]->reset(); + currentAction = getInfo().getAttackAction(attackType); + + //attack particle effect + particleEffect = getInfo().getAttackParticleEffect(attackType); + if (particleEffect != "") + { + switch (mDirection) + { + case DOWN: rotation = 0; break; + case LEFT: rotation = 90; break; + case UP: rotation = 180; break; + case RIGHT: rotation = 270; break; + default: break; + } + mSprites[BASE_SPRITE]->reset(); + Particle *p; + p = particleEngine->addEffect( + particleEffect, 0, 0, rotation); + controlParticle(p); + } break; case STAND: currentAction = ACTION_STAND; diff --git a/src/monster.h b/src/monster.h index fc46e11a..585f6f09 100644 --- a/src/monster.h +++ b/src/monster.h @@ -33,7 +33,7 @@ class Monster : public Being public: Monster(Uint16 id, Uint16 job, Map *map); - virtual void setAction(Action action); + virtual void setAction(Action action, int attackType); virtual Type getType() const; diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 3e55cce9..05795cb1 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -569,10 +569,11 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) void BeingHandler::handleBeingAttackMessage(MessageIn &msg) { Being *being = beingManager->findBeing(msg.readInt16()); + int direction = msg.readInt8(); + int attackType = msg.readInt8(); + if (!being) return; - being->setAction(Being::ATTACK); - int direction = msg.readInt8(); switch (direction) { case DIRECTION_UP: being->setDirection(Being::UP); break; @@ -580,6 +581,10 @@ void BeingHandler::handleBeingAttackMessage(MessageIn &msg) case DIRECTION_LEFT: being->setDirection(Being::LEFT); break; case DIRECTION_RIGHT: being->setDirection(Being::RIGHT); break; } + + logger->log("Attacktype: %d", attackType); + + being->setAction(Being::ATTACK, attackType); } void BeingHandler::handleBeingsDamageMessage(MessageIn &msg) diff --git a/src/particle.cpp b/src/particle.cpp index dac8c62e..11d91b47 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -212,7 +212,7 @@ Particle::update() Particle* Particle::addEffect(const std::string &particleEffectFile, - int pixelX, int pixelY) + int pixelX, int pixelY, int rotation) { Particle *newParticle = NULL; @@ -294,7 +294,7 @@ Particle::addEffect(const std::string &particleEffectFile, continue; ParticleEmitter *newEmitter; - newEmitter = new ParticleEmitter(emitterNode, newParticle, mMap); + newEmitter = new ParticleEmitter(emitterNode, newParticle, mMap, rotation); newParticle->addEmitter(newEmitter); } diff --git a/src/particle.h b/src/particle.h index 0dd34065..1859fe62 100644 --- a/src/particle.h +++ b/src/particle.h @@ -109,7 +109,7 @@ class Particle : public Sprite */ Particle* addEffect(const std::string &particleEffectFile, - int pixelX, int pixelY); + int pixelX, int pixelY, int rotation = 0); /** * Creates a standalone text particle. diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp index 6f66b632..f03490ac 100644 --- a/src/particleemitter.cpp +++ b/src/particleemitter.cpp @@ -38,7 +38,7 @@ #define SIN45 0.707106781f #define DEG_RAD_FACTOR 0.017453293f -ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map): +ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map, int rotation): mParticleImage(0) { mMap = map; @@ -98,14 +98,13 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map * else if (name == "horizontal-angle") { mParticleAngleHorizontal = readMinMax(propertyNode, 0.0f); - mParticleAngleHorizontal.minVal *= DEG_RAD_FACTOR; - mParticleAngleHorizontal.maxVal *= DEG_RAD_FACTOR; + mParticleAngleHorizontal += rotation; + mParticleAngleHorizontal *= DEG_RAD_FACTOR; } else if (name == "vertical-angle") { mParticleAngleVertical = readMinMax(propertyNode, 0.0f); - mParticleAngleVertical.minVal *= DEG_RAD_FACTOR; - mParticleAngleVertical.maxVal *= DEG_RAD_FACTOR; + mParticleAngleVertical *= DEG_RAD_FACTOR; } else if (name == "power") { diff --git a/src/particleemitter.h b/src/particleemitter.h index c9524488..f5ca6232 100644 --- a/src/particleemitter.h +++ b/src/particleemitter.h @@ -45,7 +45,7 @@ class ParticleEmitter /** * Constructor. */ - ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map); + ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map, int rotation = 0); /** * Copy Constructor (necessary for reference counting of particle images) diff --git a/src/resources/monsterinfo.cpp b/src/resources/monsterinfo.cpp index 0a7e18dc..0ee08e42 100644 --- a/src/resources/monsterinfo.cpp +++ b/src/resources/monsterinfo.cpp @@ -70,3 +70,18 @@ MonsterInfo::getSound(MonsterSoundEvent event) const return i->second->at(rand()%i->second->size()); } } + +const std::string & +MonsterInfo::getAttackParticleEffect(int attackType) const +{ + static std::string something("graphics/particles/attack.particle.xml"); + static std::string nothing(""); + + if (attackType > 1) return something; else return nothing; +} + +SpriteAction +MonsterInfo::getAttackAction(int attackType) const +{ + return ACTION_ATTACK; +} diff --git a/src/resources/monsterinfo.h b/src/resources/monsterinfo.h index 3034f10e..3dd18c0f 100644 --- a/src/resources/monsterinfo.h +++ b/src/resources/monsterinfo.h @@ -83,6 +83,14 @@ class MonsterInfo std::string getSound(MonsterSoundEvent event) const; + const std::string & + getAttackParticleEffect(int attackType) const; + + SpriteAction + getAttackAction(int attackType) const; + + + private: std::string mName; std::string mSprite; diff --git a/src/utils/minmax.h b/src/utils/minmax.h index 427c5da7..353c60e7 100644 --- a/src/utils/minmax.h +++ b/src/utils/minmax.h @@ -40,6 +40,27 @@ template struct MinMax set(val, val); } + bool operator+= (T arg) + { + minVal += arg; + maxVal += arg; + return true; + } + + bool operator-= (T arg) + { + minVal -= arg; + maxVal -= arg; + return true; + } + + bool operator*= (T arg) + { + minVal *= arg; + maxVal *= arg; + return true; + } + T value() { return (T)(minVal + (maxVal - minVal) * (rand() / ((double) RAND_MAX + 1))); -- cgit v1.2.3-70-g09d2 From fe474eb4fae9d89e3797d0ceaae6613798ce491f Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Thu, 13 Mar 2008 07:29:30 +0000 Subject: Synchronized pathfinding algorithmns with those used by the server to avoid asynchronisation. --- ChangeLog | 11 +++ src/being.cpp | 24 +++++-- src/being.h | 39 ++++++++-- src/gui/viewport.cpp | 8 ++- src/localplayer.cpp | 14 ++-- src/map.cpp | 179 +++++++++++++++++++++++++++++++++++----------- src/map.h | 46 ++++++++---- src/monster.cpp | 5 ++ src/monster.h | 15 ++++ src/net/beinghandler.cpp | 10 +-- src/net/playerhandler.cpp | 3 +- src/player.cpp | 5 ++ src/player.h | 14 +++- 13 files changed, 286 insertions(+), 87 deletions(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index f7760321..2eec14f3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-03-13 Philipp Sehmisch + + * src/being.cpp, src/being.h, src/gui/viewport.cpp, + src/localplayer.cpp, src/map.cpp, src/map.h, src/monster.cpp, + src/monster.h, src/net/beinghandler.cpp, src/net/playerhandler.cpp. + src/player.cpp, src/player.h: Unified route finding algorithmns + with those used by the server to minimize asynchronisation. + * src/map.cpp, src/gui/viewport.cpp: Improved path debugging tool + by displaying a raster and showing blocked tiles when it is + activated (alt+F). + 2008-03-12 David Athay * src/gui/guildwindow.cpp, src/gui/guildwindow.h, diff --git a/src/being.cpp b/src/being.cpp index a55158c6..55530080 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -47,12 +47,12 @@ int Being::instances = 0; ImageSet *Being::emotionSet = NULL; Being::Being(int id, int job, Map *map): - mJob(job), mX(0), mY(0), - mAction(STAND), - mWalkTime(0), mEmotion(0), mEmotionTime(0), mAttackSpeed(350), + mWalkTime(0), + mAction(STAND), + mJob(job), mId(id), mWalkSpeed(150), mSpeedModifier(1024), @@ -100,6 +100,14 @@ Being::~Being() } } +void Being::setPositionInPixels(int x, int y) +{ + mMap->freeTile(mX / 32, mY / 32, getBlockType()); + mX = x; + mY = y; + mMap->blockTile(x / 32, y / 32, getBlockType()); +} + void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY) { if (!mMap || (mX == dstX && mY == dstY)) @@ -130,7 +138,7 @@ void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY) } else { - p1 = mMap->findPath(srcX / 32, srcY / 32, dstX / 32, dstY / 32); + p1 = mMap->findPath(srcX / 32, srcY / 32, dstX / 32, dstY / 32, getWalkMask()); if (p1.empty()) { // No path, but don't teleport since it could be user input. @@ -190,7 +198,7 @@ void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY) for (Path::iterator i = p1.begin(), i_end = p1.end(); i != i_end; ++i) { // Look if it is worth passing by tile i. - Path p2 = mMap->findPath(mX / 32, mY / 32, i->x / 32, i->y / 32); + Path p2 = mMap->findPath(mX / 32, mY / 32, i->x / 32, i->y / 32, getWalkMask()); if (!p2.empty()) { int l1 = mMap->getMetaTile(i->x / 32, i->y / 32)->Gcost; @@ -343,9 +351,11 @@ Being::handleAttack() void Being::setMap(Map *map) { + // Remove sprite from potential previous map if (mMap) { + mMap->freeTile(mX / 32, mY / 32, getBlockType()); mMap->removeSprite(mSpriteIterator); } @@ -355,6 +365,7 @@ Being::setMap(Map *map) if (mMap) { mSpriteIterator = mMap->addSprite(this); + mMap->blockTile(mX / 32, mY / 32, getBlockType()); } // Clear particle effect list because child particles became invalid @@ -488,8 +499,7 @@ Being::nextStep() setDirection(dir); - mX = node.x; - mY = node.y; + setPositionInPixels(node.x, node.y); setAction(WALK); mWalkTime += mStepTime / 10; mStepTime = mWalkSpeed * (int)std::sqrt((double)mStepX * mStepX + (double)mStepY * mStepY) * diff --git a/src/being.h b/src/being.h index 0b56994e..f4cdc743 100644 --- a/src/being.h +++ b/src/being.h @@ -112,14 +112,13 @@ class Being : public Sprite enum { DOWN = 1, LEFT = 2, UP = 4, RIGHT = 8 }; std::string mName; /**< Name of character */ - Uint16 mJob; /**< Job (player job, npc, monster, ) */ - Uint16 mX, mY; /**< Pixel coordinates (tile center) */ - Action mAction; /**< Action the being is performing */ - Uint16 mWalkTime; + Uint16 mX, mY; /**< Pixel coordinates of tile center */ Uint8 mEmotion; /**< Currently showing emotion */ Uint8 mEmotionTime; /**< Time until emotion disappears */ - Uint16 mAttackSpeed; /**< Attack speed */ + Uint16 mWalkTime; + Action mAction; /**< Action the being is performing */ + Uint16 mJob; /**< Job (player job, npc, monster, ) */ /** * Constructor. @@ -264,6 +263,13 @@ class Being : public Sprite virtual void setAction(Action action, int attackType = 0); + /** + * Gets the current action. + */ + bool isAlive() { return mAction != DEAD; } + + int getWalkTime() { return mWalkTime; } + /** * Returns the direction the being is facing. */ @@ -297,6 +303,17 @@ class Being : public Sprite int getPixelY() const { return mPy; } + /** + * sets the position in pixels using pixel coordinates + */ + void setPositionInPixels(int x, int y); + + /** + * sets the position in pixels using tile coordinates + */ + void setPositionInTiles(int x, int y) + { setPositionInPixels(x * 32 + 16, y * 32 + 16); } + /** * Get the current X pixel offset. */ @@ -332,12 +349,24 @@ class Being : public Sprite */ void controlParticle(Particle *particle); + /** + * Gets the way the object is blocked by other objects + */ + virtual unsigned char getWalkMask() const + { return 0x00; } //can walk through everything + protected: /** * Sets the new path for this being. */ void setPath(const Path &path, int mod = 1024); + /** + * Gets the way the object blocks pathfinding for other objects + */ + virtual Map::BlockType getBlockType() const + { return Map::BLOCKTYPE_NONE; } + Uint16 mId; /**< Unique being id */ Uint16 mWalkSpeed; /**< Walking speed */ Uint16 mSpeedModifier; /**< Modifier to keep course on sync (1024 = normal speed) */ diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index 57c64cd6..d6c49fb2 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -221,6 +221,10 @@ Viewport::draw(gcn::Graphics *gcnGraphics) drawTargetCursor(graphics); mMap->draw(graphics, mCameraX, mCameraY, 1); mMap->draw(graphics, mCameraX, mCameraY, 2); + if (mShowDebugPath) + { + mMap->drawCollision(graphics, mCameraX, mCameraY); + } mMap->drawOverlay(graphics, mViewX, mViewY, (int) config.getValue("OverlayDetail", 2)); drawTargetName(graphics); @@ -335,7 +339,7 @@ Viewport::drawDebugPath(Graphics *graphics) Path debugPath = mMap->findPath( player_node->mX / 32, player_node->mY / 32, - mouseTileX, mouseTileY); + mouseTileX, mouseTileY, 0xFF); graphics->setColor(gcn::Color(255, 0, 0)); for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++) @@ -399,7 +403,7 @@ Viewport::mousePressed(gcn::MouseEvent &event) player_node->pickUp(item); } // Just walk around - else if (mMap->getWalk(tilex, tiley)) + else if (mMap->getWalk(tilex, tiley, player_node->getWalkMask())) { // XXX XXX XXX REALLY UGLY! Uint8 *keys = SDL_GetKeyState(NULL); diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 1614b7e7..aa3bb6ba 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -233,17 +233,17 @@ void LocalPlayer::walk(unsigned char dir) dx += 32; // Prevent skipping corners over colliding tiles - if (dx && mMap->tileCollides((mX + dx) / 32, mY / 32)) + if (dx && !mMap->getWalk((mX + dx) / 32, mY / 32, getWalkMask())) dx = 16 - mX % 32; - if (dy && mMap->tileCollides(mX / 32, (mY + dy) / 32)) + if (dy && !mMap->getWalk(mX / 32, (mY + dy) / 32, getWalkMask())) dy = 16 - mY % 32; // Choose a straight direction when diagonal target is blocked - if (dx && dy && !mMap->getWalk((mX + dx) / 32, (mY + dy) / 32)) + if (dx && dy && !mMap->getWalk((mX + dx) / 32, (mY + dy) / 32, getWalkMask())) dx = 16 - mX % 32; // Walk to where the player can actually go - if ((dx || dy) && mMap->getWalk((mX + dx) / 32, (mY + dy) / 32)) + if ((dx || dy) && mMap->getWalk((mX + dx) / 32, (mY + dy) / 32, getWalkMask())) { setDestination(mX + dx, mY + dy); } @@ -259,9 +259,9 @@ void LocalPlayer::setDestination(Uint16 x, Uint16 y) { // Fix coordinates so that the player does not seem to dig into walls. int tx = x / 32, ty = y / 32, fx = x % 32, fy = y % 32; - if (fx != 16 && mMap->tileCollides(tx + fx / 16 * 2 - 1, ty)) fx = 16; - if (fy != 16 && mMap->tileCollides(tx, ty + fy / 16 * 2 - 1)) fy = 16; - if (fx != 16 && fy != 16 && mMap->tileCollides(tx + fx / 16 * 2 - 1, ty + fy / 16 * 2 - 1)) fx = 16; + if (fx != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty, getWalkMask())) fx = 16; + if (fy != 16 && !mMap->getWalk(tx, ty + fy / 16 * 2 - 1, getWalkMask())) fy = 16; + if (fx != 16 && fy != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty + fy / 16 * 2 - 1, getWalkMask())) fx = 16; x = tx * 32 + fx; y = ty * 32 + fy; diff --git a/src/map.cpp b/src/map.cpp index c2b0b9a1..afa2bcc5 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -72,6 +72,11 @@ Map::Map(int width, int height, int tileWidth, int tileHeight): int size = mWidth * mHeight; mMetaTiles = new MetaTile[size]; + for (int i=0; i < NB_BLOCKTYPES; i++) + { + mOccupation[i] = new int[size]; + memset(mOccupation[i], 0, size * sizeof(int)); + } mTiles = new Image*[size * 3]; std::fill_n(mTiles, size * 3, (Image*)0); } @@ -81,6 +86,10 @@ Map::~Map() // clean up map data delete[] mMetaTiles; delete[] mTiles; + for (int i=0; i < NB_BLOCKTYPES; i++) + { + delete[] mOccupation[i]; + } // clean up tilesets for_each(mTilesets.begin(), mTilesets.end(), make_dtor(mTilesets)); mTilesets.clear(); @@ -186,6 +195,59 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY, int layer) } } +void Map::drawCollision(Graphics *graphics, int scrollX, int scrollY) +{ + int endPixelY = graphics->getHeight() + scrollY + mTileHeight - 1; + int startX = scrollX / mTileWidth; + int startY = scrollY / mTileHeight; + int endX = (graphics->getWidth() + scrollX + mTileWidth - 1) / mTileWidth; + int endY = endPixelY / mTileHeight; + + if (startX < 0) startX = 0; + if (startY < 0) startY = 0; + if (endX > mWidth) endX = mWidth; + if (endY > mHeight) endY = mHeight; + + for (int y = startY; y < endY; y++) + { + for (int x = startX; x < endX; x++) + { + graphics->setColor(gcn::Color(0, 0, 0, 64)); + graphics->drawRectangle(gcn::Rectangle( + x * mTileWidth - scrollX, + y * mTileWidth - scrollY, + 33, 33)); + + if (!getWalk(x, y, BLOCKMASK_WALL)) + { + graphics->setColor(gcn::Color(0, 0, 200, 64)); + graphics->fillRectangle(gcn::Rectangle( + x * mTileWidth - scrollX, + y * mTileWidth - scrollY, + 32, 32)); + } + + if (!getWalk(x, y, BLOCKMASK_MONSTER)) + { + graphics->setColor(gcn::Color(200, 0, 0, 64)); + graphics->fillRectangle(gcn::Rectangle( + x * mTileWidth - scrollX, + y * mTileWidth - scrollY, + 32, 32)); + } + + if (!getWalk(x, y, BLOCKMASK_CHARACTER)) + { + graphics->setColor(gcn::Color(0, 200, 0, 64)); + graphics->fillRectangle(gcn::Rectangle( + x * mTileWidth - scrollX, + y * mTileWidth - scrollY, + 32, 32)); + } + } + } +} + void Map::drawOverlay(Graphics *graphics, float scrollX, float scrollY, int detail) { @@ -231,7 +293,10 @@ void Map::setTileWithGid(int x, int y, int layer, int gid) if (layer == 3) { Tileset *set = getTilesetWithGid(gid); - setWalk(x, y, (!set || (gid - set->getFirstGid() == 0))); + if (set && (gid - set->getFirstGid() != 0)) + { + blockTile(x, y, BLOCKTYPE_WALL); + } } else if (layer < 3) { @@ -271,34 +336,69 @@ Image* Map::getTileWithGid(int gid) const return NULL; } -void Map::setWalk(int x, int y, bool walkable) +void Map::blockTile(int x, int y, BlockType type) { - mMetaTiles[x + y * mWidth].walkable = walkable; -} + if (type == BLOCKTYPE_NONE) return; + int tileNum = x + y * mWidth; + assert (tileNum <= mWidth * mHeight); -bool Map::getWalk(int x, int y) const -{ - return !tileCollides(x, y) && !occupied(x, y); + if ((++mOccupation[type][tileNum]) > 0) + { + switch (type) + { + case BLOCKTYPE_WALL: + mMetaTiles[tileNum].blockmask |= BLOCKMASK_WALL; + break; + case BLOCKTYPE_CHARACTER: + mMetaTiles[tileNum].blockmask |= BLOCKMASK_CHARACTER; + break; + case BLOCKTYPE_MONSTER: + mMetaTiles[tileNum].blockmask |= BLOCKMASK_MONSTER; + break; + default: + // shut up! + break; + } + } } -bool Map::occupied(int x, int y) const +void Map::freeTile(int x, int y, BlockType type) { - Beings &beings = beingManager->getAll(); - for (BeingIterator i = beings.begin(); i != beings.end(); i++) + if (type == BLOCKTYPE_NONE) return; + + int tileNum = x + y * mWidth; + assert (tileNum <= mWidth * mHeight); + + if ((--mOccupation[type][tileNum]) <= 0) { - // job 45 is a portal, they don't collide - if ((*i)->mX / 32 == x && (*i)->mY / 32 == y && (*i)->mJob != 45) + switch (type) { - return true; + case BLOCKTYPE_WALL: + mMetaTiles[tileNum].blockmask &= (BLOCKMASK_WALL xor 0xff); + break; + case BLOCKTYPE_CHARACTER: + mMetaTiles[tileNum].blockmask &= (BLOCKMASK_CHARACTER xor 0xff); + break; + case BLOCKTYPE_MONSTER: + mMetaTiles[tileNum].blockmask &= (BLOCKMASK_MONSTER xor 0xff); + break; + default: + // shut up! + break; } } - - return false; } -bool Map::tileCollides(int x, int y) const +bool Map::getWalk(int x, int y, char walkmask) const { - return !(contains(x, y) && mMetaTiles[x + y * mWidth].walkable); + // You can't walk outside of the map + if (x < 0 || y < 0 || x >= mWidth || y >= mHeight) + { + return false; + } + + // Check if the tile is walkable + return !(mMetaTiles[x + y * mWidth].blockmask & walkmask); } bool Map::contains(int x, int y) const @@ -334,17 +434,16 @@ void Map::removeSprite(SpriteIterator iterator) static int const basicCost = 100; -Path Map::findPath(int startX, int startY, int destX, int destY) +Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char walkmask, int maxCost) { // Path to be built up (empty by default) - Path path; + std::list path; // Declare open list, a list with open tiles sorted on F cost std::priority_queue openList; - // Return empty path when destination collides - if (tileCollides(destX, destY)) - return path; + // Return when destination not walkable + if (!getWalk(destX, destY, walkmask)) return path; // Reset starting tile's G cost to 0 MetaTile *startTile = getMetaTile(startX, startY); @@ -358,19 +457,20 @@ Path Map::findPath(int startX, int startY, int destX, int destY) // Keep trying new open tiles until no more tiles to try or target found while (!openList.empty() && !foundPath) { - // Take the location with the lowest F cost from the open list. + // Take the location with the lowest F cost from the open list, and + // add it to the closed list. Location curr = openList.top(); openList.pop(); // If the tile is already on the closed list, this means it has already // been processed with a shorter path to the start point (lower G cost) - if (curr.tile->whichList == mOnClosedList) + if (curr.tile->whichList == onClosedList) { continue; } // Put the current tile on the closed list - curr.tile->whichList = mOnClosedList; + curr.tile->whichList = onClosedList; // Check the adjacent tiles for (int dy = -1; dy <= 1; dy++) @@ -383,28 +483,28 @@ Path Map::findPath(int startX, int startY, int destX, int destY) // Skip if if we're checking the same tile we're leaving from, // or if the new location falls outside of the map boundaries - if ((dx == 0 && dy == 0) || !contains(x, y)) + if ((dx == 0 && dy == 0) || + (x < 0 || y < 0 || x >= mWidth || y >= mHeight)) { continue; } MetaTile *newTile = getMetaTile(x, y); - // Skip if the tile is on the closed list or collides - if (newTile->whichList == mOnClosedList || tileCollides(x, y)) + // Skip if the tile is on the closed list or is not walkable + if (newTile->whichList == onClosedList || newTile->blockmask & walkmask) { continue; } // When taking a diagonal step, verify that we can skip the - // corner. We allow skipping past beings but not past non- - // walkable tiles. + // corner. if (dx != 0 && dy != 0) { MetaTile *t1 = getMetaTile(curr.x, curr.y + dy); MetaTile *t2 = getMetaTile(curr.x + dx, curr.y); - if (!(t1->walkable && t2->walkable)) + if (t1->blockmask & walkmask && !(t2->blockmask & walkmask)) // I hope I didn't fuck this line up { continue; } @@ -428,21 +528,14 @@ Path Map::findPath(int startX, int startY, int destX, int destY) ++Gcost; } - // It costs extra to walk through a being (needs to be enough - // to make it more attractive to walk around). - if (occupied(x, y)) - { - Gcost += 30; - } - // Skip if Gcost becomes too much // Warning: probably not entirely accurate - if (Gcost > 20 * basicCost) + if (Gcost > maxCost * basicCost) { continue; } - if (newTile->whichList != mOnOpenList) + if (newTile->whichList != onOpenList) { // Found a new tile (not on open nor on closed list) @@ -464,7 +557,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY) if (x != destX || y != destY) { // Add this tile to the open list - newTile->whichList = mOnOpenList; + newTile->whichList = onOpenList; openList.push(Location(x, y, newTile)); } else { @@ -493,8 +586,8 @@ Path Map::findPath(int startX, int startY, int destX, int destY) // Two new values to indicate whether a tile is on the open or closed list, // this way we don't have to clear all the values between each pathfinding. - mOnClosedList += 2; - mOnOpenList += 2; + onClosedList += 2; + onOpenList += 2; // If a path has been found, iterate backwards using the parent locations // to extract it. diff --git a/src/map.h b/src/map.h index d8cc2189..71bbf843 100644 --- a/src/map.h +++ b/src/map.h @@ -54,7 +54,7 @@ struct MetaTile /** * Constructor. */ - MetaTile():whichList(0) {}; + MetaTile():whichList(0), blockmask(0) {}; // Pathfinding members int Fcost; /**< Estimation of total path cost */ @@ -63,7 +63,7 @@ struct MetaTile int whichList; /**< No list, open list or closed list */ int parentX; /**< X coordinate of parent tile */ int parentY; /**< Y coordinate of parent tile */ - bool walkable; /**< Can beings walk on this tile */ + unsigned char blockmask; /**< Can beings walk on this tile */ }; /** @@ -72,6 +72,15 @@ struct MetaTile class Map : public Properties { public: + enum BlockType + { + BLOCKTYPE_NONE = -1, + BLOCKTYPE_WALL, + BLOCKTYPE_CHARACTER, + BLOCKTYPE_MONSTER, + NB_BLOCKTYPES + }; + /** * Constructor, taking map and tile size as parameters. */ @@ -93,6 +102,11 @@ class Map : public Properties */ void draw(Graphics *graphics, int scrollX, int scrollY, int layer); + /** + * Visualizes collision layer for debugging + */ + void drawCollision(Graphics *graphics, int scrollX, int scrollY); + /** * Draws the overlay graphic to the given graphics output. */ @@ -129,19 +143,19 @@ class Map : public Properties MetaTile *getMetaTile(int x, int y) const; /** - * Set walkability flag for a tile. + * Marks a tile as occupied */ - void setWalk(int x, int y, bool walkable); + void blockTile(int x, int y, BlockType type); /** - * Tell if a tile is walkable or not, includes checking beings. + * Marks a tile as unoccupied */ - bool getWalk(int x, int y) const; + void freeTile(int x, int y, BlockType type); /** - * Tell if a tile collides, not including a check on beings. + * Gets walkability for a tile with a blocking bitmask */ - bool tileCollides(int x, int y) const; + bool getWalk(int x, int y, char walkmask) const; /** * Returns the width of this map. @@ -171,7 +185,7 @@ class Map : public Properties * Find a path from one location to the next. */ std::list - findPath(int startX, int startY, int destX, int destY); + findPath(int startX, int startY, int destX, int destY, unsigned char walkmask, int maxCost = 20); /** * Adds a sprite to the map. @@ -209,14 +223,20 @@ class Map : public Properties Tileset* getTilesetWithGid(int gid) const; /** - * Tells whether a tile is occupied by a being. + * Tells whether the given coordinates fall within the map boundaries. */ - bool occupied(int x, int y) const; + bool contains(int x, int y) const; /** - * Tells whether the given coordinates fall within the map boundaries. + * Blockmasks for different entities */ - bool contains(int x, int y) const; + static const unsigned char BLOCKMASK_WALL = 128; // = bin 1000 0000 + static const unsigned char BLOCKMASK_CHARACTER = 1;// = bin 0000 0001 + static const unsigned char BLOCKMASK_MONSTER = 2; // = bin 0000 0010 + int *mOccupation[NB_BLOCKTYPES]; + + // Pathfinding members + int onClosedList, onOpenList; int mWidth, mHeight; int mTileWidth, mTileHeight; diff --git a/src/monster.cpp b/src/monster.cpp index 5fbcfaea..abc7946f 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -44,6 +44,11 @@ Monster::Monster(Uint16 id, Uint16 job, Map *map): AnimatedSprite::load("graphics/sprites/" + filename); } +Monster::~Monster() +{ + if (mMap) mMap->freeTile(mX / 32, mY / 32, getBlockType()); +} + Being::Type Monster::getType() const { diff --git a/src/monster.h b/src/monster.h index 585f6f09..ecf7ad51 100644 --- a/src/monster.h +++ b/src/monster.h @@ -33,6 +33,8 @@ class Monster : public Being public: Monster(Uint16 id, Uint16 job, Map *map); + virtual ~Monster(); + virtual void setAction(Action action, int attackType); virtual Type getType() const; @@ -58,6 +60,19 @@ class Monster : public Being */ const MonsterInfo& getInfo() const; + + /** + * Gets the way the monster is blocked for other objects + */ + virtual unsigned char getWalkMask() const + { return 0x83; } // blocked walls, other monsters and players ( bin 1000 0011) + + protected: + /** + * Gets the way the monster blocks pathfinding for other objects + */ + virtual Map::BlockType getBlockType() const + { return Map::BLOCKTYPE_MONSTER; } }; #endif diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 05795cb1..f31ee48b 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -496,8 +496,7 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) return; } - being->mX = px; - being->mY = py; + being->setPositionInPixels(px, py); being->setDestination(px, py); being->setAction(action); } @@ -544,11 +543,10 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) { being->setWalkSpeed(speed * 10); } - if (abs(being->mX - sx) + abs(being->mY - sy) > 4 * 32) + if (abs(being->getPixelX() - sx) + abs(being->getPixelY() - sy) > 4 * 32) { // Too large a desynchronization. - being->mX = sx; - being->mY = sy; + being->setPositionInPixels(sx, sy); being->setDestination(dx, dy); } else if (!(flags & MOVING_POSITION)) @@ -582,8 +580,6 @@ void BeingHandler::handleBeingAttackMessage(MessageIn &msg) case DIRECTION_RIGHT: being->setDirection(Being::RIGHT); break; } - logger->log("Attacktype: %d", attackType); - being->setAction(Being::ATTACK, attackType); } diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp index 3c06d2f5..b908eae5 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/playerhandler.cpp @@ -301,6 +301,5 @@ PlayerHandler::handleMapChangeMessage(MessageIn &msg) current_npc = 0; player_node->setAction(Being::STAND); - player_node->mX = x; - player_node->mY = y; + player_node->setPositionInPixels(x, y); } diff --git a/src/player.cpp b/src/player.cpp index 2f1fc648..c218ad01 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -44,6 +44,11 @@ Player::Player(int id, int job, Map *map): { } +Player::~Player() +{ + if (mMap) mMap->freeTile(mX / 32, mY / 32, getBlockType()); +} + Being::Type Player::getType() const { diff --git a/src/player.h b/src/player.h index aff75221..76d6b460 100644 --- a/src/player.h +++ b/src/player.h @@ -49,6 +49,8 @@ class Player : public Being */ Player(int id, int job, Map *map); + virtual ~Player(); + virtual Type getType() const; @@ -113,10 +115,20 @@ class Player : public Being */ short getNumberOfGuilds(); + /** + * Gets the way the character is blocked by other objects + */ + virtual unsigned char getWalkMask() const + { return 0x82; } // blocked by walls and monsters ( bin 1000 0010) + protected: // Character guild information std::map mGuilds; - + /** + * Gets the way the monster blocks pathfinding for other objects + */ + virtual Map::BlockType getBlockType() const + { return Map::BLOCKTYPE_CHARACTER; } private: Gender mGender; Uint8 mHairStyle; -- cgit v1.2.3-70-g09d2 From 25ae0888d39ff370bfe8fa3f4f5eb572dbbe59ec Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Mon, 19 May 2008 15:10:50 +0000 Subject: --- ChangeLog | 5 +++++ src/net/beinghandler.cpp | 2 ++ 2 files changed, 7 insertions(+) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index f0c5d0cc..5a49be8b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-05-19 Philipp Sehmisch + + * src/net/beinghandler.cpp: Implemented interpretation of names for + NPCs and monsters. + 2008-05-16 David Athay * src/gui/popupmenu.cpp: Applied QOAL's patch to fix popups at diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index f31ee48b..b1c502e1 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -490,6 +490,8 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) { int subtype = msg.readInt16(); being = beingManager->createBeing(id, type, subtype); + std::string name = msg.readString(); + if (name.length() > 0) being->setName(name); } break; default: -- cgit v1.2.3-70-g09d2 From 3fe1772b1e00344365e3cf8204225be19925b9e5 Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Thu, 9 Oct 2008 19:42:13 +0000 Subject: Merged the movement branch into trunk I consider this the only way forward. In my tests this code isn't actually doing worse than what was there before. Of course some cases are a bit broken, and I'm open to any kind of feedback so that we can fix those issues. --- ChangeLog | 66 ++++++++ src/CMakeLists.txt | 3 + src/Makefile.am | 7 +- src/animatedsprite.cpp | 26 +--- src/being.cpp | 230 +++++++++++---------------- src/being.h | 110 +++++-------- src/beingmanager.cpp | 15 +- src/game.cpp | 9 +- src/gui/minimap.cpp | 7 +- src/gui/playerbox.cpp | 7 +- src/gui/updatewindow.cpp | 4 +- src/gui/viewport.cpp | 91 +++++------ src/gui/viewport.h | 11 +- src/localplayer.cpp | 63 +++++--- src/map.cpp | 35 +---- src/map.h | 12 +- src/monster.cpp | 1 - src/net/beinghandler.cpp | 370 +++----------------------------------------- src/net/playerhandler.cpp | 7 +- src/npc.cpp | 10 +- src/particleemitter.cpp | 5 +- src/player.cpp | 11 +- src/position.cpp | 47 ++++++ src/position.h | 60 +++++++ src/resources/spritedef.cpp | 5 +- src/simpleanimation.cpp | 5 +- src/vector.cpp | 30 ++++ src/vector.h | 68 +++++++- 28 files changed, 573 insertions(+), 742 deletions(-) create mode 100644 src/position.cpp create mode 100644 src/position.h create mode 100644 src/vector.cpp (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index 74cc958b..4294d0e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,76 @@ +2008-10-07 Bjørn Lindeijer + + * src/gui/updatewindow.cpp, src/particleemitter.cpp, + src/simpleanimation.cpp, src/resources/spritedef.cpp: Fixed some + compiler warnings. This probably also fixed the logging of several + error messages. + +2008-09-30 Bjørn Lindeijer + + * src/being.cpp: Fixed conversion of positions in the path to pixel + coordinates. Solves issues with keyboard walking and other + strangeness. + * src/localplayer.cpp, src/gui/playerbox.cpp, src/npc.cpp, + src/player.cpp, src/being.cpp, src/being.h: Fixed updating of player + direction and animation. Also fixed position of name, particle effects + and the position of the player sprite in the player box. + * src/map.cpp: Fixed ordering of sprites and tiles on the fringe + layer. + +2008-09-29 Bjørn Lindeijer + + * src/localplayer.cpp, src/being.cpp, src/being.h: Reenabled keyboard + walking (though its offset is broken) and make the player walk to the + exact destination when reaching the end of the path. + * src/being.cpp, src/animatedsprite.cpp: Corrected the location at + which the player sprite is drawn to match with the clicking location. + Might be a workaround for a bug elsewhere, I'm not sure yet. + +2008-09-28 Bjørn Lindeijer + + * src/localplayer.cpp, src/gui/viewport.h, src/gui/viewport.cpp, + src/position.cpp, src/position.h, src/being.cpp, src/CMakeLists.txt, + src/Makefile.am, src/being.h: Added printing and drawing of paths + beings are taking and fixed an issue in adjustPath (interpreting tiles + as pixels) that caused beings to stop moving. + +2008-09-26 Bjørn Lindeijer + + * src/net/beinghandler.cpp: Fixed interpretation of being speed. + 2008-09-14 Roderic Morris * src/gui/widgets/tabbedarea.cpp, src/gui/widgets/tabbedarea.h: Fix to avoid guichan bug and call logic in tabbed area children. +2008-09-09 Bjørn Lindeijer + + * src/being.cpp, src/net/beinghandler.cpp, src/being.h: Take into + account the speed sent by the server. Currently interpreted as pixels + per second, but this seems to be a bit too slow. + * src/localplayer.cpp: Re-enabled moving by mouse. Shows how utterly + broken the thing still is, but makes testing easier. + +2008-09-08 Bjørn Lindeijer + + * src/vector.cpp, src/being.cpp, src/CMakeLists.txt, src/vector.h, + src/Makefile.am: Made sure at least something happens. + +2008-09-07 Bjørn Lindeijer + + * src/map.cpp, src/position.h, src/being.cpp, src/CMakeLists.txt, + src/net/beinghandler.cpp, src/vector.h, src/map.h, src/Makefile.am, + src/being.h: Some late night fiddling around. It isn't doing anything + yet, but no time left to figure out why. + 2008-09-04 Bjørn Lindeijer + * src/localplayer.cpp, src/game.cpp, src/map.cpp, src/gui/viewport.h, + src/gui/viewport.cpp, src/gui/minimap.cpp, src/beingmanager.cpp, + src/npc.cpp, src/player.cpp, src/being.cpp, src/monster.cpp, + src/net/beinghandler.cpp, src/net/playerhandler.cpp, src/vector.h, + src/map.h, src/being.h: Almost completely disabled old style movement. + Clearing the road for a new movement system. * src/map.cpp, src/gui/setup.cpp, src/gui/shop.cpp, src/gui/windowcontainer.cpp, src/gui/skill.cpp, src/beingmanager.cpp, src/flooritemmanager.cpp, src/channelmanager.cpp, src/being.cpp, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aee99d2e..688f8787 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -390,6 +390,8 @@ SET(SRCS particleemitter.h player.cpp player.h + position.cpp + position.h properties.h serverinfo.h shopitem.cpp @@ -402,6 +404,7 @@ SET(SRCS textparticle.cpp textparticle.h tileset.h + vector.cpp vector.h ) diff --git a/src/Makefile.am b/src/Makefile.am index e7752477..e1de3a34 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,8 +7,8 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ gui/widgets/layout.h \ gui/widgets/resizegrip.cpp \ gui/widgets/resizegrip.h \ - gui/widgets/tab.cpp \ - gui/widgets/tab.h \ + gui/widgets/tab.cpp \ + gui/widgets/tab.h \ gui/widgets/tabbedarea.cpp \ gui/widgets/tabbedarea.h \ gui/box.h \ @@ -342,6 +342,8 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ particleemitter.h \ player.cpp \ player.h \ + position.cpp \ + position.h \ properties.h \ serverinfo.h \ shopitem.cpp \ @@ -354,6 +356,7 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \ textparticle.cpp \ textparticle.h \ tileset.h \ + vector.cpp \ vector.h # set the include path found by configure diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp index 466779fd..13596a70 100644 --- a/src/animatedsprite.cpp +++ b/src/animatedsprite.cpp @@ -160,9 +160,7 @@ bool AnimatedSprite::draw(Graphics* graphics, int posX, int posY) const { if (!mFrame || !mFrame->image) - { return false; - } return graphics->drawImage(mFrame->image, posX + mFrame->offsetX, @@ -177,9 +175,7 @@ AnimatedSprite::setDirection(SpriteDirection direction) mDirection = direction; if (!mAction) - { return; - } Animation *animation = mAction->getAnimation(mDirection); @@ -192,26 +188,12 @@ AnimatedSprite::setDirection(SpriteDirection direction) } } -int -AnimatedSprite::getWidth() const +int AnimatedSprite::getWidth() const { - if (mFrame) - { - return mFrame->image->getWidth(); - } - else { - return 0; - } + return mFrame ? mFrame->image->getWidth() : 0; } -int -AnimatedSprite::getHeight() const +int AnimatedSprite::getHeight() const { - if (mFrame) - { - return mFrame->image->getHeight(); - } - else { - return 0; - } + return mFrame ? mFrame->image->getHeight() : 0; } diff --git a/src/being.cpp b/src/being.cpp index cf2e3772..7b77ed5a 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -43,27 +43,27 @@ #include "utils/dtor.h" #include "utils/tostring.h" +namespace { +const bool debug_movement = true; +} + int Being::instances = 0; ImageSet *Being::emotionSet = NULL; Being::Being(int id, int job, Map *map): - mX(0), mY(0), mEmotion(0), mEmotionTime(0), mAttackSpeed(350), - mWalkTime(0), mAction(STAND), mJob(job), mId(id), - mWalkSpeed(150), - mSpeedModifier(1024), mSpriteDirection(DIRECTION_DOWN), mDirection(DOWN), mMap(NULL), mEquippedWeapon(NULL), mSpeechTime(0), - mPx(0), mPy(0), mSprites(VECTOREND_SPRITE, NULL), mSpriteIDs(VECTOREND_SPRITE, 0), - mSpriteColors(VECTOREND_SPRITE, "") + mSpriteColors(VECTOREND_SPRITE, ""), + mWalkSpeed(100) { setMap(map); @@ -106,27 +106,36 @@ Being::~Being() delete mSpeechBubble; } -void Being::setPositionInPixels(int x, int y) +void Being::setPosition(const Vector &pos) { - mMap->freeTile(mX / 32, mY / 32, getBlockType()); - mX = x; - mY = y; - mMap->blockTile(x / 32, y / 32, getBlockType()); + mPos = pos; + mDest = pos; } -void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY) +void Being::adjustCourse(int srcX, int srcY, int dstX, int dstY) { - if (!mMap || (mX == dstX && mY == dstY)) - { + if (debug_movement) + printf("%p adjustCourse(%d, %d, %d, %d)\n", + (void*) this, srcX, srcY, dstX, dstY); + + mDest.x = dstX; + mDest.y = dstY; + + // Find a path to the destination when it is at least a tile away + if (mMap && fabsf((mDest - mPos).length()) > 32) { + setPath(mMap->findPath((int) mPos.x / 32, (int) mPos.y / 32, + dstX / 32, dstY / 32, getWalkMask())); + } else { setPath(Path()); - return; } + // TODO: Evaluate the implementation of this method + /* if (mX / 32 == dstX / 32 && mY / 32 == dstY / 32) { // The being is already on the last tile of the path. Path p; - p.push_back(PATH_NODE(dstX, dstY)); + p.push_back(Position(dstX, dstY)); setPath(p); return; } @@ -173,7 +182,7 @@ void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY) p1_length = mMap->getMetaTile(dstX / 32, dstY / 32)->Gcost; p1_dist[p1_size - 1] = p1_length; } - p1.push_back(PATH_NODE(dstX, dstY)); + p1.push_back(Position(dstX, dstY)); if (mX / 32 == srcX / 32 && mY / 32 == srcY / 32) { @@ -248,19 +257,24 @@ void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY) assert(bestLength > 0); setPath(p1, p1_length * 1024 / bestLength); delete[] p1_dist; + */ } -void Being::adjustCourse(Uint16 srcX, Uint16 srcY) +void Being::adjustCourse(int srcX, int srcY) { + if (debug_movement) + printf("%p adjustCourse(%d, %d)\n", (void*) this, srcX, srcY); + if (!mPath.empty()) - { - adjustCourse(srcX, srcY, mPath.back().x, mPath.back().y); - } + adjustCourse(srcX, srcY, mPath.back().x * 32, mPath.back().y * 32); } -void Being::setDestination(Uint16 destX, Uint16 destY) +void Being::setDestination(int destX, int destY) { - adjustCourse(mX, mY, destX, destY); + if (debug_movement) + printf("%p setDestination(%d, %d)\n", (void*) this, destX, destY); + + adjustCourse((int) mPos.x, (int) mPos.y, destX, destY); } void Being::clearPath() @@ -268,34 +282,10 @@ void Being::clearPath() mPath.clear(); } -void Being::setPath(const Path &path, int mod) +void Being::setPath(const Path &path) { + std::cout << this << " New path: " << path << std::endl; mPath = path; - mSpeedModifier = mod >= 512 ? (mod <= 2048 ? mod : 2048) : 512; // TODO: tune bounds - - int sz = mPath.size(); - if (sz > 1) - { - // The path contains intermediate steps, so avoid going through tile - // centers for them. Instead, interpolate the tile offset. - int sx = mX & 31, sy = mY & 31; - int dx = (mPath.back().x & 31) - sx; - int dy = (mPath.back().y & 31) - sy; - Path::iterator j = mPath.begin(); - for (int i = 0; i < sz - 1; ++i) - { - j->x |= sx + dx * (i + 1) / (sz - 1); - j->y |= sy + dy * (i + 1) / (sz - 1); - ++j; - } - } - - if (mAction != WALK && mAction != DEAD) - { - mWalkTime = tick_time; - mStepTime = 0; - nextStep(); - } } void Being::setSprite(int slot, int id, const std::string &color) @@ -339,7 +329,8 @@ void Being::takeDamage(int amount) // Show damage number particleEngine->addTextSplashEffect(damage, 255, 255, 255, font, - mPx + 16, mPy + 16); + (int) mPos.x + 16, + (int) mPos.y + 16); } void Being::handleAttack() @@ -349,11 +340,9 @@ void Being::handleAttack() void Being::setMap(Map *map) { - // Remove sprite from potential previous map if (mMap) { - mMap->freeTile(mX / 32, mY / 32, getBlockType()); mMap->removeSprite(mSpriteIterator); } @@ -363,7 +352,6 @@ void Being::setMap(Map *map) if (mMap) { mSpriteIterator = mMap->addSprite(this); - mMap->blockTile(mX / 32, mY / 32, getBlockType()); } // Clear particle effect list because child particles became invalid @@ -447,21 +435,13 @@ void Being::setDirection(Uint8 direction) SpriteDirection dir; if (mFaceDirection & UP) - { dir = DIRECTION_UP; - } else if (mFaceDirection & RIGHT) - { dir = DIRECTION_RIGHT; - } else if (mFaceDirection & DOWN) - { dir = DIRECTION_DOWN; - } else - { dir = DIRECTION_LEFT; - } mSpriteDirection = dir; for (int i = 0; i < VECTOREND_SPRITE; i++) @@ -471,57 +451,48 @@ void Being::setDirection(Uint8 direction) } } -void Being::nextStep() -{ - if (mPath.empty()) - { - setAction(STAND); - return; - } - - PATH_NODE node = mPath.front(); - mPath.pop_front(); - - mStepX = node.x - mX; - mStepY = node.y - mY; - - int dir = 0, dx = std::abs(mStepX), dy = std::abs(mStepY); - if (dx * 2 > dy) - dir |= mStepX > 0 ? RIGHT : LEFT; - if (dy * 2 > dx) - dir |= mStepY > 0 ? DOWN : UP; - - setDirection(dir); - - if (!mMap->getWalk(node.x / 32, node.y / 32)) - { - setAction(STAND); - return; - } - - setPositionInPixels(node.x, node.y); - setAction(WALK); - mWalkTime += mStepTime / 10; - mStepTime = mWalkSpeed * (int)std::sqrt((double)mStepX * mStepX + (double)mStepY * mStepY) * - mSpeedModifier / (32 * 1024); -} - void Being::logic() { - // Determine whether the being should take another step - if (mAction == WALK && get_elapsed_time(mWalkTime) >= mStepTime) - { - nextStep(); + const Vector dest = (mPath.empty()) ? + mDest : Vector(mPath.front().x * 32 + 16, + mPath.front().y * 32 + 16); + + Vector dir = dest - mPos; + const float length = dir.length(); + + // When we're over 2 pixels from our destination, move to it + // TODO: Should be possible to make it even pixel exact, but this solves + // the jigger caused by moving too far. + if (length > 2.0f) { + const float speed = mWalkSpeed / 100.0f; + dir /= (length / speed); + mPos += dir; + + if (mAction != WALK) + setAction(WALK); + + // Update the player sprite direction + int direction = 0; + const float dx = std::abs(dir.x); + const float dy = std::abs(dir.y); + if (dx * 2 > dy) + direction |= (dir.x > 0) ? RIGHT : LEFT; + if (dy * 2 > dx) + direction |= (dir.y > 0) ? DOWN : UP; + setDirection(direction); + } + else if (!mPath.empty()) { + // TODO: Pop as soon as there is a direct unblocked line to the next + // point on the path. + mPath.pop_front(); + } else if (mAction == WALK) { + setAction(STAND); } // Reduce the time that speech is still displayed if (mSpeechTime > 0) mSpeechTime--; - // Update pixel coordinates - mPx = mX - 16 + getXOffset(); - mPy = mY - 16 + getYOffset(); - if (mEmotion != 0) { mEmotionTime--; @@ -543,7 +514,7 @@ void Being::logic() for (std::list::iterator i = mChildParticleEffects.begin(); i != mChildParticleEffects.end();) { - (*i)->setPosition((float)mPx + 16.0f, (float)mPy + 32.0f); + (*i)->setPosition(mPos.x, mPos.y); if (!(*i)->isAlive()) { (*i)->kill(); @@ -557,14 +528,16 @@ void Being::logic() void Being::draw(Graphics *graphics, int offsetX, int offsetY) const { - int px = mPx + offsetX; - int py = mPy + offsetY; + int px = (int) mPos.x + offsetX; + int py = (int) mPos.y + offsetY; for (int i = 0; i < VECTOREND_SPRITE; i++) { if (mSprites[i] != NULL) { - mSprites[i]->draw(graphics, px, py); + // TODO: Eventually, we probably should fix all sprite offsets so + // that this translation isn't necessary anymore. + mSprites[i]->draw(graphics, px - 16, py - 32); } } } @@ -574,18 +547,18 @@ void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY) if (!mEmotion) return; - const int px = mPx + offsetX + 3; - const int py = mPy + offsetY - 60; + const int px = (int) mPos.x + offsetX + 3; + const int py = (int) mPos.y + offsetY - 60; const int emotionIndex = mEmotion - 1; - if ( emotionIndex >= 0 && emotionIndex < (int) emotionSet->size() ) + if (emotionIndex >= 0 && emotionIndex < (int) emotionSet->size()) graphics->drawImage(emotionSet->get(emotionIndex), px, py); } void Being::drawSpeech(Graphics *graphics, int offsetX, int offsetY) { - int px = mPx + offsetX; - int py = mPy + offsetY; + int px = (int) mPos.x + offsetX; + int py = (int) mPos.y + offsetY; // Draw speech above this being if (mSpeechTime > 0) @@ -605,32 +578,7 @@ Being::Type Being::getType() const return UNKNOWN; } -int Being::getOffset(int step) const -{ - // Check whether we're walking in the requested direction - if (mAction != WALK || step == 0) { - return 0; - } - - int offset = (get_elapsed_time(mWalkTime) * std::abs(step)) / mStepTime; - - // We calculate the offset _from_ the _target_ location - offset -= std::abs(step); - if (offset > 0) { - offset = 0; - } - - // Going into negative direction? Invert the offset. - if (step < 0) { - offset = -offset; - } - - return offset; -} - - -int -Being::getWidth() const +int Being::getWidth() const { if (mSprites[BASE_SPRITE]) { @@ -641,9 +589,7 @@ Being::getWidth() const } } - -int -Being::getHeight() const +int Being::getHeight() const { if (mSprites[BASE_SPRITE]) { diff --git a/src/being.h b/src/being.h index 9d04f383..567a0d98 100644 --- a/src/being.h +++ b/src/being.h @@ -29,9 +29,11 @@ #include #include +#include "position.h" #include "sprite.h" #include "map.h" #include "animatedsprite.h" +#include "vector.h" #define NR_HAIR_STYLES 8 #define NR_HAIR_COLORS 10 @@ -46,24 +48,6 @@ class ImageSet; class Particle; class SpeechBubble; -/** - * A position along a being's path. - */ -struct PATH_NODE -{ - /** - * Constructor. - */ - PATH_NODE(unsigned short x, unsigned short y): - x(x), y(y) - { } - - unsigned short x; - unsigned short y; -}; -typedef std::list Path; -typedef Path::iterator PathIterator; - class Being : public Sprite { public: @@ -113,11 +97,9 @@ class Being : public Sprite enum { DOWN = 1, LEFT = 2, UP = 4, RIGHT = 8 }; std::string mName; /**< Name of character */ - Uint16 mX, mY; /**< Pixel coordinates of tile center */ Uint8 mEmotion; /**< Currently showing emotion */ Uint8 mEmotionTime; /**< Time until emotion disappears */ Uint16 mAttackSpeed; /**< Attack speed */ - Uint16 mWalkTime; Action mAction; /**< Action the being is performing */ Uint16 mJob; /**< Job (player job, npc, monster, creature ) */ @@ -139,17 +121,17 @@ class Being : public Sprite /** * Sets a new destination for this being to walk to. */ - void setDestination(Uint16 destX, Uint16 destY); + void setDestination(int x, int y); /** * Adjusts course to expected stat point. */ - void adjustCourse(Uint16, Uint16); + void adjustCourse(int, int); /** * Adjusts course to expected start and end points. */ - void adjustCourse(Uint16, Uint16, Uint16, Uint16); + void adjustCourse(int, int, int, int); /** * Puts a "speech balloon" above this being for the specified amount @@ -194,12 +176,6 @@ class Being : public Sprite virtual void setSprite(int slot, int id, const std::string &color = ""); - /** - * Makes this being take the next step of his path. - */ - virtual void - nextStep(); - /** * Performs being logic. */ @@ -231,15 +207,14 @@ class Being : public Sprite /** * Gets the walk speed. + * @see setWalkSpeed(int) */ - Uint16 - getWalkSpeed() const { return mWalkSpeed; } + int getWalkSpeed() const { return mWalkSpeed; } /** - * Sets the walk speed. + * Sets the walk speed (in pixels per second). */ - void - setWalkSpeed(Uint16 speed) { mWalkSpeed = speed; } + void setWalkSpeed(int speed) { mWalkSpeed = speed; } /** * Gets the being id. @@ -269,8 +244,6 @@ class Being : public Sprite */ bool isAlive() { return mAction != DEAD; } - int getWalkTime() { return mWalkTime; } - /** * Returns the direction the being is facing. */ @@ -287,57 +260,49 @@ class Being : public Sprite * * @see Sprite::draw(Graphics, int, int) */ - virtual void - draw(Graphics *graphics, int offsetX, int offsetY) const; + virtual void draw(Graphics *graphics, int offsetX, int offsetY) const; /** * Returns the pixel X coordinate. */ - int - getPixelX() const { return mPx; } + int getPixelX() const { return (int) mPos.x; } /** * Returns the pixel Y coordinate. * * @see Sprite::getPixelY() */ - int - getPixelY() const { return mPy; } + int getPixelY() const { return (int) mPos.y; } /** - * sets the position in pixels using pixel coordinates + * Sets the position of this being. */ - void setPositionInPixels(int x, int y); + void setPosition(const Vector &pos); /** - * sets the position in pixels using tile coordinates - */ - void setPositionInTiles(int x, int y) - { setPositionInPixels(x * 32 + 16, y * 32 + 16); } - - /** - * Get the current X pixel offset. + * Overloaded method provided for convenience. + * + * @see setPosition(const Vector &pos) */ - int - getXOffset() const { return getOffset(mStepX); } + void setPosition(float x, float y, float z = 0.0f) + { + setPosition(Vector(x, y, z)); + } /** - * Get the current Y pixel offset. + * Returns the position of this being. */ - int - getYOffset() const { return getOffset(mStepY); } + const Vector &getPosition() const { return mPos; } /** - * Returns the horizontal size of the current base sprite of the being + * Returns the horizontal size of the current base sprite of the being. */ - virtual int - getWidth() const; + virtual int getWidth() const; /** - * Returns the vertical size of the current base sprite of the being + * Returns the vertical size of the current base sprite of the being. */ - virtual int - getHeight() const; + virtual int getHeight() const; /** * Returns the required size of a target cursor for this being. @@ -351,16 +316,22 @@ class Being : public Sprite void controlParticle(Particle *particle); /** - * Gets the way the object is blocked by other objects + * Gets the way the object is blocked by other objects. */ virtual unsigned char getWalkMask() const { return 0x00; } //can walk through everything + /** + * Returns the path this being is following. An empty path is returned + * when this being isn't following any path currently. + */ + const Path &getPath() const { return mPath; } + protected: /** * Sets the new path for this being. */ - void setPath(const Path &path, int mod = 1024); + void setPath(const Path &path); /** * Gets the way the object blocks pathfinding for other objects @@ -369,8 +340,6 @@ class Being : public Sprite { return Map::BLOCKTYPE_NONE; } Uint16 mId; /**< Unique being id */ - Uint16 mWalkSpeed; /**< Walking speed */ - Uint16 mSpeedModifier; /**< Modifier to keep course on sync (1024 = normal speed) */ Uint8 mSpriteDirection; /**< Facing direction */ Uint8 mDirection; /**< Walking direction */ Map *mMap; /**< Map on which this being resides */ @@ -382,7 +351,6 @@ class Being : public Sprite Path mPath; std::string mSpeech; Uint32 mSpeechTime; - Sint32 mPx, mPy; /**< Pixel coordinates */ std::vector mSprites; std::vector mSpriteIDs; @@ -390,13 +358,13 @@ class Being : public Sprite std::list mChildParticleEffects; private: - int getOffset(int step) const; - // Speech Bubble components SpeechBubble *mSpeechBubble; - Sint16 mStepX, mStepY; - Uint16 mStepTime; + int mWalkSpeed; /**< Walking speed (pixels/sec) */ + + Vector mPos; + Vector mDest; static int instances; /**< Number of Being instances */ static ImageSet *emotionSet; /**< Emoticons used by beings */ diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp index a58c97e7..abb23f5e 100644 --- a/src/beingmanager.cpp +++ b/src/beingmanager.cpp @@ -39,8 +39,9 @@ class FindBeingFunctor bool operator() (Being *being) { Uint16 other_y = y + ((being->getType() == Being::NPC) ? 1 : 0); - return (being->mX / 32 == x && - (being->mY / 32 == y || being->mY / 32 == other_y) && + const Vector &pos = being->getPosition(); + return ((int) pos.x / 32 == x && + ((int) pos.y / 32 == y || (int) pos.y / 32 == other_y) && being->mAction != Being::DEAD && (type == Being::UNKNOWN || being->getType() == type)); } @@ -165,7 +166,8 @@ Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist, for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++) { Being *being = (*i); - int d = abs(being->mX - x) + abs(being->mY - y); + const Vector &pos = being->getPosition(); + int d = abs((int) pos.x - x) + abs((int) pos.y - y); if ((being->getType() == type || type == Being::UNKNOWN) && (d < dist || closestBeing == NULL) // it is closer @@ -185,13 +187,14 @@ Being* BeingManager::findNearestLivingBeing(Being *aroundBeing, int maxdist, { Being *closestBeing = NULL; int dist = 0; - int x = aroundBeing->mX; - int y = aroundBeing->mY; + const Vector &aroundBeingPos = aroundBeing->getPosition(); for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++) { Being *being = (*i); - int d = abs(being->mX - x) + abs(being->mY - y); + const Vector &pos = being->getPosition(); + int d = abs((int) pos.x - aroundBeingPos.x) + + abs((int) pos.y - aroundBeingPos.y); if ((being->getType() == type || type == Being::UNKNOWN) && (d < dist || closestBeing == NULL) // it is closer diff --git a/src/game.cpp b/src/game.cpp index e2343f39..fb434be2 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -580,8 +580,9 @@ void Game::handleInput() switch (tKey) { case KeyboardConfig::KEY_PICKUP: { - Uint16 x = player_node->mX / 32; - Uint16 y = player_node->mY / 32; + const Vector &pos = player_node->getPosition(); + Uint16 x = (int) pos.x / 32; + Uint16 y = (int) pos.y / 32; FloorItem *item = floorItemManager->findByCoordinates(x, y); @@ -754,7 +755,9 @@ void Game::handleInput() // Get the state of the keyboard keys keyboard.refreshActiveKeys(); - Uint16 x = player_node->mX / 32, y = player_node->mY / 32; + const Vector &pos = player_node->getPosition(); + Uint16 x = (int) pos.x / 32; + Uint16 y = (int) pos.y / 32; unsigned char direction = 0; diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp index 4e5664d6..ca6f4fd7 100644 --- a/src/gui/minimap.cpp +++ b/src/gui/minimap.cpp @@ -113,11 +113,12 @@ void Minimap::draw(gcn::Graphics *graphics) break; } - int offset = (dotSize - 1) / 2; + const int offset = (dotSize - 1) / 2; + const Vector &pos = being->getPosition(); graphics->fillRectangle(gcn::Rectangle( - being->mX / 64 + getPadding() - offset, - being->mY / 64 + getTitleBarHeight() - offset, + (int) pos.x / 64 + getPadding() - offset, + (int) pos.y / 64 + getTitleBarHeight() - offset, dotSize, dotSize)); } } diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp index 2c633b72..e9237110 100644 --- a/src/gui/playerbox.cpp +++ b/src/gui/playerbox.cpp @@ -82,10 +82,9 @@ PlayerBox::draw(gcn::Graphics *graphics) if (mPlayer) { // Draw character - int x, y, bs; - bs = getFrameSize(); - x = getWidth() / 2 - 16 + bs; - y = getHeight() / 2 + bs; + const int bs = getFrameSize(); + const int x = getWidth() / 2 + bs; + const int y = getHeight() - bs - 8; mPlayer->draw(static_cast(graphics), x, y); } } diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index abae69f6..10d0c826 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -60,9 +60,9 @@ unsigned long fadler32(FILE *file) // Calculate Adler-32 checksum char *buffer = (char*) malloc(fileSize); - fread(buffer, 1, fileSize, file); + const size_t read = fread(buffer, 1, fileSize, file); unsigned long adler = adler32(0L, Z_NULL, 0); - adler = adler32(adler, (Bytef*) buffer, fileSize); + adler = adler32(adler, (Bytef*) buffer, read); free(buffer); return adler; diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index 9677f81a..80dcf489 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -58,7 +58,6 @@ Viewport::Viewport(): mShowDebugPath(false), mVisibleNames(false), mPlayerFollowMouse(false), - mWalkTime(0), mLocalWalkTime(-1) { setOpaque(false); @@ -91,9 +90,9 @@ Viewport::Viewport(): true, Being::TC_LARGE); } -void -Viewport::loadTargetCursor(std::string filename, int width, int height, - bool outRange, Being::TargetCursorSize size) +void Viewport::loadTargetCursor(const std::string &filename, + int width, int height, + bool outRange, Being::TargetCursorSize size) { assert(size >= Being::TC_SMALL); assert(size < Being::NUM_TC); @@ -125,7 +124,7 @@ Viewport::loadTargetCursor(std::string filename, int width, int height, Viewport::~Viewport() { delete mPopupMenu; - + config.removeListener("visiblenames", this); for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++) @@ -137,14 +136,12 @@ Viewport::~Viewport() } } -void -Viewport::setMap(Map *map) +void Viewport::setMap(Map *map) { mMap = map; } -void -Viewport::draw(gcn::Graphics *gcnGraphics) +void Viewport::draw(gcn::Graphics *gcnGraphics) { static int lastTick = tick_time; @@ -163,8 +160,9 @@ Viewport::draw(gcn::Graphics *gcnGraphics) int midTileX = (graphics->getWidth() + mScrollCenterOffsetX) / 2; int midTileY = (graphics->getHeight() + mScrollCenterOffsetX) / 2; - int player_x = player_node->mX - midTileX + player_node->getXOffset(); - int player_y = player_node->mY - midTileY + player_node->getYOffset(); + const Vector &playerPos = player_node->getPosition(); + const int player_x = (int) playerPos.x - midTileX; + const int player_y = (int) playerPos.y - midTileY; if (mScrollLaziness < 1) mScrollLaziness = 1; // Avoids division by zero @@ -203,8 +201,10 @@ Viewport::draw(gcn::Graphics *gcnGraphics) }; // Don't move camera so that the end of the map is on screen - int viewXmax = mMap->getWidth() * 32 - graphics->getWidth(); - int viewYmax = mMap->getHeight() * 32 - graphics->getHeight(); + const int viewXmax = + mMap->getWidth() * mMap->getTileWidth() - graphics->getWidth(); + const int viewYmax = + mMap->getHeight() * mMap->getTileHeight() - graphics->getHeight(); if (mMap) { if (mViewX < 0) { @@ -227,10 +227,11 @@ Viewport::draw(gcn::Graphics *gcnGraphics) mMap->draw(graphics, (int) mViewX, (int) mViewY); drawTargetCursor(graphics); // TODO: Draw the cursor with the sprite drawTargetName(graphics); - if (mShowDebugPath) { mMap->drawCollision(graphics, (int) mViewX, (int) mViewY); +#if 0 drawDebugPath(graphics); +#endif } } @@ -239,19 +240,21 @@ Viewport::draw(gcn::Graphics *gcnGraphics) for (BeingIterator i = beings.begin(); i != beings.end(); i++) { (*i)->drawSpeech(graphics, -(int) mViewX, -(int) mViewY); - if(mVisibleNames) + if (mVisibleNames) (*i)->drawName(graphics, -(int) mViewX, -(int) mViewY); - else if((*i) == mSelectedBeing) + else if ((*i) == mSelectedBeing) (*i)->drawName(graphics, -(int) mViewX, -(int) mViewY); (*i)->drawEmotion(graphics, -(int) mViewX, -(int) mViewY); + + if (mShowDebugPath && !(*i)->getPath().empty()) + drawPath(graphics, (*i)->getPath()); } // Draw contained widgets WindowContainer::draw(gcnGraphics); } -void -Viewport::logic() +void Viewport::logic() { WindowContainer::logic(); @@ -262,13 +265,11 @@ Viewport::logic() Uint8 button = SDL_GetMouseState(&mouseX, &mouseY); if (mPlayerFollowMouse && button & SDL_BUTTON(1) && - mWalkTime != player_node->mWalkTime && get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay) { mLocalWalkTime = tick_time; player_node->setDestination(mouseX + (int) mViewX, mouseY + (int) mViewY); - mWalkTime = player_node->mWalkTime; } for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++) @@ -278,8 +279,7 @@ Viewport::logic() } } -void -Viewport::drawTargetCursor(Graphics *graphics) +void Viewport::drawTargetCursor(Graphics *graphics) { // Draw target marker if needed Being *target = player_node->getTarget(); @@ -288,9 +288,11 @@ Viewport::drawTargetCursor(Graphics *graphics) // Calculate target circle position // Find whether target is in range - int rangeX = abs(target->mX - player_node->mX); - int rangeY = abs(target->mY - player_node->mY); - int attackRange = player_node->getAttackRange(); + const Vector &dist = + target->getPosition() - player_node->getPosition(); + const int rangeX = abs((int) dist.x); + const int rangeY = abs((int) dist.y); + const int attackRange = player_node->getAttackRange(); // Get the correct target cursors graphic Being::TargetCursorSize cursorSize = target->getTargetCursorSize(); @@ -313,8 +315,7 @@ Viewport::drawTargetCursor(Graphics *graphics) } } -void -Viewport::drawTargetName(Graphics *graphics) +void Viewport::drawTargetName(Graphics *graphics) { // Draw target marker if needed Being *target = player_node->getTarget(); @@ -331,8 +332,7 @@ Viewport::drawTargetName(Graphics *graphics) } } -void -Viewport::drawDebugPath(Graphics *graphics) +void Viewport::drawDebugPath(Graphics *graphics) { // Get the current mouse position int mouseX, mouseY; @@ -340,13 +340,20 @@ Viewport::drawDebugPath(Graphics *graphics) const int mouseTileX = (mouseX + (int) mViewX) / 32; const int mouseTileY = (mouseY + (int) mViewY) / 32; + const Vector &playerPos = player_node->getPosition(); Path debugPath = mMap->findPath( - player_node->mX / 32, player_node->mY / 32, + (int) playerPos.x / 32, + (int) playerPos.y / 32, mouseTileX, mouseTileY, 0xFF); + drawPath(graphics, debugPath); +} + +void Viewport::drawPath(Graphics *graphics, const Path &path) +{ graphics->setColor(gcn::Color(255, 0, 0)); - for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++) + for (Path::const_iterator i = path.begin(); i != path.end(); ++i) { int squareX = i->x * 32 - (int) mViewX + 12; int squareY = i->y * 32 - (int) mViewY + 12; @@ -358,8 +365,7 @@ Viewport::drawDebugPath(Graphics *graphics) } } -void -Viewport::mousePressed(gcn::MouseEvent &event) +void Viewport::mousePressed(gcn::MouseEvent &event) { // Check if we are alive and kickin' if (!mMap || !player_node || player_node->mAction == Being::DEAD) @@ -435,13 +441,12 @@ Viewport::mousePressed(gcn::MouseEvent &event) } } -void -Viewport::mouseDragged(gcn::MouseEvent &event) +void Viewport::mouseDragged(gcn::MouseEvent &event) { if (!mMap || !player_node) return; - if (mPlayerFollowMouse && mWalkTime == player_node->mWalkTime + if (mPlayerFollowMouse && get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay) { mLocalWalkTime = tick_time; @@ -450,31 +455,27 @@ Viewport::mouseDragged(gcn::MouseEvent &event) } } -void -Viewport::mouseReleased(gcn::MouseEvent &event) +void Viewport::mouseReleased(gcn::MouseEvent &event) { mPlayerFollowMouse = false; } -void -Viewport::showPopup(int x, int y, Item *item) +void Viewport::showPopup(int x, int y, Item *item) { mPopupMenu->showPopup(x, y, item); } -void -Viewport::optionChanged(const std::string &name) +void Viewport::optionChanged(const std::string &name) { mScrollLaziness = (int) config.getValue("ScrollLaziness", 32); mScrollRadius = (int) config.getValue("ScrollRadius", 32); if (name == "visiblenames") { - mVisibleNames = config.getValue("visiblenames", 1); + mVisibleNames = config.getValue("visiblenames", 1); } } -void -Viewport::mouseMoved(gcn::MouseEvent &event) +void Viewport::mouseMoved(gcn::MouseEvent &event) { // Check if we are on the map if (!mMap || !player_node) diff --git a/src/gui/viewport.h b/src/gui/viewport.h index 82587938..5dedcea8 100644 --- a/src/gui/viewport.h +++ b/src/gui/viewport.h @@ -145,9 +145,10 @@ class Viewport : public WindowContainer, public gcn::MouseListener, private: /** - * Helper function for loading target cursors + * Helper function for loading target cursors. */ - void loadTargetCursor(std::string filename, int width, int height, + void loadTargetCursor(const std::string &filename, + int width, int height, bool outRange, Being::TargetCursorSize size); /** @@ -166,6 +167,11 @@ class Viewport : public WindowContainer, public gcn::MouseListener, */ void drawDebugPath(Graphics *graphics); + /** + * Draws the given path. + */ + void drawPath(Graphics *graphics, const Path &path); + Map *mMap; /**< The current map. */ @@ -191,7 +197,6 @@ class Viewport : public WindowContainer, public gcn::MouseListener, SimpleAnimation *mTargetCursorOutRange[Being::NUM_TC]; bool mPlayerFollowMouse; - int mWalkTime; int mLocalWalkTime; /**< Timestamp before the next walk can be sent. */ PopupMenu *mPopupMenu; /**< Popup menu. */ diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 00ea6a49..f596a8d9 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -87,14 +87,16 @@ void LocalPlayer::logic() } // Show XP messages - if(!mExpMessages.empty()) + if (!mExpMessages.empty()) { if (mExpMessageTime == 0) { + const Vector &pos = getPosition(); particleEngine->addTextRiseFadeOutEffect(mExpMessages.front(), 0, 128, 255, speechFont, - mPx + 16, mPy - 16); + (int) pos.x + 16, + (int) pos.y - 16); mExpMessages.pop_front(); mExpMessageTime = 30; } @@ -106,6 +108,8 @@ void LocalPlayer::logic() void LocalPlayer::nextStep() { + // TODO: Fix picking up when reaching target (this method is obsolete) + // TODO: Fix holding walking button to keep walking smoothly if (mPath.empty()) { if (mPickUpTarget) @@ -118,8 +122,6 @@ void LocalPlayer::nextStep() walk(mWalkingDir); } } - - Player::nextStep(); } bool LocalPlayer::checkInviteRights(const std::string &guildName) @@ -165,8 +167,7 @@ void LocalPlayer::setInvItem(int index, int id, int amount) mInventory->setItem(index, id, amount); } -void -LocalPlayer::moveInvItem(Item *item, int newIndex) +void LocalPlayer::moveInvItem(Item *item, int newIndex) { // special case, the old and new cannot copy over each other. if (item->getInvIndex() == newIndex) @@ -218,13 +219,12 @@ void LocalPlayer::splitItem(Item *item, int quantity) Net::GameServer::Player::moveItem( item->getInvIndex(), newIndex, quantity); } - } void LocalPlayer::pickUp(FloorItem *item) { - int dx = item->getX() - mX / 32; - int dy = item->getY() - mY / 32; + int dx = item->getX() - (int) getPosition().x / 32; + int dy = item->getY() - (int) getPosition().y / 32; if (dx * dx + dy * dy < 4) { int id = item->getId(); @@ -238,13 +238,16 @@ void LocalPlayer::pickUp(FloorItem *item) void LocalPlayer::walk(unsigned char dir) { + // TODO: Evaluate the implementation of this method if (!mMap || !dir) return; + const Vector &pos = getPosition(); + if (mAction == WALK && !mPath.empty()) { // Just finish the current action, otherwise we get out of sync - Being::setDestination(mX, mY); + Being::setDestination(pos.x, pos.y); return; } @@ -259,19 +262,23 @@ void LocalPlayer::walk(unsigned char dir) dx += 32; // Prevent skipping corners over colliding tiles - if (dx && !mMap->getWalk((mX + dx) / 32, mY / 32, getWalkMask())) - dx = 16 - mX % 32; - if (dy && !mMap->getWalk(mX / 32, (mY + dy) / 32, getWalkMask())) - dy = 16 - mY % 32; + if (dx && !mMap->getWalk(((int) pos.x + dx) / 32, + (int) pos.y / 32, getWalkMask())) + dx = 16 - (int) pos.x % 32; + if (dy && !mMap->getWalk((int) pos.x / 32, + ((int) pos.y + dy) / 32, getWalkMask())) + dy = 16 - (int) pos.y % 32; // Choose a straight direction when diagonal target is blocked - if (dx && dy && !mMap->getWalk((mX + dx) / 32, (mY + dy) / 32, getWalkMask())) - dx = 16 - mX % 32; + if (dx && dy && !mMap->getWalk((pos.x + dx) / 32, + (pos.y + dy) / 32, getWalkMask())) + dx = 16 - (int) pos.x % 32; // Walk to where the player can actually go - if ((dx || dy) && mMap->getWalk((mX + dx) / 32, (mY + dy) / 32, getWalkMask())) + if ((dx || dy) && mMap->getWalk(((int) pos.x + dx) / 32, + ((int) pos.y + dy) / 32, getWalkMask())) { - setDestination(mX + dx, mY + dy); + setDestination((int) pos.x + dx, (int) pos.y + dy); } else if (dir) { @@ -284,10 +291,20 @@ void LocalPlayer::walk(unsigned char dir) void LocalPlayer::setDestination(Uint16 x, Uint16 y) { // Fix coordinates so that the player does not seem to dig into walls. - int tx = x / 32, ty = y / 32, fx = x % 32, fy = y % 32; - if (fx != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty, getWalkMask())) fx = 16; - if (fy != 16 && !mMap->getWalk(tx, ty + fy / 16 * 2 - 1, getWalkMask())) fy = 16; - if (fx != 16 && fy != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty + fy / 16 * 2 - 1, getWalkMask())) fx = 16; + const int tx = x / 32; + const int ty = y / 32; + int fx = x % 32; + int fy = y % 32; + + if (fx != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty, getWalkMask())) + fx = 16; + if (fy != 16 && !mMap->getWalk(tx, ty + fy / 16 * 2 - 1, getWalkMask())) + fy = 16; + if (fx != 16 && fy != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, + ty + fy / 16 * 2 - 1, + getWalkMask())) + fx = 16; + x = tx * 32 + fx; y = ty * 32 + fy; @@ -375,7 +392,6 @@ void LocalPlayer::attack() return; mLastAction = tick_time; - mWalkTime = tick_time; setAction(ATTACK); @@ -449,7 +465,6 @@ const struct LocalPlayer::SkillInfo& LocalPlayer::getSkillInfo(int skill) { return skills[skill]; } - } void LocalPlayer::setExperience(int skill, int current, int next) diff --git a/src/map.cpp b/src/map.cpp index 888ea3a8..e10e4fad 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -113,7 +113,7 @@ void MapLayer::draw(Graphics *graphics, // If drawing the fringe layer, make sure all sprites above this row of // tiles have been drawn if (mIsFringeLayer) { - while (si != sprites.end() && (*si)->getPixelY() <= y * 32 - 32) { + while (si != sprites.end() && (*si)->getPixelY() <= y * 32) { (*si)->draw(graphics, -scrollX, -scrollY); si++; } @@ -383,35 +383,6 @@ void Map::blockTile(int x, int y, BlockType type) } } -void Map::freeTile(int x, int y, BlockType type) -{ - if (type == BLOCKTYPE_NONE || x < 0 || y < 0 || x >= mWidth || y >= mHeight) - { - return; - } - - int tileNum = x + y * mWidth; - - if ((--mOccupation[type][tileNum]) <= 0) - { - switch (type) - { - case BLOCKTYPE_WALL: - mMetaTiles[tileNum].blockmask &= (BLOCKMASK_WALL xor 0xff); - break; - case BLOCKTYPE_CHARACTER: - mMetaTiles[tileNum].blockmask &= (BLOCKMASK_CHARACTER xor 0xff); - break; - case BLOCKTYPE_MONSTER: - mMetaTiles[tileNum].blockmask &= (BLOCKMASK_MONSTER xor 0xff); - break; - default: - // shut up! - break; - } - } -} - bool Map::getWalk(int x, int y, char walkmask) const { // You can't walk outside of the map @@ -450,7 +421,7 @@ static int const basicCost = 100; Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char walkmask, int maxCost) { // Path to be built up (empty by default) - std::list path; + std::list path; // Declare open list, a list with open tiles sorted on F cost std::priority_queue openList; @@ -612,7 +583,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w while (pathX != startX || pathY != startY) { // Add the new path node to the start of the path list - path.push_front(PATH_NODE(pathX, pathY)); + path.push_front(Position(pathX, pathY)); // Find out the next parent MetaTile *tile = getMetaTile(pathX, pathY); diff --git a/src/map.h b/src/map.h index 31c6be00..c4a4fc0b 100644 --- a/src/map.h +++ b/src/map.h @@ -27,6 +27,7 @@ #include #include +#include "position.h" #include "properties.h" class AmbientOverlay; @@ -37,8 +38,6 @@ class Particle; class Sprite; class Tileset; -struct PATH_NODE; - typedef std::vector Tilesets; typedef std::list Sprites; typedef Sprites::iterator SpriteIterator; @@ -188,11 +187,6 @@ class Map : public Properties */ void blockTile(int x, int y, BlockType type); - /** - * Marks a tile as unoccupied - */ - void freeTile(int x, int y, BlockType type); - /** * Gets walkability for a tile with a blocking bitmask. When called * without walkmask, only blocks against colliding tiles. @@ -226,8 +220,8 @@ class Map : public Properties /** * Find a path from one location to the next. */ - std::list - findPath(int startX, int startY, int destX, int destY, unsigned char walkmask, int maxCost = 20); + Path findPath(int startX, int startY, int destX, int destY, + unsigned char walkmask, int maxCost = 20); /** * Adds a sprite to the map. diff --git a/src/monster.cpp b/src/monster.cpp index 1561b2ea..396d0c06 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -55,7 +55,6 @@ Monster::Monster(Uint16 id, Uint16 job, Map *map): Monster::~Monster() { - if (mMap) mMap->freeTile(mX / 32, mY / 32, getBlockType()); } Being::Type diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index b1c502e1..7e37aa27 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -48,18 +48,6 @@ const int EMOTION_TIME = 150; /**< Duration of emotion icon */ BeingHandler::BeingHandler() { static const Uint16 _messages[] = { - //SMSG_BEING_VISIBLE, - //SMSG_BEING_MOVE, - //SMSG_BEING_REMOVE, - //SMSG_BEING_ACTION, - //SMSG_BEING_LEVELUP, - //SMSG_BEING_EMOTION, - //SMSG_BEING_CHANGE_LOOKS, - //SMSG_BEING_NAME_RESPONSE, - //SMSG_PLAYER_UPDATE_1, - //SMSG_PLAYER_UPDATE_2, - //SMSG_PLAYER_MOVE, - //0x0119, GPMSG_BEING_ATTACK, GPMSG_BEING_ENTER, GPMSG_BEING_LEAVE, @@ -74,15 +62,6 @@ BeingHandler::BeingHandler() void BeingHandler::handleMessage(MessageIn &msg) { - /* - Uint32 id; - Uint16 job, speed; - Uint16 headBottom, headTop, headMid; - Sint16 param1; - Sint8 type; - Being *srcBeing, *dstBeing; - */ - switch (msg.getId()) { case GPMSG_BEING_ENTER: @@ -106,322 +85,6 @@ void BeingHandler::handleMessage(MessageIn &msg) case GPMSG_BEING_LOOKS_CHANGE: handleBeingLooksChangeMessage(msg); break; - - - /* - case SMSG_BEING_VISIBLE: - case SMSG_BEING_MOVE: - // Information about a being in range - id = msg.readInt32(); - speed = msg.readInt16(); - msg.readInt16(); // unknown - msg.readInt16(); // unknown - msg.readInt16(); // option - job = msg.readInt16(); // class - - dstBeing = beingManager->findBeing(id); - - if (!dstBeing) - { - // Being with id >= 110000000 and job 0 are better - // known as ghosts, so don't create those. - if (job == 0 && id >= 110000000) - { - break; - } - - dstBeing = beingManager->createBeing(id, job); - } - else if (msg.getId() == 0x0078) - { - dstBeing->clearPath(); - dstBeing->mFrame = 0; - dstBeing->mWalkTime = tick_time; - dstBeing->setAction(Being::STAND); - } - - // Prevent division by 0 when calculating frame - if (speed == 0) { speed = 150; } - - dstBeing->setWalkSpeed(speed); - dstBeing->mJob = job; - dstBeing->setHairStyle(msg->readInt16()); - dstBeing->setSprite( - Being::WEAPON_SPRITE, msg->readInt16()); - dstBeing->setSprite( - Being::BOTTOMCLOTHES_SPRITE, msg->readInt16()); - - if (msg.getId() == SMSG_BEING_MOVE) - { - msg.readInt32(); // server tick - } - - msg->readInt16(); // shield - headTop = msg->readInt16(); - headMid = msg->readInt16(); - dstBeing->setSprite(Being::HAT_SPRITE, headTop); - dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid); - dstBeing->setHairColor(msg->readInt16()); - msg->readInt16(); // unknown - msg->readInt16(); // head dir - msg->readInt16(); // guild - msg->readInt16(); // unknown - msg->readInt16(); // unknown - msg->readInt16(); // manner - msg->readInt16(); // karma - msg->readInt8(); // unknown - dstBeing->setSex(1 - msg->readInt8()); // sex - - if (msg.getId() == SMSG_BEING_MOVE) - { - //Uint16 srcX, srcY, dstX, dstY; - //msg.readCoordinatePair(srcX, srcY, dstX, dstY); - //dstBeing->setAction(Being::STAND); - //dstBeing->mX = srcX; - //dstBeing->mY = srcY; - //dstBeing->setDestination(dstX, dstY); - } - else - { - //Uint8 dir; - //msg->readCoordinates(dstBeing->mX, dstBeing->mY, dir); - //dstBeing->setDirection(dir); - } - - msg.readInt8(); // unknown - msg.readInt8(); // unknown - msg.readInt8(); // unknown / sit - break; - - case SMSG_BEING_REMOVE: - // A being should be removed or has died - dstBeing = beingManager->findBeing(msg.readInt32()); - - if (!dstBeing) - break; - - if (msg.readInt8() == 1) - { - dstBeing->setAction(Being::DEAD); - } - else - { - beingManager->destroyBeing(dstBeing); - } - - if (dstBeing == player_node->getTarget()) - { - player_node->stopAttack(); - } - break; - - case SMSG_BEING_ACTION: - srcBeing = beingManager->findBeing(msg.readInt32()); - dstBeing = beingManager->findBeing(msg.readInt32()); - msg.readInt32(); // server tick - msg.readInt32(); // src speed - msg.readInt32(); // dst speed - param1 = msg.readInt16(); - msg.readInt16(); // param 2 - type = msg.readInt8(); - msg.readInt16(); // param 3 - - switch (type) - { - case 0: // Damage - if (dstBeing) { - dstBeing->takeDamage(param1); - } - if (srcBeing) { - srcBeing->handleAttack(dstBeing, param1); - } - break; - - case 2: // Sit - if (srcBeing) { - srcBeing->mFrame = 0; - srcBeing->setAction(Being::SIT); - } - break; - - case 3: // Stand up - if (srcBeing) { - srcBeing->mFrame = 0; - srcBeing->setAction(Being::STAND); - } - break; - } - break; - - case SMSG_BEING_LEVELUP: - id = (Uint32) msg->readInt32(); - - if (id == player_node->getId()) { - logger->log("Level up"); - sound.playSfx("sfx/levelup.ogg"); - } - else { - logger->log("Someone else went level up"); - } - Particle *levelupFX; - if (msg->readInt32() == 0) { // type - levelupFX = particleEngine->addEffect( - "graphics/particles/levelup.particle.xml", 0, 0); - } - else { - levelupFX = particleEngine->addEffect( - "graphics/particles/skillup.particle.xml", 0, 0); - } - beingManager->findBeing(id)->controlParticle(levelupFX); - break; - - case SMSG_BEING_EMOTION: - if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) - { - break; - } - - dstBeing->mEmotion = msg.readInt8(); - dstBeing->mEmotionTime = EMOTION_TIME; - break; - - case SMSG_BEING_CHANGE_LOOKS: - { - if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) - { - break; - } - - int type = msg.readInt8(); - int id = msg.readInt8(); - - switch (type) { - case 1: - dstBeing->setHairStyle(id); - break; - case 2: - dstBeing->setSprite(Being::WEAPON_SPRITE, id); - break; - case 3: // Change lower headgear for eAthena, pants for us - dstBeing->setSprite( - Being::BOTTOMCLOTHES_SPRITE, id); - break; - case 4: // Change upper headgear for eAthena, hat for us - dstBeing->setSprite( - Being::HAT_SPRITE, id); - break; - case 5: // Change middle headgear for eathena, armor for us - dstBeing->setSprite( - Being::TOPCLOTHES_SPRITE, id); - break; - case 6: - dstBeing->setHairColor(id); - break; - default: - logger->log("SMSG_BEING_CHANGE_LOOKS: unsupported type: " - "%d, id: %d", type, id); - break; - } - } - break; - - case SMSG_BEING_NAME_RESPONSE: - if ((dstBeing = beingManager->findBeing(msg.readInt32()))) - { - dstBeing->setName(msg.readString(24)); - } - break; - - case SMSG_PLAYER_UPDATE_1: - case SMSG_PLAYER_UPDATE_2: - case SMSG_PLAYER_MOVE: - // An update about a player, potentially including movement. - id = msg.readInt32(); - speed = msg.readInt16(); - msg.readInt16(); // option 1 - msg.readInt16(); // option 2 - msg.readInt16(); // option - job = msg.readInt16(); - - dstBeing = beingManager->findBeing(id); - - if (!dstBeing) - { - dstBeing = beingManager->createBeing(id, job); - } - - dstBeing->setWalkSpeed(speed); - dstBeing->mJob = job; - dstBeing->setHairStyle(msg->readInt16()); - dstBeing->setSprite( - Being::WEAPON_SPRITE, msg->readInt16()); - msg->readInt16(); // item id 2 - headBottom = msg->readInt16(); - - if (msg.getId() == SMSG_PLAYER_MOVE) - { - msg.readInt32(); // server tick - } - - headTop = msg.readInt16(); - headMid = msg.readInt16(); - dstBeing->setHairColor(msg.readInt16()); - msg.readInt16(); // unknown - msg.readInt16(); // head dir - msg.readInt32(); // guild - msg.readInt32(); // emblem - msg.readInt16(); // manner - msg.readInt8(); // karma - dstBeing->setSex(1 - msg.readInt8()); // sex - dstBeing->setSprite( - Being::BOTTOMCLOTHES_SPRITE, headBottom); - dstBeing->setSprite(Being::HAT_SPRITE, headTop); - dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid); - - if (msg.getId() == SMSG_PLAYER_MOVE) - { - //Uint16 srcX, srcY, dstX, dstY; - //msg.readCoordinatePair(srcX, srcY, dstX, dstY); - //dstBeing->mX = srcX; - //dstBeing->mY = srcY; - //dstBeing->setDestination(dstX, dstY); - } - else - { - //Uint8 dir; - //msg->readCoordinates(dstBeing->mX, dstBeing->mY, dir); - //dstBeing->setDirection(dir); - } - - msg.readInt8(); // unknown - msg.readInt8(); // unknown - - if (msg.getId() == SMSG_PLAYER_UPDATE_1) - { - if (msg.readInt8() == 2) - { - dstBeing->setAction(Being::SIT); - } - } - else if (msg.getId() == SMSG_PLAYER_MOVE) - { - msg.readInt8(); // unknown - } - - msg.readInt8(); // Lv - msg.readInt8(); // unknown - - dstBeing->mWalkTime = tick_time; - dstBeing->mFrame = 0; - break; - - case 0x0119: - // Change in players look - logger->log("0x0119 %i %i %i %x %i", msg->readInt32(), - msg->readInt16(), msg->readInt16(), msg->readInt16(), - msg->readInt8()); - break; - */ } } @@ -453,8 +116,7 @@ static void handleLooks(Player *being, MessageIn &msg) } } -void -BeingHandler::handleBeingEnterMessage(MessageIn &msg) +void BeingHandler::handleBeingEnterMessage(MessageIn &msg) { int type = msg.readInt8(); int id = msg.readInt16(); @@ -481,7 +143,8 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) Player *p = static_cast< Player * >(being); int hs = msg.readInt8(), hc = msg.readInt8(); p->setHairStyle(hs, hc); - p->setGender(msg.readInt8() == GENDER_MALE ? GENDER_MALE : GENDER_FEMALE); + p->setGender(msg.readInt8() == GENDER_MALE ? + GENDER_MALE : GENDER_FEMALE); handleLooks(p, msg); } break; @@ -498,7 +161,7 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg) return; } - being->setPositionInPixels(px, py); + being->setPosition(px, py); being->setDestination(px, py); being->setAction(action); } @@ -518,7 +181,17 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) int id = msg.readInt16(); int flags = msg.readInt8(); Being *being = beingManager->findBeing(id); - int sx = 0, sy = 0, dx = 0, dy = 0, speed = 0; + int sx = 0; + int sy = 0; + int dx = 0; + int dy = 0; + int speed = 0; + + printf("handleBeingsMoveMessage for %p (%s | %s)\n", + (void*) being, + (flags & MOVING_POSITION) ? "pos" : "", + (flags & MOVING_DESTINATION) ? "dest" : ""); + if (flags & MOVING_POSITION) { Uint16 sx2, sy2; @@ -543,12 +216,19 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) } if (speed) { - being->setWalkSpeed(speed * 10); + /* The speed on the server is the cost of moving from one tile to + * the next. Beings get 1000 cost units per second. The speed is + * transferred as devided by 10, so that slower speeds fit in a + * byte. Here we convert the speed to pixels per second. + */ + const float tilesPerSecond = 100.0f / speed; + being->setWalkSpeed((int) (tilesPerSecond * 32)); } - if (abs(being->getPixelX() - sx) + abs(being->getPixelY() - sy) > 4 * 32) + if (abs(being->getPixelX() - sx) + + abs(being->getPixelY() - sy) > 4 * 32) { // Too large a desynchronization. - being->setPositionInPixels(sx, sy); + being->setPosition(sx, sy); being->setDestination(dx, dy); } else if (!(flags & MOVING_POSITION)) diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp index ea581095..3c0a1835 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/playerhandler.cpp @@ -302,11 +302,12 @@ PlayerHandler::handleMapChangeMessage(MessageIn &msg) current_npc = 0; - const float scrollOffsetX = x - player_node->mX; - const float scrollOffsetY = y - player_node->mY; + const Vector &playerPos = player_node->getPosition(); + const float scrollOffsetX = x - (int) playerPos.x; + const float scrollOffsetY = y - (int) playerPos.y; player_node->setAction(Being::STAND); - player_node->setPositionInPixels(x, y); + player_node->setPosition(x, y); logger->log("Adjust scrolling by %d,%d", (int) scrollOffsetX, (int) scrollOffsetY); diff --git a/src/npc.cpp b/src/npc.cpp index c2b266ff..a7302e0d 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -69,15 +69,15 @@ NPC::getType() const return Being::NPC; } -void -NPC::drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) +void NPC::drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) { - int px = mPx + offsetX; - int py = mPy + offsetY; + const Vector &pos = getPosition(); + const int px = (int) pos.x + offsetX; + const int py = (int) pos.y + offsetY; graphics->setFont(speechFont); graphics->setColor(gcn::Color(200, 200, 255)); - graphics->drawText(mName, px + 15, py + 30, gcn::Graphics::CENTER); + graphics->drawText(mName, px, py, gcn::Graphics::CENTER); } void diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp index f03490ac..23c6879e 100644 --- a/src/particleemitter.cpp +++ b/src/particleemitter.cpp @@ -195,7 +195,7 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map * if (!img) { - logger->log("No image at index " + (index)); + logger->log("No image at index %d", index); continue; } @@ -218,8 +218,7 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map * if (!img) { - logger->log("No image at index " + - (start)); + logger->log("No image at index %d", start); continue; } diff --git a/src/player.cpp b/src/player.cpp index 49f0221d..97c60789 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -46,7 +46,6 @@ Player::Player(int id, int job, Map *map): Player::~Player() { - if (mMap) mMap->freeTile(mX / 32, mY / 32, getBlockType()); } Being::Type @@ -55,15 +54,15 @@ Player::getType() const return PLAYER; } -void -Player::drawName(Graphics *graphics, int offsetX, int offsetY) +void Player::drawName(Graphics *graphics, int offsetX, int offsetY) { - int px = mPx + offsetX; - int py = mPy + offsetY; + const Vector &pos = getPosition(); + const int px = (int) pos.x + offsetX; + const int py = (int) pos.y + offsetY; graphics->setFont(speechFont); graphics->setColor(gcn::Color(255, 255, 255)); - graphics->drawText(mName, px + 15, py + 30, gcn::Graphics::CENTER); + graphics->drawText(mName, px, py, gcn::Graphics::CENTER); } void Player::setGender(Gender gender) diff --git a/src/position.cpp b/src/position.cpp new file mode 100644 index 00000000..334079bb --- /dev/null +++ b/src/position.cpp @@ -0,0 +1,47 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "position.h" + +std::ostream& operator <<(std::ostream &os, const Position &p) +{ + os << "(" << p.x << ", " << p.y << ")"; + return os; +} + +std::ostream& operator <<(std::ostream &os, const Path &path) +{ + Path::const_iterator i = path.begin(); + + os << "("; + while (i != path.end()) + { + os << *i; + ++i; + if (i != path.end()) + os << ", "; + } + os << ")"; + + return os; +} diff --git a/src/position.h b/src/position.h new file mode 100644 index 00000000..d1aa2ee6 --- /dev/null +++ b/src/position.h @@ -0,0 +1,60 @@ +/* + * The Mana World + * Copyright 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: being.h 4570 2008-09-04 20:59:34Z b_lindeijer $ + */ + +#ifndef TMW_POSITION_H +#define TMW_POSITION_H + +#include +#include + +/** + * A position along a being's path. + */ +struct Position +{ + /** + * Constructor. + */ + Position(int x, int y): + x(x), y(y) + { } + + int x; + int y; +}; + +typedef std::list Path; +typedef Path::iterator PathIterator; + +/** + * Appends a string representation of a position to the output stream. + */ +std::ostream& operator <<(std::ostream &os, const Position &p); + +/** + * Appends a string representation of a path (sequence of positions) to the + * output stream. + */ +std::ostream& operator <<(std::ostream &os, const Path &path); + +#endif // TMW_POSITION_H diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp index 9d98184a..dcfee165 100644 --- a/src/resources/spritedef.cpp +++ b/src/resources/spritedef.cpp @@ -232,7 +232,7 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode, if (!img) { - logger->log("No image at index " + (index + variant_offset)); + logger->log("No image at index %d", index + variant_offset); continue; } @@ -255,8 +255,7 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode, if (!img) { - logger->log("No image at index " + - (start + variant_offset)); + logger->log("No image at index %d", start + variant_offset); continue; } diff --git a/src/simpleanimation.cpp b/src/simpleanimation.cpp index 18e732ef..f425d3c1 100644 --- a/src/simpleanimation.cpp +++ b/src/simpleanimation.cpp @@ -68,7 +68,7 @@ SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode): if (!img) { - logger->log("No image at index " + (index)); + logger->log("No image at index %d", index); continue; } @@ -91,8 +91,7 @@ SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode): if (!img) { - logger->log("No image at index " + - (start)); + logger->log("No image at index %d", start); continue; } diff --git a/src/vector.cpp b/src/vector.cpp new file mode 100644 index 00000000..88092c9b --- /dev/null +++ b/src/vector.cpp @@ -0,0 +1,30 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: vector.h 4592 2008-09-07 20:38:52Z b_lindeijer $ + */ + +#include "vector.h" + +std::ostream& operator <<(std::ostream &os, const Vector &v) +{ + os << "Vector(" << v.x << ", " << v.y << ", " << v.z << ")"; + return os; +} diff --git a/src/vector.h b/src/vector.h index 7a5da241..7251eff0 100644 --- a/src/vector.h +++ b/src/vector.h @@ -24,6 +24,10 @@ #ifndef _TMW_VECTOR_H_ #define _TMW_VECTOR_H_ +#include + +#include + /** * Vector class. Represents either a 3D point in space, a velocity or a force. * Provides several convenient operator overloads. @@ -43,7 +47,7 @@ class Vector /** * Constructor. */ - Vector(float x, float y, float z): + Vector(float x, float y, float z = 0.0f): x(x), y(y), z(z) @@ -71,11 +75,12 @@ class Vector /** * In-place scale vector operator. */ - void operator*=(float c) + Vector &operator*=(float c) { x *= c; y *= c; z *= c; + return *this; } /** @@ -88,6 +93,17 @@ class Vector z / c); } + /** + * In-place scale vector operator. + */ + Vector &operator/=(float c) + { + x /= c; + y /= c; + z /= c; + return *this; + } + /** * Add vector operator. */ @@ -101,11 +117,12 @@ class Vector /** * In-place add vector operator. */ - void operator+=(const Vector &v) + Vector &operator+=(const Vector &v) { x += v.x; y += v.y; z += v.z; + return *this; } /** @@ -121,14 +138,55 @@ class Vector /** * In-place substract vector operator. */ - void operator-=(const Vector &v) + Vector &operator-=(const Vector &v) { x -= v.x; y -= v.y; z -= v.z; + return *this; + } + + /** + * Returns the length of this vector. This method does a relatively + * slow square root. + */ + float length() const + { + return sqrtf(x * x + y * y + z * z); + } + + /** + * Returns the squared length of this vector. Avoids the square root. + */ + float squaredLength() const + { + return x * x + y * y + z * z; + } + + /** + * Returns the manhattan length of this vector. + */ + float manhattanLength() const + { + return fabsf(x) + fabsf(y) + fabsf(z); + } + + /** + * Returns a normalized version of this vector. This is a unit vector + * running parallel to it. + */ + Vector normalized() const + { + const float l = length(); + return Vector(x / l, y / l, z / l); } float x, y, z; }; -#endif +/** + * Appends a string representation of a vector to the output stream. + */ +std::ostream& operator <<(std::ostream &os, const Vector &v); + +#endif // _TMW_VECTOR_H_ -- cgit v1.2.3-70-g09d2 From 438be47fa7078cd235bda7d2461024ddc222c026 Mon Sep 17 00:00:00 2001 From: David Athay Date: Wed, 15 Oct 2008 15:45:14 +0000 Subject: src/localplayer.cpp src/net/beinghandler.cpp src/net/protocol.h src/net/gameserver/player.h src/net/gameserver/player.cpp src/net/beinghandler.h ChangeLog tmw.cbp --- ChangeLog | 7 +++++++ src/commandhandler.cpp | 11 +++++++++++ src/localplayer.cpp | 2 +- src/net/beinghandler.cpp | 10 ++++++++++ src/net/beinghandler.h | 1 + src/net/gameserver/player.cpp | 22 ++++++++++++++++++++++ src/net/gameserver/player.h | 3 +++ src/net/protocol.h | 8 ++++++++ tmw.cbp | 4 ++++ 9 files changed, 67 insertions(+), 1 deletion(-) (limited to 'src/net/beinghandler.cpp') diff --git a/ChangeLog b/ChangeLog index f5f95cb3..5d2417f3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-10-15 David Athay + + * src/localplayer.cpp, src/net/beinghandler.cpp, src/net/protocol.h, + src/net/gameserver/player.h, src/net/gameserver/player.cpp, + src/net/beinghandler.h, tmw.cbp: Added communicating change of + direction to server. + 2008-10-10 Bjørn Lindeijer * src/gui/shop.cpp, src/gui/shop.h, src/resources/itemdb.cpp, diff --git a/src/commandhandler.cpp b/src/commandhandler.cpp index 7ec48f46..58b8905d 100644 --- a/src/commandhandler.cpp +++ b/src/commandhandler.cpp @@ -93,6 +93,17 @@ void CommandHandler::handleCommand(const std::string &command) { handleOp(args); } + else if (type == "post") + { + std::string::size_type pos = args.find(' '); + std::string recipient(args, 0, pos); + std::string text(args, pos+1); + Net::GameServer::Player::sendLetter(recipient, text); + } + else if (type == "check") + { + Net::GameServer::Player::getLetters(); + } else { chatWindow->chatLog("Unknown command"); diff --git a/src/localplayer.cpp b/src/localplayer.cpp index f596a8d9..d272caaf 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -283,7 +283,7 @@ void LocalPlayer::walk(unsigned char dir) else if (dir) { // If the being can't move, just change direction - // TODO: Communicate this to the server (waiting on tmwserv) + Net::GameServer::Player::changeDir(dir); setDirection(dir); } } diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 7e37aa27..fc3c7d1e 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -55,6 +55,7 @@ BeingHandler::BeingHandler() GPMSG_BEINGS_DAMAGE, GPMSG_BEING_ACTION_CHANGE, GPMSG_BEING_LOOKS_CHANGE, + GPMSG_BEING_DIR_CHANGE, 0 }; handledMessages = _messages; @@ -85,6 +86,9 @@ void BeingHandler::handleMessage(MessageIn &msg) case GPMSG_BEING_LOOKS_CHANGE: handleBeingLooksChangeMessage(msg); break; + case GPMSG_BEING_DIR_CHANGE: + handleBeingDirChangeMessage(msg); + break; } } @@ -319,3 +323,9 @@ void BeingHandler::handleBeingLooksChangeMessage(MessageIn &msg) handleLooks(static_cast< Player * >(being), msg); } +void BeingHandler::handleBeingDirChangeMessage(MessageIn &msg) +{ + Being *being = beingManager->findBeing(msg.readInt16()); + if (!being) return; + being->setDirection(msg.readInt8()); +} diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h index d2a332a8..8ac07017 100644 --- a/src/net/beinghandler.h +++ b/src/net/beinghandler.h @@ -41,6 +41,7 @@ class BeingHandler : public MessageHandler void handleBeingsDamageMessage(MessageIn &msg); void handleBeingActionChangeMessage(MessageIn &msg); void handleBeingLooksChangeMessage(MessageIn &msg); + void handleBeingDirChangeMessage(MessageIn &msg); }; #endif diff --git a/src/net/gameserver/player.cpp b/src/net/gameserver/player.cpp index d8050d2b..28fd954a 100644 --- a/src/net/gameserver/player.cpp +++ b/src/net/gameserver/player.cpp @@ -160,6 +160,21 @@ void Net::GameServer::Player::tradeWithNPC(int item, int amount) Net::GameServer::connection->send(msg); } +void Net::GameServer::Player::sendLetter(const std::string &player, + const std::string &text) +{ + MessageOut msg(PGMSG_SEND_POST); + msg.writeString(player); + msg.writeString(text); + Net::GameServer::connection->send(msg); +} + +void Net::GameServer::Player::getLetters() +{ + MessageOut msg(PGMSG_GET_POST); + Net::GameServer::connection->send(msg); +} + void Net::GameServer::Player::raiseAttribute(int attribute) { MessageOut msg(PGMSG_RAISE_ATTRIBUTE); @@ -179,3 +194,10 @@ void Net::GameServer::Player::respawn() MessageOut msg(PGMSG_RESPAWN); Net::GameServer::connection->send(msg); } + +void Net::GameServer::Player::changeDir(unsigned char dir) +{ + MessageOut msg(PGMSG_DIRECTION_CHANGE); + msg.writeInt8(dir); + Net::GameServer::connection->send(msg); +} diff --git a/src/net/gameserver/player.h b/src/net/gameserver/player.h index eea15c2b..fa8c1376 100644 --- a/src/net/gameserver/player.h +++ b/src/net/gameserver/player.h @@ -59,10 +59,13 @@ namespace Net void tradeItem(int slot, int amount); void tradeMoney(int amount); void tradeWithNPC(int item, int amount); + void sendLetter(const std::string &player, const std::string &text); + void getLetters(); void raiseAttribute(int attribute); void lowerAttribute(int attribute); void respawn(); static RespawnRequestListener respawnListener; + void changeDir(unsigned char dir); } } } diff --git a/src/net/protocol.h b/src/net/protocol.h index bd4eaa17..f766d2da 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -99,6 +99,8 @@ enum { PGMSG_WALK = 0x0260, // W*2 destination PGMSG_ACTION_CHANGE = 0x0270, // B Action GPMSG_BEING_ACTION_CHANGE = 0x0271, // W being id, B action + PGMSG_DIRECTION_CHANGE = 0x0272, // B Direction + GPMSG_BEING_DIR_CHANGE = 0x0273, // W being id, B direction GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, C position, B speed] [, W*2 destination] }* GPMSG_ITEMS = 0x0281, // { W item id, W*2 position }* PGMSG_ATTACK = 0x0290, // B direction @@ -180,6 +182,12 @@ enum { PCMSG_USER_MODE = 0x0465, // W channel id, S name, B mode PCMSG_KICK_USER = 0x0466, // W channel id, S name + // Post + PGMSG_SEND_POST = 0x04A0, // S player, S letter, { W attachment id } + GPMSG_SEND_POST_RESPONSE = 0x04A1, // B error + PGMSG_GET_POST = 0x04A2, // + GPMSG_GET_POST_RESPONSE = 0x04A3, // { L sender id, S letter, { W attachment id } } + XXMSG_INVALID = 0x7FFF }; diff --git a/tmw.cbp b/tmw.cbp index d3381da3..a6d2f7df 100644 --- a/tmw.cbp +++ b/tmw.cbp @@ -217,6 +217,8 @@ + +