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. --- 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 +++ 20 files changed, 330 insertions(+), 177 deletions(-) (limited to 'src') 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-60-g2f50