From 82c7ecf7a838c43771a676bb9311f9a1fc403f67 Mon Sep 17 00:00:00 2001
From: Bjørn Lindeijer <bjorn@lindeijer.nl>
Date: Thu, 22 Mar 2007 23:53:13 +0000
Subject: Clarified the error message when character creation fails and made
 sure the character creation dialog doesn't close when creation failed.

---
 src/gui/char_select.cpp       | 37 +++++++++++++------
 src/gui/char_select.h         | 12 +++++--
 src/net/charserverhandler.cpp | 83 +++++++++++++++++++++++++------------------
 src/net/charserverhandler.h   | 21 +++++++++--
 4 files changed, 102 insertions(+), 51 deletions(-)

(limited to 'src')

diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp
index eb9ce31d..845c6d64 100644
--- a/src/gui/char_select.cpp
+++ b/src/gui/char_select.cpp
@@ -37,10 +37,14 @@
 #include "../localplayer.h"
 #include "../main.h"
 
+#include "../net/charserverhandler.h"
 #include "../net/messageout.h"
 
 #include "../utils/tostring.h"
 
+// Defined in main.cpp, used here for setting the char create dialog
+extern CharServerHandler charServerHandler;
+
 /**
  * Listener for confirming character deletion.
  */
@@ -144,15 +148,14 @@ void CharSelectDialog::action(const gcn::ActionEvent &event)
     {
         state = EXIT_STATE;
     }
-    else if (event.getId() == "new")
+    else if (event.getId() == "new" && n_character <= MAX_SLOT)
     {
-        if (n_character < MAX_SLOT + 1)
-        {
-            // Start new character dialog
-            mCharInfo->lock();
+        // Start new character dialog
+        mCharInfo->lock();
+        CharCreateDialog *charCreateDialog =
             new CharCreateDialog(this, mCharInfo->getPos(), mNetwork, mSex);
-            mCharInfo->unlock();
-        }
+        charServerHandler.setCharCreateDialog(charCreateDialog);
+        mCharInfo->unlock();
     }
     else if (event.getId() == "delete")
     {
@@ -312,21 +315,25 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network,
 
     setLocationRelativeTo(getParent());
     setVisible(true);
+    mNameField->requestFocus();
 }
 
 CharCreateDialog::~CharCreateDialog()
 {
     delete mPlayer;
+
+    // Make sure the char server handler knows that we're gone
+    charServerHandler.setCharCreateDialog(0);
 }
 
