diff options
author | Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> | 2010-02-19 22:38:59 +0100 |
---|---|---|
committer | Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> | 2010-02-19 23:37:36 +0100 |
commit | 363527d0f95963ba3f4a6d25c8eabc1bb3ad4efe (patch) | |
tree | 117ce95d3587f913a64b71fe4dcdee716b8aea7e | |
parent | 432d16435774cafd630e287321e882f3e8510d16 (diff) | |
download | mana-363527d0f95963ba3f4a6d25c8eabc1bb3ad4efe.tar.gz mana-363527d0f95963ba3f4a6d25c8eabc1bb3ad4efe.tar.bz2 mana-363527d0f95963ba3f4a6d25c8eabc1bb3ad4efe.tar.xz mana-363527d0f95963ba3f4a6d25c8eabc1bb3ad4efe.zip |
Fixed a crash when trying to switch servers
Ownership of the charInfo global variable wasn't well defined. It was
being locked, unlocked and generally modified from a lot of places, and
somewhere in this mess it ended up crashing when switching servers.
Now the CharHandler instances, for eAthena and manaserv respectively,
own this list of characters. A new class, Net::Character wraps up the
slot index in combination with the player dummy. The list is passed on
to the CharSelectDialog each time it changes.
Both related and unrelated cleanups were made as well.
Reviewed-by: Jared Adams
32 files changed, 592 insertions, 671 deletions
@@ -292,7 +292,6 @@ ./src/keyboardconfig.h ./src/localplayer.cpp ./src/localplayer.h -./src/lockedarray.h ./src/log.cpp ./src/log.h ./src/main.cpp @@ -303,6 +302,7 @@ ./src/monster.cpp ./src/monster.h ./src/net/adminhandler.h +./src/net/charhandler.cpp ./src/net/charhandler.h ./src/net/chathandler.h ./src/net/download.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 221d7d8b..1273fe40 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -303,6 +303,7 @@ SET(SRCS gui/worldselectdialog.cpp gui/worldselectdialog.h net/adminhandler.h + net/charhandler.cpp net/charhandler.h net/chathandler.h net/download.cpp @@ -434,7 +435,6 @@ SET(SRCS keyboardconfig.h localplayer.cpp localplayer.h - lockedarray.h log.cpp log.h main.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 3b3773ab..8f7c7164 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -208,6 +208,7 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ gui/worldselectdialog.cpp \ gui/worldselectdialog.h \ net/adminhandler.h \ + net/charhandler.cpp \ net/charhandler.h \ net/chathandler.h \ net/download.cpp \ @@ -339,7 +340,6 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ keyboardconfig.h \ localplayer.cpp \ localplayer.h \ - lockedarray.h \ log.cpp \ log.h \ main.cpp \ diff --git a/src/being.cpp b/src/being.cpp index 42fb2d4e..495a81e0 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -814,10 +814,10 @@ int Being::getOffset(char pos, char neg) const if (mMap) { offset = (pos == LEFT && neg == RIGHT) ? - (int)((get_elapsed_time(mWalkTime) - * mMap->getTileWidth()) / mWalkSpeed.x) : - (int)((get_elapsed_time(mWalkTime) - * mMap->getTileHeight()) / mWalkSpeed.y); + (int)((get_elapsed_time(mWalkTime) + * mMap->getTileWidth()) / mWalkSpeed.x) : + (int)((get_elapsed_time(mWalkTime) + * mMap->getTileHeight()) / mWalkSpeed.y); } // We calculate the offset _from_ the _target_ location diff --git a/src/gui/charcreatedialog.cpp b/src/gui/charcreatedialog.cpp index 3d240271..8fb54f76 100644 --- a/src/gui/charcreatedialog.cpp +++ b/src/gui/charcreatedialog.cpp @@ -90,13 +90,13 @@ CharCreateDialog::CharCreateDialog(CharSelectDialog *parent, int slot): mFemale->addActionListener(this); mPlayerBox = new PlayerBox(mPlayer); - mPlayerBox->setWidth(74); mNameField->setActionEventId("create"); mNameField->addActionListener(this); - mAttributesLeft = new Label(strprintf(_("Please distribute %d points"), 99)); + mAttributesLeft = new Label( + strprintf(_("Please distribute %d points"), 99)); int w = 200; int h = 330; @@ -168,8 +168,9 @@ void CharCreateDialog::action(const gcn::ActionEvent &event) } Net::getCharHandler()->newCharacter(getName(), mSlot, - mFemale->isSelected(), mHairStyle, - mHairColor, atts); + mFemale->isSelected(), + mHairStyle, + mHairColor, atts); } else { @@ -246,11 +247,13 @@ void CharCreateDialog::updateSliders() mCreateButton->setEnabled(false); if (pointsLeft > 0) { - mAttributesLeft->setCaption(strprintf(_("Please distribute %d points"), pointsLeft)); + mAttributesLeft->setCaption( + strprintf(_("Please distribute %d points"), pointsLeft)); } else { - mAttributesLeft->setCaption(strprintf(_("Please remove %d points"), -pointsLeft)); + mAttributesLeft->setCaption( + strprintf(_("Please remove %d points"), -pointsLeft)); } } @@ -273,7 +276,7 @@ int CharCreateDialog::getDistributedPoints() const return points; } -void CharCreateDialog::setAttributes(std::vector<std::string> labels, +void CharCreateDialog::setAttributes(const std::vector<std::string> &labels, int available, int min, int max) { mMaxPoints = available; @@ -303,7 +306,8 @@ void CharCreateDialog::setAttributes(std::vector<std::string> labels, add(mAttributeLabel[i]); mAttributeSlider[i] = new Slider(min, max); - mAttributeSlider[i]->setDimension(gcn::Rectangle(75, 140 + i*20, 100, 10)); + mAttributeSlider[i]->setDimension(gcn::Rectangle(75, 140 + i * 20, + 100, 10)); mAttributeSlider[i]->setActionEventId("statslider"); mAttributeSlider[i]->addActionListener(this); add(mAttributeSlider[i]); @@ -346,11 +350,6 @@ void CharCreateDialog::setFixedGender(bool fixed, Gender gender) } } -void CharCreateDialog::success() -{ - mCharSelectDialog->update(mSlot); -} - void CharCreateDialog::updateHair() { mHairStyle %= Being::getNumOfHairstyles(); diff --git a/src/gui/charcreatedialog.h b/src/gui/charcreatedialog.h index c4838712..a6d4b49b 100644 --- a/src/gui/charcreatedialog.h +++ b/src/gui/charcreatedialog.h @@ -19,12 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef CHAR_CREATE_H -#define CHAR_CREATE_H +#ifndef CHAR_CREATE_DIALOG_H +#define CHAR_CREATE_DIALOG_H #include "player.h" #include "guichanfwd.h" -#include "lockedarray.h" #include "gui/charselectdialog.h" @@ -63,19 +62,12 @@ class CharCreateDialog : public Window, public gcn::ActionListener */ void unlock(); - void setAttributes(std::vector<std::string> labels, int available, + void setAttributes(const std::vector<std::string> &labels, + int available, int min, int max); void setFixedGender(bool fixed, Gender gender = GENDER_FEMALE); - /** - * Notify the CharSelectDialog the character was created successfully. - */ - void success(); - - CharSelectDialog *getSelectDialog() const - { return mCharSelectDialog; } - private: int getDistributedPoints() const; @@ -127,4 +119,4 @@ class CharCreateDialog : public Window, public gcn::ActionListener int mSlot; }; -#endif // CHAR_CREATE_H +#endif // CHAR_CREATE_DIALOG_H diff --git a/src/gui/charselectdialog.cpp b/src/gui/charselectdialog.cpp index 0489a6cb..dd2368ef 100644 --- a/src/gui/charselectdialog.cpp +++ b/src/gui/charselectdialog.cpp @@ -25,6 +25,7 @@ #include "localplayer.h" #include "main.h" #include "units.h" +#include "log.h" #include "gui/changeemaildialog.h" #include "gui/changepassworddialog.h" @@ -56,6 +57,7 @@ #include <guichan/font.hpp> #include <string> +#include <cassert> /** * Listener for confirming character deletion. @@ -63,48 +65,45 @@ class CharDeleteConfirm : public ConfirmDialog { public: - CharDeleteConfirm(CharSelectDialog *m): + CharDeleteConfirm(CharSelectDialog *m, int index): ConfirmDialog(_("Confirm Character Delete"), _("Are you sure you want to delete this character?"), m), - master(m) + mMaster(m), + mIndex(index) { } void action(const gcn::ActionEvent &event) { - //ConfirmDialog::action(event); if (event.getId() == "yes") - { - master->attemptCharDelete(); - } + mMaster->attemptCharacterDelete(mIndex); + ConfirmDialog::action(event); } private: - CharSelectDialog *master; + CharSelectDialog *mMaster; + int mIndex; }; -class CharEntry : public Container +class CharacterDisplay : public Container { public: - CharEntry(CharSelectDialog *m, char slot, LocalPlayer *chr); + CharacterDisplay(CharSelectDialog *charSelectDialog); - char getSlot() const - { return mSlot; } + void setCharacter(Net::Character *character); - LocalPlayer *getChar() const + Net::Character *getCharacter() const { return mCharacter; } - void setChar(LocalPlayer *chr); - void requestFocus(); + void setActive(bool active); + + private: void update(); - protected: - friend class CharSelectDialog; - char mSlot; - LocalPlayer *mCharacter; + Net::Character *mCharacter; PlayerBox *mPlayerBox; Label *mName; @@ -114,10 +113,11 @@ class CharEntry : public Container Button *mDelete; }; -CharSelectDialog::CharSelectDialog(LockedArray<LocalPlayer*> *charInfo, - LoginData *loginData): +CharSelectDialog::CharSelectDialog(LoginData *loginData): Window(_("Account and Character Management")), - mCharInfo(charInfo), + mLocked(false), + mUnregisterButton(0), + mChangeEmailButton(0), mLoginData(loginData), mCharHandler(Net::getCharHandler()) { @@ -128,12 +128,6 @@ CharSelectDialog::CharSelectDialog(LockedArray<LocalPlayer*> *charInfo, mChangePasswordButton = new Button(_("Change Password"), "change_password", this); - for (int i = 0; i < MAX_CHARACTER_COUNT; i++) - { - charInfo->select(i); - mCharEntries[i] = new CharEntry(this, i, charInfo->getEntry()); - } - int optionalActions = Net::getLoginHandler()->supportedOptionalActions(); ContainerPlacer place; @@ -144,79 +138,85 @@ CharSelectDialog::CharSelectDialog(LockedArray<LocalPlayer*> *charInfo, if (optionalActions & Net::LoginHandler::Unregister) { - gcn::Button *unregisterButton = new Button(_("Unregister"), - "unregister", this); - place(3, 1, unregisterButton); + mUnregisterButton = new Button(_("Unregister"), + "unregister", this); + place(3, 1, mUnregisterButton); } place(0, 2, mChangePasswordButton); if (optionalActions & Net::LoginHandler::ChangeEmail) { - gcn::Button *changeEmailButton = new Button(_("Change Email"), - "change_email", this); - place(3, 2, changeEmailButton); + mChangeEmailButton = new Button(_("Change Email"), + "change_email", this); + place(3, 2, mChangeEmailButton); } place = getPlacer(0, 1); - place(0, 0, mCharEntries[0]); - place(1, 0, mCharEntries[1]); - place(2, 0, mCharEntries[2]); + + for (int i = 0; i < MAX_CHARACTER_COUNT; i++) { + mCharacterEntries[i] = new CharacterDisplay(this); + place(i, 0, mCharacterEntries[i]); + } reflowLayout(); addKeyListener(this); center(); - mCharEntries[0]->requestFocus(); + mCharacterEntries[0]->requestFocus(); setVisible(true); Net::getCharHandler()->setCharSelectDialog(this); } +CharSelectDialog::~CharSelectDialog() +{ +} + void CharSelectDialog::action(const gcn::ActionEvent &event) { + // Check if a button of a character was pressed const gcn::Widget *sourceParent = event.getSource()->getParent(); + int selected = -1; + for (unsigned i = 0; i < MAX_CHARACTER_COUNT; ++i) + if (mCharacterEntries[i] == sourceParent) + selected = i; - // Update which character is selected when applicable - if (const CharEntry *entry = dynamic_cast<const CharEntry*>(sourceParent)) - mCharInfo->select(entry->getSlot()); + const std::string &eventId = event.getId(); - if (event.getId() == "use") - { - chooseSelected(); - } - else if (event.getId() == "switch") + if (selected != -1) { - mCharInfo->clear(); - state = STATE_SWITCH_LOGIN; - } - else if (event.getId() == "new") - { - if (!(mCharInfo->getEntry())) + if (eventId == "use") + { + attemptCharacterSelect(selected); + } + else if (eventId == "new" && !mCharacterEntries[selected]->getCharacter()) { // Start new character dialog CharCreateDialog *charCreateDialog = - new CharCreateDialog(this, mCharInfo->getPos()); + new CharCreateDialog(this, selected); mCharHandler->setCharCreateDialog(charCreateDialog); } - } - else if (event.getId() == "delete") - { - if (mCharInfo->getEntry()) + else if (eventId == "delete" + && mCharacterEntries[selected]->getCharacter()) { - new CharDeleteConfirm(this); + new CharDeleteConfirm(this, selected); } } - else if (event.getId() == "change_password") + else if (eventId == "switch") + { + state = STATE_SWITCH_LOGIN; + } + else if (eventId == "change_password") { state = STATE_CHANGEPASSWORD; } - else if (event.getId() == "change_email") + else if (eventId == "change_email") { state = STATE_CHANGEEMAIL; } - else if (event.getId() == "unregister") + else if (eventId == "unregister") { state = STATE_UNREGISTER; } @@ -228,90 +228,111 @@ void CharSelectDialog::keyPressed(gcn::KeyEvent &keyEvent) if (key.getValue() == Key::ESCAPE) { - action(gcn::ActionEvent(mSwitchLoginButton, mSwitchLoginButton->getActionEventId())); + action(gcn::ActionEvent(mSwitchLoginButton, + mSwitchLoginButton->getActionEventId())); } } -void CharSelectDialog::attemptCharDelete() +/** + * Communicate character deletion to the server. + */ +void CharSelectDialog::attemptCharacterDelete(int index) { - mCharHandler->deleteCharacter(mCharInfo->getPos(), mCharInfo->getEntry()); - mCharInfo->lock(); + if (mLocked) + return; + + mCharHandler->deleteCharacter(mCharacterEntries[index]->getCharacter()); + lock(); } -void CharSelectDialog::attemptCharSelect() +/** + * Communicate character selection to the server. + */ +void CharSelectDialog::attemptCharacterSelect(int index) { - mCharHandler->chooseCharacter(mCharInfo->getPos(), mCharInfo->getEntry()); - mCharInfo->lock(); + if (mLocked) + return; + + mCharHandler->chooseCharacter(mCharacterEntries[index]->getCharacter()); + lock(); } -bool CharSelectDialog::selectByName(const std::string &name) +void CharSelectDialog::setCharacters(const Net::Characters &characters) { - if (mCharInfo->isLocked()) - return false; - - unsigned int oldPos = mCharInfo->getPos(); + // Reset previous characters + for (int i = 0; i < MAX_CHARACTER_COUNT; ++i) + mCharacterEntries[i]->setCharacter(0); - mCharInfo->select(0); - do + Net::Characters::const_iterator i, i_end = characters.end(); + for (i = characters.begin(); i != i_end; ++i) { - LocalPlayer *player = mCharInfo->getEntry(); - - if (player && player->getName() == name) - { - mCharEntries[mCharInfo->getPos()]->requestFocus(); - return true; + Net::Character *character = *i; + if (character->slot >= MAX_CHARACTER_COUNT) { + logger->log("Warning: slot out of range: %d", character->slot); + continue; } - mCharInfo->next(); - } while (mCharInfo->getPos()); + mCharacterEntries[character->slot]->setCharacter(character); + } +} - mCharInfo->select(oldPos); +void CharSelectDialog::lock() +{ + assert(!mLocked); + setLocked(true); +} - return false; +void CharSelectDialog::unlock() +{ + setLocked(false); } -bool CharSelectDialog::chooseSelected() +void CharSelectDialog::setLocked(bool locked) { - if (!mCharInfo->getSize()) - return false; + mLocked = locked; - setVisible(false); - attemptCharSelect(); + mSwitchLoginButton->setEnabled(!locked); + mChangePasswordButton->setEnabled(!locked); + if (mUnregisterButton) + mUnregisterButton->setEnabled(!locked); + if (mChangeEmailButton) + mChangeEmailButton->setEnabled(!locked); - return true; + for (int i = 0; i < MAX_CHARACTER_COUNT; ++i) + mCharacterEntries[i]->setActive(!mLocked); } -void CharSelectDialog::update(int slot) +bool CharSelectDialog::selectByName(const std::string &name, + SelectAction action) { - if (slot >= 0 && slot < MAX_CHARACTER_COUNT) - { - mCharInfo->select(slot); - mCharEntries[slot]->setChar(mCharInfo->getEntry()); - mCharEntries[slot]->requestFocus(); - } - else - { - int slot = mCharInfo->getPos(); - for (int i = 0; i < MAX_CHARACTER_COUNT; i++) - { - mCharInfo->select(slot); - mCharEntries[slot]->setChar(mCharInfo->getEntry()); + if (mLocked) + return false; + + for (unsigned i = 0; i < MAX_CHARACTER_COUNT; ++i) { + if (Net::Character *character = mCharacterEntries[i]->getCharacter()) { + if (character->dummy->getName() == name) { + mCharacterEntries[i]->requestFocus(); + if (action == Choose) + attemptCharacterSelect(i); + return true; + } } - mCharInfo->select(slot); } + + return false; } -CharEntry::CharEntry(CharSelectDialog *m, char slot, LocalPlayer *chr): - mSlot(slot), - mCharacter(chr), - mPlayerBox(new PlayerBox(chr)) + +CharacterDisplay::CharacterDisplay(CharSelectDialog *charSelectDialog): + mCharacter(0), + mPlayerBox(new PlayerBox) { - mButton = new Button("wwwwwwwww", "go", m); + mButton = new Button("wwwwwwwww", "go", charSelectDialog); mName = new Label("wwwwwwwwwwwwwwwwwwwwwwww"); mLevel = new Label("(888)"); mMoney = new Label("wwwwwwwww"); - mDelete = new Button(_("Delete"), "delete", m); + mDelete = new Button(_("Delete"), "delete", charSelectDialog); LayoutHelper h(this); ContainerPlacer place = h.getPlacer(0, 0); @@ -337,29 +358,37 @@ CharEntry::CharEntry(CharSelectDialog *m, char slot, LocalPlayer *chr): mMoney->getHeight() + mButton->getHeight() + mDelete->getHeight()); } -void CharEntry::setChar(LocalPlayer *chr) +void CharacterDisplay::setCharacter(Net::Character *character) { - mCharacter = chr; - - mPlayerBox->setPlayer(chr); + if (mCharacter == character) + return; + mCharacter = character; + mPlayerBox->setPlayer(character ? character->dummy : 0); update(); } -void CharEntry::requestFocus() +void CharacterDisplay::requestFocus() { mButton->requestFocus(); } -void CharEntry::update() +void CharacterDisplay::setActive(bool active) +{ + mButton->setEnabled(active); + mDelete->setEnabled(active); +} + +void CharacterDisplay::update() { if (mCharacter) { + const LocalPlayer *character = mCharacter->dummy; mButton->setCaption(_("Choose")); mButton->setActionEventId("use"); - mName->setCaption(strprintf("%s", mCharacter->getName().c_str())); - mLevel->setCaption(strprintf("Level %d", mCharacter->getLevel())); - mMoney->setCaption(Units::formatCurrency(mCharacter->getMoney())); + mName->setCaption(strprintf("%s", character->getName().c_str())); + mLevel->setCaption(strprintf("Level %d", character->getLevel())); + mMoney->setCaption(Units::formatCurrency(character->getMoney())); mDelete->setVisible(true); } diff --git a/src/gui/charselectdialog.h b/src/gui/charselectdialog.h index fa9591bf..9e455462 100644 --- a/src/gui/charselectdialog.h +++ b/src/gui/charselectdialog.h @@ -23,16 +23,17 @@ #define CHAR_SELECT_H #include "guichanfwd.h" -#include "lockedarray.h" #include "main.h" #include "player.h" #include "gui/widgets/window.h" +#include "net/charhandler.h" + #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> -class CharEntry; +class CharacterDisplay; class LocalPlayer; class LoginData; class PlayerBox; @@ -51,49 +52,55 @@ class CharSelectDialog : public Window, public gcn::ActionListener, { public: friend class CharDeleteConfirm; + friend class Net::CharHandler; /** * Constructor. */ - CharSelectDialog(LockedArray<LocalPlayer*> *charInfo, - LoginData *loginData); + CharSelectDialog(LoginData *loginData); - ~CharSelectDialog() { mCharInfo->clear(); }; + ~CharSelectDialog(); void action(const gcn::ActionEvent &event); void keyPressed(gcn::KeyEvent &keyEvent); - bool selectByName(const std::string &name); + enum SelectAction { + Focus, + Choose + }; /** - * Send selection to character server - * @return false if the selection or the number of existing character - * is empty. - */ - bool chooseSelected(); - - void update(int slot = -1); + * Attempt to select the character with the given name. Returns whether + * a character with the given name was found. + * + * \param action determines what to do when a character with the given + * name was found (just focus or also try to choose this + * character). + */ + bool selectByName(const std::string &name, + SelectAction action = Focus); private: - /** - * Communicate character deletion to the server. - */ - void attemptCharDelete(); + void attemptCharacterDelete(int index); + void attemptCharacterSelect(int index); - /** - * Communicate character selection to the server. - */ - void attemptCharSelect(); + void setCharacters(const Net::Characters &characters); + + void lock(); + void unlock(); + void setLocked(bool locked); - LockedArray<LocalPlayer*> *mCharInfo; + bool mLocked; gcn::Label *mAccountNameLabel; gcn::Button *mSwitchLoginButton; gcn::Button *mChangePasswordButton; + gcn::Button *mUnregisterButton; + gcn::Button *mChangeEmailButton; - CharEntry *mCharEntries[MAX_CHARACTER_COUNT]; + CharacterDisplay *mCharacterEntries[MAX_CHARACTER_COUNT]; LoginData *mLoginData; diff --git a/src/gui/unregisterdialog.cpp b/src/gui/unregisterdialog.cpp index 11cb2c57..95e7e5f5 100644 --- a/src/gui/unregisterdialog.cpp +++ b/src/gui/unregisterdialog.cpp @@ -91,8 +91,7 @@ UnRegisterDialog::~UnRegisterDialog() delete mWrongDataNoticeListener; } -void -UnRegisterDialog::action(const gcn::ActionEvent &event) +void UnRegisterDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "cancel") { diff --git a/src/gui/widgets/playerbox.h b/src/gui/widgets/playerbox.h index 243668cf..d3329234 100644 --- a/src/gui/widgets/playerbox.h +++ b/src/gui/widgets/playerbox.h @@ -39,7 +39,7 @@ class PlayerBox : public gcn::ScrollArea * Constructor. Takes the initial player character that this box should * display, which defaults to <code>NULL</code>. */ - PlayerBox(const Player *player = NULL); + PlayerBox(const Player *player = 0); /** * Destructor. diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 4e70fc2f..30159f34 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -74,8 +74,8 @@ const short walkingKeyboardDelay = 1000; LocalPlayer *player_node = NULL; -LocalPlayer::LocalPlayer(int id, int job, Map *map): - Player(id, job, map), +LocalPlayer::LocalPlayer(int id, int job): + Player(id, job, 0), mEquipment(new Equipment), mInStorage(false), mAttackRange(0), @@ -795,7 +795,7 @@ void LocalPlayer::stopAttack() mLastTarget = -1; } -void LocalPlayer::raiseAttribute(size_t attr) +void LocalPlayer::raiseAttribute(int attr) { // we assume that the server allows the change. When not we will undo it later. mCharacterPoints--; @@ -805,7 +805,7 @@ void LocalPlayer::raiseAttribute(size_t attr) Net::getPlayerHandler()->increaseAttribute(attr); } -void LocalPlayer::lowerAttribute(size_t attr) +void LocalPlayer::lowerAttribute(int attr) { // we assume that the server allows the change. When not we will undo it later. mCorrectionPoints--; diff --git a/src/localplayer.h b/src/localplayer.h index d4aa258c..d9a56e34 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -105,7 +105,7 @@ class LocalPlayer : public Player /** * Constructor. */ - LocalPlayer(int id= 65535, int job = 0, Map *map = NULL); + LocalPlayer(int id= 65535, int job = 0); /** * Destructor. @@ -249,12 +249,12 @@ class LocalPlayer : public Player /** * Uses a character point to raise an attribute */ - void raiseAttribute(size_t attr); + void raiseAttribute(int attr); /** * Uses a correction point to lower an attribute */ - void lowerAttribute(size_t attr); + void lowerAttribute(int attr); void toggleSit(); void emote(Uint8 emotion); diff --git a/src/lockedarray.h b/src/lockedarray.h deleted file mode 100644 index 2190684f..00000000 --- a/src/lockedarray.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * The Mana World - * Copyright (C) 2004-2010 The Mana World Development Team - * - * This file is part of The Mana World. - * - * This program 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. - * - * 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 the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef LOCKEDARRAY_H -#define LOCKEDARRAY_H - -#include <algorithm> - -/** - * A _very_ basic array class that allows simple iteration and jumps, keeping - * its currently selected entry and providing a mechanism to lock this - * position. Anyone can unlock it though, so its your job to use it the right - * way ;) - */ - -template<class T> -class LockedArray -{ - public: - LockedArray(unsigned int size); - ~LockedArray(); - - void lock() { mLocked = true; }; - void unlock() { mLocked = false; }; - - bool isLocked() const { return mLocked; }; - - T getEntry() const { return mData[mCurEntry]; }; - void setEntry(T entry) { mData[mCurEntry] = entry; mFilled = true; }; - - void next(); - void prev(); - void select(unsigned int pos); - unsigned int getPos() const { return mCurEntry; } - - unsigned int getSize() const { return mSize; }; - - /** - * Clears the array without changing size or data type - */ - void clear(); - - protected: - unsigned int mSize; - - T* mData; - - unsigned int mCurEntry; - bool mLocked; - - bool mFilled; -}; - -template<class T> -LockedArray<T>::LockedArray(unsigned int size): - mSize(size), mData(new T[size]), mCurEntry(0), mLocked(false), - mFilled(false) -{ - std::fill_n(mData, mSize, (T)0); -} - -template<class T> -LockedArray<T>::~LockedArray() -{ - delete [] mData; -} - -template<class T> -void LockedArray<T>::next() -{ - if (mLocked) - return; - - if (++mCurEntry == mSize) - mCurEntry = 0; -} - -template<class T> -void LockedArray<T>::prev() -{ - if (mLocked) - return; - - mCurEntry = mCurEntry ? (--mCurEntry) : (mSize - 1); -} - -template<class T> -void LockedArray<T>::select(unsigned int pos) -{ - if (mLocked) - return; - - mCurEntry = pos; - if (mCurEntry >= mSize) - mCurEntry = 0; -} - -template<class T> -void LockedArray<T>::clear() -{ - if (!mFilled) return; - - delete [] mData; - - mData = new T[mSize]; - - std::fill_n(mData, mSize, (T)0); - - mCurEntry = 0; - - mLocked = false; -} -#endif diff --git a/src/main.cpp b/src/main.cpp index de133ecb..d4306f94 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,7 +28,6 @@ #include "itemshortcut.h" #include "keyboardconfig.h" #include "localplayer.h" -#include "lockedarray.h" #include "log.h" #ifdef USE_OPENGL #include "openglgraphics.h" @@ -135,7 +134,6 @@ Logger *logger; /**< Log object */ KeyboardConfig keyboard; LoginData loginData; -LockedArray<LocalPlayer*> charInfo(MAX_CHARACTER_COUNT); Palette *guiPalette; @@ -632,7 +630,7 @@ static void parseOptions(int argc, char *argv[], Options &options) class AccountListener : public gcn::ActionListener { public: - void action(const gcn::ActionEvent &event) + void action(const gcn::ActionEvent &) { state = STATE_CHAR_SELECT; } @@ -641,7 +639,7 @@ public: class LoginListener : public gcn::ActionListener { public: - void action(const gcn::ActionEvent &event) + void action(const gcn::ActionEvent &) { state = STATE_LOGIN; } @@ -649,7 +647,7 @@ public: } // namespace -void ErrorListener::action(const gcn::ActionEvent &event) +void ErrorListener::action(const gcn::ActionEvent &) { state = STATE_CHOOSE_SERVER; } @@ -664,8 +662,6 @@ static void accountLogin(LoginData *loginData) { logger->log("Username is %s", loginData->username.c_str()); - Net::getCharHandler()->setCharInfo(&charInfo); - // Send login infos if (loginData->registerLogin) Net::getLoginHandler()->registerAccount(loginData); @@ -847,7 +843,6 @@ int main(int argc, char *argv[]) oldstate != STATE_CHOOSE_SERVER && Net::getLoginHandler()->isConnected()) { - Net::getCharHandler()->setCharInfo(&charInfo); state = STATE_LOGIN; } else if (state == STATE_WORLD_SELECT && oldstate == STATE_UPDATE) @@ -1040,7 +1035,7 @@ int main(int argc, char *argv[]) case STATE_GET_CHARACTERS: logger->log("State: GET CHARACTERS"); - Net::getCharHandler()->getCharacters(); + Net::getCharHandler()->requestCharacters(); currentDialog = new ConnectionDialog( _("Requesting characters"), STATE_SWITCH_SERVER); @@ -1052,22 +1047,16 @@ int main(int argc, char *argv[]) // lower than the default value SkinLoader::instance()->setMinimumOpacity(0.8f); - currentDialog = - new CharSelectDialog(&charInfo, &loginData); + currentDialog = new CharSelectDialog(&loginData); - if (((CharSelectDialog*) currentDialog)-> - selectByName(options.character)) - { - ((CharSelectDialog*) currentDialog)->chooseSelected(); - } - else + if (!((CharSelectDialog*) currentDialog)->selectByName( + options.character, CharSelectDialog::Choose)) { - if (((CharSelectDialog*) currentDialog)->selectByName( - config.getValue("lastCharacter", ""))) - { - if (options.chooseDefault) - ((CharSelectDialog*) currentDialog)->chooseSelected(); - } + ((CharSelectDialog*) currentDialog)->selectByName( + config.getValue("lastCharacter", ""), + options.chooseDefault ? + CharSelectDialog::Choose : + CharSelectDialog::Focus); } break; @@ -1141,8 +1130,6 @@ int main(int argc, char *argv[]) case STATE_REGISTER_ATTEMPT: logger->log("Username is %s", loginData.username.c_str()); - - Net::getCharHandler()->setCharInfo(&charInfo); Net::getLoginHandler()->registerAccount(&loginData); break; @@ -1232,7 +1219,7 @@ int main(int argc, char *argv[]) // Done with game Net::getGameHandler()->disconnect(); - Net::getCharHandler()->getCharacters(); + Net::getCharHandler()->requestCharacters(); break; case STATE_LOGOUT_ATTEMPT: diff --git a/src/net/charhandler.cpp b/src/net/charhandler.cpp new file mode 100644 index 00000000..8cf756ba --- /dev/null +++ b/src/net/charhandler.cpp @@ -0,0 +1,38 @@ +/* + * The Mana World + * Copyright (C) 2010 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program 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. + * + * 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 the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "net/charhandler.h" + +#include "gui/charselectdialog.h" + +using namespace Net; + +void CharHandler::updateCharSelectDialog() +{ + if (mCharSelectDialog) + mCharSelectDialog->setCharacters(mCharacters); +} + +void CharHandler::unlockCharSelectDialog() +{ + if (mCharSelectDialog) + mCharSelectDialog->unlock(); +} diff --git a/src/net/charhandler.h b/src/net/charhandler.h index a55e8d86..dfe0882f 100644 --- a/src/net/charhandler.h +++ b/src/net/charhandler.h @@ -23,7 +23,6 @@ #define CHARHANDLER_H #include "localplayer.h" -#include "lockedarray.h" #include "logindata.h" #include <iosfwd> @@ -35,34 +34,73 @@ class LocalPlayer; namespace Net { +/** + * A structure to hold information about a character. + */ +struct Character +{ + Character() : + slot(0), + dummy(new LocalPlayer) + { + } + + ~Character() + { + delete dummy; + } + + int slot; /**< The index in the list of characters */ + LocalPlayer *dummy; /**< A dummy representing this character */ +}; + +typedef std::list<Character*> Characters; + class CharHandler { public: - virtual void setCharInfo(LockedArray<LocalPlayer*> *charInfo) = 0; - virtual void setCharSelectDialog(CharSelectDialog *window) = 0; virtual void setCharCreateDialog(CharCreateDialog *window) = 0; - virtual void getCharacters() = 0; + virtual void requestCharacters() = 0; - virtual void chooseCharacter(int slot, LocalPlayer *character) = 0; + virtual void chooseCharacter(Net::Character *character) = 0; virtual void newCharacter(const std::string &name, int slot, - bool gender, int hairstyle, int hairColor, - std::vector<int> stats) = 0; + bool gender, int hairstyle, int hairColor, + const std::vector<int> &stats) = 0; - virtual void deleteCharacter(int slot, LocalPlayer* character) = 0; + virtual void deleteCharacter(Net::Character *character) = 0; virtual void switchCharacter() = 0; - virtual unsigned int baseSprite() const = 0; + virtual int baseSprite() const = 0; - virtual unsigned int hairSprite() const = 0; + virtual int hairSprite() const = 0; - virtual unsigned int maxSprite() const = 0; + virtual int maxSprite() const = 0; virtual ~CharHandler() {} + + protected: + CharHandler(): + mSelectedCharacter(0), + mCharSelectDialog(0), + mCharCreateDialog(0) + {} + + void updateCharSelectDialog(); + void unlockCharSelectDialog(); + + /** The list of available characters. */ + Net::Characters mCharacters; + + /** The selected character. */ + Net::Character *mSelectedCharacter; + + CharSelectDialog *mCharSelectDialog; + CharCreateDialog *mCharCreateDialog; }; } // namespace Net diff --git a/src/net/ea/charserverhandler.cpp b/src/net/ea/charserverhandler.cpp index 106d0c8e..a49a55ac 100644 --- a/src/net/ea/charserverhandler.cpp +++ b/src/net/ea/charserverhandler.cpp @@ -39,6 +39,7 @@ #include "resources/colordb.h" +#include "utils/dtor.h" #include "utils/gettext.h" #include "utils/stringutils.h" @@ -49,9 +50,7 @@ namespace EAthena { extern ServerInfo charServer; extern ServerInfo mapServer; -CharServerHandler::CharServerHandler(): - mCharSelectDialog(0), - mCharCreateDialog(0) +CharServerHandler::CharServerHandler() { static const Uint16 _messages[] = { SMSG_CHAR_LOGIN, @@ -69,30 +68,32 @@ CharServerHandler::CharServerHandler(): void CharServerHandler::handleMessage(Net::MessageIn &msg) { - int count, slot; - LocalPlayer *tempPlayer; - logger->log("CharServerHandler: Packet ID: %x, Length: %d", - msg.getId(), msg.getLength()); + msg.getId(), msg.getLength()); + switch (msg.getId()) { - case SMSG_CHAR_LOGIN: - msg.skip(2); // Length word - msg.skip(20); // Unused + case SMSG_CHAR_LOGIN: + { + msg.skip(2); // Length word + msg.skip(20); // Unused - // Derive number of characters from message length - count = (msg.getLength() - 24) / 106; + // Derive number of characters from message length + const int count = (msg.getLength() - 24) / 106; - for (int i = 0; i < count; i++) - { - tempPlayer = readPlayerData(msg, slot); - mCharInfo->select(slot); - mCharInfo->setEntry(tempPlayer); - logger->log("CharServer: Player: %s (%d)", - tempPlayer->getName().c_str(), slot); - } + for (int i = 0; i < count; ++i) + { + Net::Character *character = new Net::Character; + int slot; + character->dummy = readPlayerData(msg, &slot); + character->slot = slot; + mCharacters.push_back(character); + logger->log("CharServer: Player: %s (%d)", + character->dummy->getName().c_str(), slot); + } - state = STATE_CHAR_SELECT; + state = STATE_CHAR_SELECT; + } break; case SMSG_CHAR_LOGIN_ERROR: @@ -108,81 +109,75 @@ void CharServerHandler::handleMessage(Net::MessageIn &msg) errorMessage = _("Unknown failure to select character."); break; } - mCharInfo->unlock(); + unlockCharSelectDialog(); break; case SMSG_CHAR_CREATE_SUCCEEDED: - tempPlayer = readPlayerData(msg, slot); - mCharInfo->unlock(); - mCharInfo->select(slot); - mCharInfo->setEntry(tempPlayer); - - // Close the character create dialog - if (mCharCreateDialog) { - mCharCreateDialog->success(); - mCharCreateDialog->scheduleDelete(); - mCharCreateDialog = 0; + Net::Character *character = new Net::Character; + int slot; + character->dummy = readPlayerData(msg, &slot); + character->slot = slot; + mCharacters.push_back(character); + + updateCharSelectDialog(); + + // Close the character create dialog + if (mCharCreateDialog) + { + mCharCreateDialog->scheduleDelete(); + mCharCreateDialog = 0; + } } break; case SMSG_CHAR_CREATE_FAILED: new OkDialog(_("Error"), _("Failed to create character. Most " "likely the name is already taken.")); - if (mCharCreateDialog) mCharCreateDialog->unlock(); break; case SMSG_CHAR_DELETE_SUCCEEDED: - tempPlayer = mCharInfo->getEntry(); - mCharInfo->setEntry(0); - mCharInfo->unlock(); - if (mCharSelectDialog) - mCharSelectDialog->update(mCharInfo->getPos()); + delete mSelectedCharacter; + mCharacters.remove(mSelectedCharacter); + mSelectedCharacter = 0; + updateCharSelectDialog(); + unlockCharSelectDialog(); new OkDialog(_("Info"), _("Character deleted.")); - delete tempPlayer; break; case SMSG_CHAR_DELETE_FAILED: - mCharInfo->unlock(); + unlockCharSelectDialog(); new OkDialog(_("Error"), _("Failed to delete character.")); break; case SMSG_CHAR_MAP_INFO: - player_node = mCharInfo->getEntry(); - slot = mCharInfo->getPos(); msg.skip(4); // CharID, must be the same as player_node->charID map_path = msg.readString(16); mapServer.hostname = ipToString(msg.readInt32()); mapServer.port = msg.readInt16(); - mCharInfo->unlock(); - mCharInfo->select(0); - // Clear unselected players infos - do - { - LocalPlayer *tmp = mCharInfo->getEntry(); - if (tmp != player_node) - { - delete tmp; - mCharInfo->setEntry(0); - } - mCharInfo->next(); - } while (mCharInfo->getPos()); - mCharInfo->select(slot); + // Prevent the selected local player from being deleted + player_node = mSelectedCharacter->dummy; + mSelectedCharacter->dummy = 0; + + delete_all(mCharacters); + mCharacters.clear(); + updateCharSelectDialog(); + mNetwork->disconnect(); state = STATE_CONNECT_GAME; break; } } -LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int &slot) +LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int *slot) { const Token &token = static_cast<LoginHandler*>(Net::getLoginHandler())->getToken(); - LocalPlayer *tempPlayer = new LocalPlayer(msg.readInt32(), 0, NULL); + LocalPlayer *tempPlayer = new LocalPlayer(msg.readInt32(), 0); tempPlayer->setGender(token.sex); tempPlayer->setExp(msg.readInt32()); @@ -219,7 +214,7 @@ LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int &slot) tempPlayer->setName(msg.readString(24)); for (int i = 0; i < 6; i++) tempPlayer->setAttributeBase(i + STR, msg.readInt8(), false); - slot = msg.readInt8(); // character slot + *slot = msg.readInt8(); // character slot msg.readInt8(); // unknown return tempPlayer; @@ -228,6 +223,7 @@ LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int &slot) void CharServerHandler::setCharSelectDialog(CharSelectDialog *window) { mCharSelectDialog = window; + updateCharSelectDialog(); } void CharServerHandler::setCharCreateDialog(CharCreateDialog *window) @@ -252,19 +248,22 @@ void CharServerHandler::setCharCreateDialog(CharCreateDialog *window) mCharCreateDialog->setFixedGender(true, token.sex); } -void CharServerHandler::getCharacters() +void CharServerHandler::requestCharacters() { connect(); } -void CharServerHandler::chooseCharacter(int slot, LocalPlayer *) +void CharServerHandler::chooseCharacter(Net::Character *character) { + mSelectedCharacter = character; + MessageOut outMsg(CMSG_CHAR_SELECT); - outMsg.writeInt8(slot); + outMsg.writeInt8(mSelectedCharacter->slot); } void CharServerHandler::newCharacter(const std::string &name, int slot, - bool gender, int hairstyle, int hairColor, std::vector<int> stats) + bool gender, int hairstyle, int hairColor, + const std::vector<int> &stats) { MessageOut outMsg(CMSG_CHAR_CREATE); outMsg.writeString(name, 24); @@ -277,10 +276,12 @@ void CharServerHandler::newCharacter(const std::string &name, int slot, outMsg.writeInt16(hairstyle); } -void CharServerHandler::deleteCharacter(int slot, LocalPlayer *character) +void CharServerHandler::deleteCharacter(Net::Character *character) { + mSelectedCharacter = character; + MessageOut outMsg(CMSG_CHAR_DELETE); - outMsg.writeInt32(character->getId()); + outMsg.writeInt32(mSelectedCharacter->dummy->getId()); outMsg.writeString("a@a.com", 40); } @@ -291,17 +292,17 @@ void CharServerHandler::switchCharacter() outMsg.writeInt8(1); } -unsigned int CharServerHandler::baseSprite() const +int CharServerHandler::baseSprite() const { return SPRITE_BASE; } -unsigned int CharServerHandler::hairSprite() const +int CharServerHandler::hairSprite() const { return SPRITE_HAIR; } -unsigned int CharServerHandler::maxSprite() const +int CharServerHandler::maxSprite() const { return SPRITE_VECTOREND; } diff --git a/src/net/ea/charserverhandler.h b/src/net/ea/charserverhandler.h index b159c63b..d96da452 100644 --- a/src/net/ea/charserverhandler.h +++ b/src/net/ea/charserverhandler.h @@ -42,9 +42,6 @@ class CharServerHandler : public MessageHandler, public Net::CharHandler virtual void handleMessage(Net::MessageIn &msg); - void setCharInfo(LockedArray<LocalPlayer*> *charInfo) - { mCharInfo = charInfo; } - void setCharSelectDialog(CharSelectDialog *window); /** @@ -54,31 +51,28 @@ class CharServerHandler : public MessageHandler, public Net::CharHandler */ void setCharCreateDialog(CharCreateDialog *window); - void getCharacters(); + void requestCharacters(); - void chooseCharacter(int slot, LocalPlayer* character); + void chooseCharacter(Net::Character *character); void newCharacter(const std::string &name, int slot, bool gender, - int hairstyle, int hairColor, std::vector<int> stats); + int hairstyle, int hairColor, + const std::vector<int> &stats); - void deleteCharacter(int slot, LocalPlayer* character); + void deleteCharacter(Net::Character *character); void switchCharacter(); - unsigned int baseSprite() const; + int baseSprite() const; - unsigned int hairSprite() const; + int hairSprite() const; - unsigned int maxSprite() const; + int maxSprite() const; void connect(); - protected: - LockedArray<LocalPlayer*> *mCharInfo; - CharSelectDialog *mCharSelectDialog; - CharCreateDialog *mCharCreateDialog; - - LocalPlayer *readPlayerData(Net::MessageIn &msg, int &slot); + private: + LocalPlayer *readPlayerData(Net::MessageIn &msg, int *slot); }; } // namespace EAthena diff --git a/src/net/ea/playerhandler.cpp b/src/net/ea/playerhandler.cpp index 34e0daf4..8de15d2b 100644 --- a/src/net/ea/playerhandler.cpp +++ b/src/net/ea/playerhandler.cpp @@ -556,7 +556,7 @@ void PlayerHandler::emote(int emoteId) outMsg.writeInt8(emoteId); } -void PlayerHandler::increaseAttribute(size_t attr) +void PlayerHandler::increaseAttribute(int attr) { if (attr >= STR && attr <= LUK) { @@ -566,7 +566,7 @@ void PlayerHandler::increaseAttribute(size_t attr) } } -void PlayerHandler::decreaseAttribute(size_t attr) +void PlayerHandler::decreaseAttribute(int attr) { // Supported by eA? } diff --git a/src/net/ea/playerhandler.h b/src/net/ea/playerhandler.h index 9e7e9ac3..bbfbc74c 100644 --- a/src/net/ea/playerhandler.h +++ b/src/net/ea/playerhandler.h @@ -37,31 +37,23 @@ class PlayerHandler : public MessageHandler, public Net::PlayerHandler void handleMessage(Net::MessageIn &msg); void attack(int id); - void emote(int emoteId); - void increaseAttribute(size_t attr); - - void decreaseAttribute(size_t attr); - + void increaseAttribute(int attr); + void decreaseAttribute(int attr); void increaseSkill(int skillId); void pickUp(FloorItem *floorItem); - void setDirection(char direction); - void setDestination(int x, int y, int direction = -1); - void changeAction(Being::Action action); void respawn(); void ignorePlayer(const std::string &player, bool ignore); - void ignoreAll(bool ignore); bool canUseMagic(); - bool canCorrectAttributes(); int getJobLocation(); diff --git a/src/net/manaserv/beinghandler.cpp b/src/net/manaserv/beinghandler.cpp index 5f9d1586..ae5bbc0e 100644 --- a/src/net/manaserv/beinghandler.cpp +++ b/src/net/manaserv/beinghandler.cpp @@ -114,7 +114,7 @@ Vector BeingHandler::giveSpeedInPixelsPerTicks(float speedInTilesPerSeconds) { speedInTicks.x = speedInTicks.y = 0; logger->log("Manaserv::BeingHandler: Speed wasn't given back" - " because game/Map not initialized."); + " because game/Map not initialized."); } // We don't use z for now. speedInTicks.z = 0; diff --git a/src/net/manaserv/charhandler.cpp b/src/net/manaserv/charhandler.cpp index 122ee10b..7a75e38d 100644 --- a/src/net/manaserv/charhandler.cpp +++ b/src/net/manaserv/charhandler.cpp @@ -41,25 +41,10 @@ #include "resources/colordb.h" +#include "utils/dtor.h" #include "utils/gettext.h" extern Net::CharHandler *charHandler; - -struct CharInfo { - unsigned char slot; - std::string name; - Gender gender; - int hs, hc; - unsigned short level; - unsigned short charPoints; - unsigned short corrPoints; - unsigned int money; - unsigned char attr[7]; -}; - -typedef std::vector<CharInfo> CharInfos; -CharInfos chars; - extern ManaServ::GameHandler *gameHandler; namespace ManaServ { @@ -71,9 +56,7 @@ extern std::string netToken; extern ServerInfo gameServer; extern ServerInfo chatServer; -CharHandler::CharHandler(): - mCharSelectDialog(0), - mCharCreateDialog(0) +CharHandler::CharHandler() { static const Uint16 _messages[] = { APMSG_CHAR_CREATE_RESPONSE, @@ -91,104 +74,54 @@ void CharHandler::handleMessage(Net::MessageIn &msg) switch (msg.getId()) { case APMSG_CHAR_CREATE_RESPONSE: - handleCharCreateResponse(msg); + handleCharacterCreateResponse(msg); break; case APMSG_CHAR_DELETE_RESPONSE: - { - int errMsg = msg.readInt8(); - // Character deletion successful - if (errMsg == ERRMSG_OK) - { - LocalPlayer *tempPlayer = mCharInfo->getEntry(); - mCharInfo->setEntry(0); - mCharInfo->unlock(); - if (mCharSelectDialog) - mCharSelectDialog->update(mCharInfo->getPos()); - new OkDialog(_("Info"), _("Player deleted.")); - delete tempPlayer; - } - // Character deletion failed - else - { - std::string errorMessage = ""; - switch (errMsg) - { - case ERRMSG_NO_LOGIN: - errorMessage = _("Not logged in."); - break; - case ERRMSG_INVALID_ARGUMENT: - errorMessage = _("Selection out of range."); - break; - default: - errorMessage = _("Unknown error."); - } - mCharInfo->unlock(); - new OkDialog(_("Error"), errorMessage); - } - } + handleCharacterDeleteResponse(msg); break; case APMSG_CHAR_INFO: - { - CharInfo info; - info.slot = msg.readInt8(); // character slot - info.name = msg.readString(); - info.gender = msg.readInt8() == GENDER_MALE ? GENDER_MALE : - GENDER_FEMALE; - info.hs = msg.readInt8(); - info.hc = msg.readInt8(); - info.level = msg.readInt16(); - info.charPoints = msg.readInt16(); - info.corrPoints = msg.readInt16(); - info.money = msg.readInt32(); - - for (int i = 0; i < 7; i++) - { - info.attr[i] = msg.readInt8(); - } - - chars.push_back(info); - - if (mCharSelectDialog) - { - mCharInfo->select(info.slot); - - LocalPlayer *tempPlayer = new LocalPlayer(); - tempPlayer->setName(info.name); - tempPlayer->setGender(info.gender); - tempPlayer->setSprite(SPRITE_HAIR, info.hs * -1, - ColorDB::get(info.hc)); - tempPlayer->setLevel(info.level); - tempPlayer->setCharacterPoints(info.charPoints); - tempPlayer->setCorrectionPoints(info.corrPoints); - tempPlayer->setMoney(info.money); - - for (int i = 0; i < 7; i++) - { - tempPlayer->setAttributeBase(i, info.attr[i], false); - } - - mCharInfo->setEntry(tempPlayer); - - mCharSelectDialog->update(info.slot); - } - } + handleCharacterInfo(msg); break; case APMSG_CHAR_SELECT_RESPONSE: - handleCharSelectResponse(msg); + handleCharacterSelectResponse(msg); break; } } -void CharHandler::handleCharCreateResponse(Net::MessageIn &msg) +void CharHandler::handleCharacterInfo(Net::MessageIn &msg) { - int errMsg = msg.readInt8(); + CachedCharacterInfo info; + info.slot = msg.readInt8(); + info.name = msg.readString(); + info.gender = msg.readInt8() == GENDER_MALE ? GENDER_MALE : + GENDER_FEMALE; + info.hairStyle = msg.readInt8(); + info.hairColor = msg.readInt8(); + info.level = msg.readInt16(); + info.characterPoints = msg.readInt16(); + info.correctionPoints = msg.readInt16(); + info.money = msg.readInt32(); + + for (int i = 0; i < 7; i++) + { + info.attribute[i] = msg.readInt8(); + } + + mCachedCharacterInfos.push_back(info); + + updateCharacters(); +} + +void CharHandler::handleCharacterCreateResponse(Net::MessageIn &msg) +{ + const int errMsg = msg.readInt8(); - // Character creation failed if (errMsg != ERRMSG_OK) { + // Character creation failed std::string errorMessage = ""; switch (errMsg) { @@ -233,17 +166,48 @@ void CharHandler::handleCharCreateResponse(Net::MessageIn &msg) } else { + // Close the character create dialog if (mCharCreateDialog) { - mCharCreateDialog->success(); mCharCreateDialog->scheduleDelete(); mCharCreateDialog = 0; } } +} +void CharHandler::handleCharacterDeleteResponse(Net::MessageIn &msg) +{ + int errMsg = msg.readInt8(); + if (errMsg == ERRMSG_OK) + { + // Character deletion successful + delete mSelectedCharacter; + mCharacters.remove(mSelectedCharacter); + updateCharSelectDialog(); + unlockCharSelectDialog(); + new OkDialog(_("Info"), _("Player deleted.")); + } + else + { + // Character deletion failed + std::string errorMessage = ""; + switch (errMsg) + { + case ERRMSG_NO_LOGIN: + errorMessage = _("Not logged in."); + break; + case ERRMSG_INVALID_ARGUMENT: + errorMessage = _("Selection out of range."); + break; + default: + errorMessage = strprintf(_("Unknown error (%d)."), errMsg); + } + new OkDialog(_("Error"), errorMessage); + } + mSelectedCharacter = 0; } -void CharHandler::handleCharSelectResponse(Net::MessageIn &msg) +void CharHandler::handleCharacterSelectResponse(Net::MessageIn &msg) { int errMsg = msg.readInt8(); @@ -265,31 +229,20 @@ void CharHandler::handleCharSelectResponse(Net::MessageIn &msg) gameServerConnection->connect(gameServer.hostname, gameServer.port); chatServerConnection->connect(chatServer.hostname, chatServer.port); - // Keep the selected character and delete the others - player_node = mCharInfo->getEntry(); - int slot = mCharInfo->getPos(); - mCharInfo->unlock(); - mCharInfo->select(0); - - do { - LocalPlayer *tmp = mCharInfo->getEntry(); - if (tmp != player_node) - { - delete tmp; - mCharInfo->setEntry(0); - } - mCharInfo->next(); - } while (mCharInfo->getPos()); - mCharInfo->select(slot); - - mCharInfo->clear(); //player_node will be deleted by ~Game + // Prevent the selected local player from being deleted + player_node = mSelectedCharacter->dummy; + mSelectedCharacter->dummy = 0; + + mCachedCharacterInfos.clear(); + updateCharacters(); state = STATE_CONNECT_GAME; } - else if(errMsg == ERRMSG_FAILURE) + else if (errMsg == ERRMSG_FAILURE) { errorMessage = _("No gameservers are available."); - mCharInfo->clear(); + delete_all(mCharacters); + mCharacters.clear(); state = STATE_ERROR; } } @@ -297,13 +250,15 @@ void CharHandler::handleCharSelectResponse(Net::MessageIn &msg) void CharHandler::setCharSelectDialog(CharSelectDialog *window) { mCharSelectDialog = window; + updateCharacters(); } void CharHandler::setCharCreateDialog(CharCreateDialog *window) { mCharCreateDialog = window; - if (!mCharCreateDialog) return; + if (!mCharCreateDialog) + return; std::vector<std::string> attributes; attributes.push_back(_("Strength:")); @@ -316,59 +271,34 @@ void CharHandler::setCharCreateDialog(CharCreateDialog *window) mCharCreateDialog->setAttributes(attributes, 60, 1, 20); } -void CharHandler::getCharacters() +void CharHandler::requestCharacters() { if (!accountServerConnection->isConnected()) + { Net::getLoginHandler()->connect(); + } else { - mCharInfo->unlock(); - LocalPlayer *tempPlayer; - for (CharInfos::const_iterator it = chars.begin(); it != chars.end(); it++) - { - const CharInfo info = (CharInfo) (*it); - mCharInfo->select(info.slot); - - tempPlayer = new LocalPlayer(); - tempPlayer->setName(info.name); - tempPlayer->setGender(info.gender); - tempPlayer->setSprite(SPRITE_HAIR, info.hs * -1, - ColorDB::get(info.hc)); - tempPlayer->setLevel(info.level); - tempPlayer->setCharacterPoints(info.charPoints); - tempPlayer->setCorrectionPoints(info.corrPoints); - tempPlayer->setMoney(info.money); - - for (int i = 0; i < 7; i++) - { - tempPlayer->setAttributeBase(i, info.attr[i], false); - } - - mCharInfo->setEntry(tempPlayer); - } - - // Close the character create dialog - if (mCharCreateDialog) - { - mCharCreateDialog->scheduleDelete(); - mCharCreateDialog = 0; - } - + // The characters are already there, continue to character selection state = STATE_CHAR_SELECT; } } -void CharHandler::chooseCharacter(int slot, LocalPlayer* character) +void CharHandler::chooseCharacter(Net::Character *character) { - MessageOut msg(PAMSG_CHAR_SELECT); - - msg.writeInt8(slot); + mSelectedCharacter = character; + MessageOut msg(PAMSG_CHAR_SELECT); + msg.writeInt8(mSelectedCharacter->slot); accountServerConnection->send(msg); } -void CharHandler::newCharacter(const std::string &name, int slot, bool gender, - int hairstyle, int hairColor, std::vector<int> stats) +void CharHandler::newCharacter(const std::string &name, + int /* slot */, + bool gender, + int hairstyle, + int hairColor, + const std::vector<int> &stats) { MessageOut msg(PAMSG_CHAR_CREATE); @@ -386,12 +316,12 @@ void CharHandler::newCharacter(const std::string &name, int slot, bool gender, accountServerConnection->send(msg); } -void CharHandler::deleteCharacter(int slot, LocalPlayer* character) +void CharHandler::deleteCharacter(Net::Character *character) { - MessageOut msg(PAMSG_CHAR_DELETE); - - msg.writeInt8(slot); + mSelectedCharacter = character; + MessageOut msg(PAMSG_CHAR_DELETE); + msg.writeInt8(mSelectedCharacter->slot); accountServerConnection->send(msg); } @@ -400,19 +330,56 @@ void CharHandler::switchCharacter() gameHandler->quit(true); } -unsigned int CharHandler::baseSprite() const +int CharHandler::baseSprite() const { return SPRITE_BASE; } -unsigned int CharHandler::hairSprite() const +int CharHandler::hairSprite() const { return SPRITE_HAIR; } -unsigned int CharHandler::maxSprite() const +int CharHandler::maxSprite() const { return SPRITE_VECTOREND; } +void CharHandler::updateCharacters() +{ + // Delete previous characters + delete_all(mCharacters); + mCharacters.clear(); + + if (!mCharSelectDialog) + return; + + // Create new characters and initialize them from the cached infos + for (unsigned i = 0; i < mCachedCharacterInfos.size(); ++i) + { + const CachedCharacterInfo &info = mCachedCharacterInfos.at(i); + + Net::Character *character = new Net::Character; + character->slot = info.slot; + LocalPlayer *player = character->dummy; + player->setName(info.name); + player->setGender(info.gender); + player->setSprite(SPRITE_HAIR, info.hairStyle * -1, + ColorDB::get(info.hairColor)); + player->setLevel(info.level); + player->setCharacterPoints(info.characterPoints); + player->setCorrectionPoints(info.correctionPoints); + player->setMoney(info.money); + + for (int i = 0; i < 7; i++) + { + player->setAttributeBase(i, info.attribute[i], false); + } + + mCharacters.push_back(character); + } + + updateCharSelectDialog(); +} + } // namespace ManaServ diff --git a/src/net/manaserv/charhandler.h b/src/net/manaserv/charhandler.h index 74f68f55..4a1af307 100644 --- a/src/net/manaserv/charhandler.h +++ b/src/net/manaserv/charhandler.h @@ -42,11 +42,6 @@ class CharHandler : public MessageHandler, public Net::CharHandler void handleMessage(Net::MessageIn &msg); - void setCharInfo(LockedArray<LocalPlayer*> *charInfo) - { - mCharInfo = charInfo; - } - void setCharSelectDialog(CharSelectDialog *window); /** @@ -56,32 +51,52 @@ class CharHandler : public MessageHandler, public Net::CharHandler */ void setCharCreateDialog(CharCreateDialog *window); - void getCharacters(); + void requestCharacters(); - void chooseCharacter(int slot, LocalPlayer* character); + void chooseCharacter(Net::Character *character); void newCharacter(const std::string &name, int slot, - bool gender, int hairstyle, int hairColor, - std::vector<int> stats); + bool gender, int hairstyle, int hairColor, + const std::vector<int> &stats); - void deleteCharacter(int slot, LocalPlayer* character); + void deleteCharacter(Net::Character *character); void switchCharacter(); - unsigned int baseSprite() const; - - unsigned int hairSprite() const; - - unsigned int maxSprite() const; + int baseSprite() const; - protected: - void handleCharCreateResponse(Net::MessageIn &msg); + int hairSprite() const; - void handleCharSelectResponse(Net::MessageIn &msg); + int maxSprite() const; - LockedArray<LocalPlayer*> *mCharInfo; - CharSelectDialog *mCharSelectDialog; - CharCreateDialog *mCharCreateDialog; + private: + /** + * Character information needs to be cached since we receive it before + * we have loaded the dynamic data, so we can't resolve load any + * sprites yet. + */ + struct CachedCharacterInfo { + int slot; + std::string name; + Gender gender; + int hairStyle; + int hairColor; + int level; + int characterPoints; + int correctionPoints; + int money; + int attribute[7]; + }; + + void handleCharacterInfo(Net::MessageIn &msg); + void handleCharacterCreateResponse(Net::MessageIn &msg); + void handleCharacterDeleteResponse(Net::MessageIn &msg); + void handleCharacterSelectResponse(Net::MessageIn &msg); + + void updateCharacters(); + + /** Cached character information */ + std::vector<CachedCharacterInfo> mCachedCharacterInfos; }; } // namespace ManaServ diff --git a/src/net/manaserv/inventoryhandler.cpp b/src/net/manaserv/inventoryhandler.cpp index 0020a4e7..3ce1aa6f 100644 --- a/src/net/manaserv/inventoryhandler.cpp +++ b/src/net/manaserv/inventoryhandler.cpp @@ -61,7 +61,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) { case GPMSG_INVENTORY_FULL: player_node->clearInventory(); - player_node->mEquipment->setBackend(&mEqiups); + player_node->mEquipment->setBackend(&mEquips); // no break! case GPMSG_INVENTORY: @@ -77,7 +77,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) int id = msg.readInt16(); if (slot < EQUIPMENT_SIZE) { - mEqiups.setEquipment(slot, id); + mEquips.setEquipment(slot, id); } else if (slot >= 32 && slot < 32 + getSize(INVENTORY)) { @@ -105,7 +105,7 @@ void InventoryHandler::unequipItem(const Item *item) // Tidy equipment directly to avoid weapon still shown bug, for instance int equipSlot = item->getInvIndex(); logger->log("Unequipping %d", equipSlot); - mEqiups.setEquipment(equipSlot, 0); + mEquips.setEquipment(equipSlot, 0); } void InventoryHandler::useItem(const Item *item) diff --git a/src/net/manaserv/inventoryhandler.h b/src/net/manaserv/inventoryhandler.h index 362e392a..402af3b5 100644 --- a/src/net/manaserv/inventoryhandler.h +++ b/src/net/manaserv/inventoryhandler.h @@ -30,7 +30,8 @@ namespace ManaServ { -class EquipBackend : public Equipment::Backend { +class EquipBackend : public Equipment::Backend +{ public: EquipBackend() { memset(mEquipment, 0, sizeof(mEquipment)); } @@ -97,7 +98,7 @@ class InventoryHandler : public MessageHandler, Net::InventoryHandler size_t getSize(StorageType type) const; private: - EquipBackend mEqiups; + EquipBackend mEquips; }; } // namespace ManaServ diff --git a/src/net/manaserv/itemhandler.cpp b/src/net/manaserv/itemhandler.cpp index 802f9303..c939589e 100644 --- a/src/net/manaserv/itemhandler.cpp +++ b/src/net/manaserv/itemhandler.cpp @@ -58,12 +58,9 @@ void ItemHandler::handleMessage(Net::MessageIn &msg) if (itemId) { - Game *game = Game::instance(); - Map *map = 0; - if (game) + if (Game *game = Game::instance()) { - map = game->getCurrentMap(); - if (map) + if (Map *map = game->getCurrentMap()) { floorItemManager->create(id, itemId, @@ -71,9 +68,11 @@ void ItemHandler::handleMessage(Net::MessageIn &msg) y / map->getTileHeight()); } else - logger->log( - "ItemHandler: An item wasn't created because of" - "Game/Map not initialized..."); + { + logger->log( + "ItemHandler: An item wasn't created " + "because of Game/Map not initialized..."); + } } } else if (FloorItem *item = floorItemManager->findById(id)) diff --git a/src/net/manaserv/loginhandler.cpp b/src/net/manaserv/loginhandler.cpp index 63195816..9d8bc0e2 100644 --- a/src/net/manaserv/loginhandler.cpp +++ b/src/net/manaserv/loginhandler.cpp @@ -64,9 +64,11 @@ void LoginHandler::handleMessage(Net::MessageIn &msg) case APMSG_LOGIN_RESPONSE: handleLoginResponse(msg); break; + case APMSG_REGISTER_RESPONSE: handleRegisterResponse(msg); break; + case APMSG_RECONNECT_RESPONSE: { int errMsg = msg.readInt8(); diff --git a/src/net/manaserv/playerhandler.cpp b/src/net/manaserv/playerhandler.cpp index bff9512e..56502ec1 100644 --- a/src/net/manaserv/playerhandler.cpp +++ b/src/net/manaserv/playerhandler.cpp @@ -306,14 +306,14 @@ void PlayerHandler::emote(int emoteId) // TODO } -void PlayerHandler::increaseAttribute(size_t attr) +void PlayerHandler::increaseAttribute(int attr) { MessageOut msg(PGMSG_RAISE_ATTRIBUTE); msg.writeInt8(attr); gameServerConnection->send(msg); } -void PlayerHandler::decreaseAttribute(size_t attr) +void PlayerHandler::decreaseAttribute(int attr) { MessageOut msg(PGMSG_LOWER_ATTRIBUTE); msg.writeInt8(attr); diff --git a/src/net/manaserv/playerhandler.h b/src/net/manaserv/playerhandler.h index 6edc96bb..65170d63 100644 --- a/src/net/manaserv/playerhandler.h +++ b/src/net/manaserv/playerhandler.h @@ -44,31 +44,23 @@ class PlayerHandler : public MessageHandler, public Net::PlayerHandler void handleMessage(Net::MessageIn &msg); void attack(int id); - void emote(int emoteId); - void increaseAttribute(size_t attr); - - void decreaseAttribute(size_t attr); - + void increaseAttribute(int attr); + void decreaseAttribute(int attr); void increaseSkill(int skillId); void pickUp(FloorItem *floorItem); - void setDirection(char direction); - void setDestination(int x, int y, int direction = -1); - void changeAction(Being::Action action); void respawn(); void ignorePlayer(const std::string &player, bool ignore); - void ignoreAll(bool ignore); bool canUseMagic(); - bool canCorrectAttributes(); int getJobLocation(); diff --git a/src/net/playerhandler.h b/src/net/playerhandler.h index 0174ede2..c2ecd2d0 100644 --- a/src/net/playerhandler.h +++ b/src/net/playerhandler.h @@ -35,9 +35,9 @@ class PlayerHandler virtual void emote(int emoteId) = 0; - virtual void increaseAttribute(size_t attr) = 0; + virtual void increaseAttribute(int attr) = 0; - virtual void decreaseAttribute(size_t attr) = 0; + virtual void decreaseAttribute(int attr) = 0; virtual void increaseSkill(int skillId) = 0; diff --git a/src/player.cpp b/src/player.cpp index e537a2b9..2f6b14e9 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -49,7 +49,7 @@ Player::Player(int id, int job, Map *map, bool isNPC): { if (!isNPC) { - for (unsigned int i = 0; i < Net::getCharHandler()->maxSprite(); i++) + for (int i = 0; i < Net::getCharHandler()->maxSprite(); i++) { mSprites.push_back(NULL); mSpriteIDs.push_back(0); @@ -157,7 +157,7 @@ void Player::setGM(bool gm) updateColors(); } -void Player::setSprite(unsigned int slot, int id, const std::string &color, +void Player::setSprite(int slot, int id, const std::string &color, bool isWeapon) { if (getType() == NPC) diff --git a/src/player.h b/src/player.h index 6e2566b8..34963cf4 100644 --- a/src/player.h +++ b/src/player.h @@ -75,7 +75,7 @@ class Player : public Being /** * Sets visible equipments for this player. */ - virtual void setSprite(unsigned int slot, int id, + virtual void setSprite(int slot, int id, const std::string &color = "", bool isWeapon = false); |