-void CharCreateDialog::action(const gcn::ActionEvent &event)
+void
+CharCreateDialog::action(const gcn::ActionEvent &event)
 {
     if (event.getId() == "create") {
         if (getName().length() >= 4) {
             // Attempt to create the character
             mCreateButton->setEnabled(false);
             attemptCharCreate();
-            scheduleDelete();
         }
         else {
             new OkDialog("Error",
@@ -352,12 +359,20 @@ void CharCreateDialog::action(const gcn::ActionEvent &event)
     }
 }
 
-std::string CharCreateDialog::getName()
+const std::string&
+CharCreateDialog::getName()
 {
     return mNameField->getText();
 }
 
-void CharCreateDialog::attemptCharCreate()
+void
+CharCreateDialog::unlock()
+{
+    mCreateButton->setEnabled(true);
+}
+
+void
+CharCreateDialog::attemptCharCreate()
 {
     // Send character infos
     MessageOut outMsg(mNetwork);
diff --git a/src/gui/char_select.h b/src/gui/char_select.h
index d6b53044..754362c3 100644
--- a/src/gui/char_select.h
+++ b/src/gui/char_select.h
@@ -116,9 +116,17 @@ class CharCreateDialog : public Window, public gcn::ActionListener
          */
         ~CharCreateDialog();
 
-        void action(const gcn::ActionEvent &event);
+        void
+        action(const gcn::ActionEvent &event);
 
-        std::string getName();
+        const std::string&
+        getName();
+
+        /**
+         * Unlocks the dialog, enabling the create character button again.
+         */
+        void
+        unlock();
 
     private:
         Network *mNetwork;
diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp
index 64b7f8cd..01a8756b 100644
--- a/src/net/charserverhandler.cpp
+++ b/src/net/charserverhandler.cpp
@@ -34,8 +34,10 @@
 #include "../main.h"
 
 #include "../gui/ok_dialog.h"
+#include "../gui/char_select.h"
 
-CharServerHandler::CharServerHandler()
+CharServerHandler::CharServerHandler():
+    mCharCreateDialog(0)
 {
     static const Uint16 _messages[] = {
         0x006b,
@@ -69,7 +71,7 @@ void CharServerHandler::handleMessage(MessageIn *msg)
 
             for (int i = 0; i < n_character; i++)
             {
-                tempPlayer = readPlayerData(msg, slot);
+                tempPlayer = readPlayerData(*msg, slot);
                 mCharInfo->select(slot);
                 mCharInfo->setEntry(tempPlayer);
                 logger->log("CharServer: Player: %s (%d)",
@@ -95,15 +97,26 @@ void CharServerHandler::handleMessage(MessageIn *msg)
             break;
 
         case 0x006d:
-            tempPlayer = readPlayerData(msg, slot);
+            tempPlayer = readPlayerData(*msg, slot);
             mCharInfo->unlock();
             mCharInfo->select(slot);
             mCharInfo->setEntry(tempPlayer);
             n_character++;
+
+            // Close the character create dialog
+            if (mCharCreateDialog)
+            {
+                mCharCreateDialog->scheduleDelete();
+                mCharCreateDialog = 0;
+            }
             break;
 
         case 0x006e:
-            new OkDialog("Error", "Failed to create character");
+            new OkDialog("Error", "Failed to create character. Most likely"
+                                  " the name is already taken.");
+
+            if (mCharCreateDialog)
+                mCharCreateDialog->unlock();
             break;
 
         case 0x006f:
@@ -160,49 +173,49 @@ void CharServerHandler::handleMessage(MessageIn *msg)
     }
 }
 
-LocalPlayer* CharServerHandler::readPlayerData(MessageIn *msg, int &slot)
+LocalPlayer* CharServerHandler::readPlayerData(MessageIn &msg, int &slot)
 {
     LocalPlayer *tempPlayer = new LocalPlayer(mLoginData->account_ID, 0, NULL);
     tempPlayer->setSex(1 - mLoginData->sex);
 
-    tempPlayer->mCharId = msg->readInt32();
+    tempPlayer->mCharId = msg.readInt32();
     tempPlayer->mTotalWeight = 0;
     tempPlayer->mMaxWeight = 0;
     tempPlayer->mLastAttackTime = 0;
-    tempPlayer->mXp = msg->readInt32();
-    tempPlayer->mGp = msg->readInt32();
-    tempPlayer->mJobXp = msg->readInt32();
-    tempPlayer->mJobLevel = msg->readInt32();
-    msg->skip(8);                          // unknown
-    msg->readInt32();                       // option
-    msg->readInt32();                       // karma
-    msg->readInt32();                       // manner
-    msg->skip(2);                          // unknown
-    tempPlayer->mHp = msg->readInt16();
-    tempPlayer->mMaxHp = msg->readInt16();
-    tempPlayer->mMp = msg->readInt16();
-    tempPlayer->mMaxMp = msg->readInt16();
-    msg->readInt16();                       // speed
-    msg->readInt16();                       // class
-    tempPlayer->setHairStyle(msg->readInt16());
-    Uint16 weapon = msg->readInt16();
+    tempPlayer->mXp = msg.readInt32();
+    tempPlayer->mGp = msg.readInt32();
+    tempPlayer->mJobXp = msg.readInt32();
+    tempPlayer->mJobLevel = msg.readInt32();
+    msg.skip(8);                          // unknown
+    msg.readInt32();                       // option
+    msg.readInt32();                       // karma
+    msg.readInt32();                       // manner
+    msg.skip(2);                          // unknown
+    tempPlayer->mHp = msg.readInt16();
+    tempPlayer->mMaxHp = msg.readInt16();
+    tempPlayer->mMp = msg.readInt16();
+    tempPlayer->mMaxMp = msg.readInt16();
+    msg.readInt16();                       // speed
+    msg.readInt16();                       // class
+    tempPlayer->setHairStyle(msg.readInt16());
+    Uint16 weapon = msg.readInt16();
     if (weapon == 11)
         weapon = 2;
     tempPlayer->setWeapon(weapon);
-    tempPlayer->mLevel = msg->readInt16();
-    msg->readInt16();                       // skill point
-    tempPlayer->setVisibleEquipment(Being::BOTTOMCLOTHES_SPRITE, msg->readInt16()); // head bottom
-    msg->readInt16();                       // shield
-    tempPlayer->setVisibleEquipment(Being::HAT_SPRITE, msg->readInt16()); // head option top
-    tempPlayer->setVisibleEquipment(Being::TOPCLOTHES_SPRITE, msg->readInt16()); // head option mid
-    tempPlayer->setHairColor(msg->readInt16());
-    msg->readInt16();                       // unknown
-    tempPlayer->setName(msg->readString(24));
+    tempPlayer->mLevel = msg.readInt16();
+    msg.readInt16();                       // skill point
+    tempPlayer->setVisibleEquipment(Being::BOTTOMCLOTHES_SPRITE, msg.readInt16()); // head bottom
+    msg.readInt16();                       // shield
+    tempPlayer->setVisibleEquipment(Being::HAT_SPRITE, msg.readInt16()); // head option top
+    tempPlayer->setVisibleEquipment(Being::TOPCLOTHES_SPRITE, msg.readInt16()); // head option mid
+    tempPlayer->setHairColor(msg.readInt16());
+    msg.readInt16();                       // unknown
+    tempPlayer->setName(msg.readString(24));
     for (int i = 0; i < 6; i++) {
-        tempPlayer->mAttr[i] = msg->readInt8();
+        tempPlayer->mAttr[i] = msg.readInt8();
     }
-    slot = msg->readInt8(); // character slot
-    msg->readInt8();                        // unknown
+    slot = msg.readInt8(); // character slot
+    msg.readInt8();                        // unknown
 
     return tempPlayer;
 }
diff --git a/src/net/charserverhandler.h b/src/net/charserverhandler.h
index 16d2c361..ab4ca1c7 100644
--- a/src/net/charserverhandler.h
+++ b/src/net/charserverhandler.h
@@ -28,9 +28,13 @@
 
 #include "../lockedarray.h"
 
+class CharCreateDialog;
 class LocalPlayer;
 class LoginData;
 
+/**
+ * Deals with incoming messages from the character server.
+ */
 class CharServerHandler : public MessageHandler
 {
     public:
@@ -38,15 +42,26 @@ class CharServerHandler : public MessageHandler
 
         void handleMessage(MessageIn *msg);
 
-        void setCharInfo(LockedArray<LocalPlayer*> *charInfo) { mCharInfo = charInfo; };
+        void setCharInfo(LockedArray<LocalPlayer*> *charInfo)
+        { mCharInfo = charInfo; }
+
+        void setLoginData(LoginData *loginData)
+        { mLoginData = loginData; }
 
-        void setLoginData(LoginData *loginData) { mLoginData = loginData; };
+        /**
+         * Sets the character create dialog. The handler will clean up this
+         * dialog when a new character is succesfully created, and will unlock
+         * the dialog when a new character failed to be created.
+         */
+        void setCharCreateDialog(CharCreateDialog *window)
+        { mCharCreateDialog = window; }
 
     protected:
         LoginData *mLoginData;
         LockedArray<LocalPlayer*> *mCharInfo;
+        CharCreateDialog *mCharCreateDialog;
 
-        LocalPlayer* readPlayerData(MessageIn *msg, int &slot);
+        LocalPlayer* readPlayerData(MessageIn &msg, int &slot);
 };
 
 #endif
-- 
cgit v1.2.3-70-g09d2