Fixed adding/deleting characters.
[tmw:aethyra.git] / src / eathena / net / charserverhandler.cpp
1 /*
2  *  Aethyra
3  *  Copyright (C) 2004  The Mana World Development Team
4  *
5  *  This file is part of Aethyra based on original code
6  *  from The Mana World.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "charserverhandler.h"
24 #include "logindata.h"
25 #include "messagein.h"
26 #include "messageout.h"
27 #include "network.h"
28 #include "protocol.h"
29
30 #include "../game.h"
31
32 #include "../gui/charselect.h"
33
34 #include "../../main.h"
35
36 #include "../../bindings/guichan/dialogs/okdialog.h"
37
38 #include "../../core/log.h"
39
40 #include "../../core/map/sprite/localplayer.h"
41
42 #include "../../core/utils/dtor.h"
43 #include "../../core/utils/gettext.h"
44 #include "../../core/utils/stringutils.h"
45
46 CharServerHandler::CharServerHandler()
47 {
48     static const Uint16 _messages[] = {
49         SMSG_CONNECTION_PROBLEM,
50         0x006b,
51         0x006c,
52         0x006d,
53         0x006e,
54         0x006f,
55         0x0070,
56         0x0071,
57         0
58     };
59     handledMessages = _messages;
60 }
61
62 void CharServerHandler::handleMessage(MessageIn *msg)
63 {
64     int slot, flags, code;
65     LocalPlayer *tempPlayer;
66
67     logger->log("CharServerHandler: Packet ID: %x, Length: %d",
68             msg->getId(), msg->getLength());
69     switch (msg->getId())
70     {
71         case SMSG_CONNECTION_PROBLEM:
72             code = msg->readInt8();
73             logger->log("Connection problem: %i", code);
74
75             switch (code)
76             {
77                 case 0:
78                     errorMessage = _("Authentication failed.");
79                     break;
80                 case 1:
81                     errorMessage = _("Map server(s) offline.");
82                     break;
83                 case 2:
84                     errorMessage = _("This account is already logged in.");
85                     break;
86                 case 3:
87                     errorMessage = _("Speed hack detected.");
88                     break;
89                 case 8:
90                     errorMessage = _("Duplicated login.");
91                     break;
92                 default:
93                     errorMessage = _("Unknown connection error.");
94                     break;
95             }
96             state = ERROR_STATE;
97             break;
98
99         case 0x006b:
100             msg->skip(2); // Length word
101             flags = msg->readInt32(); // Aethyra extensions flags
102             logger->log("Server flags are: %x", flags);
103             msg->skip(16); // Unused
104
105             // Derive number of characters from message length
106             loginData.slots = (msg->getLength() - 24) / 106;
107
108             for (int i = 0; i < loginData.slots; i++)
109             {
110                 tempPlayer = readPlayerData(*msg, slot);
111                 mCharInfo->select(slot);
112                 mCharInfo->setEntry(tempPlayer);
113                 logger->log("CharServer: Player: %s (%d)",
114                 tempPlayer->getName().c_str(), slot);
115             }
116
117             state = CHAR_SELECT_STATE;
118             break;
119
120         case 0x006c:
121             switch (msg->readInt8())
122             {
123                 case 0:
124                     errorMessage = _("Access denied.");
125                     break;
126                 case 1:
127                     errorMessage = _("Cannot use this ID.");
128                     break;
129                 default:
130                     errorMessage = _("Unknown failure to select character.");
131                     break;
132             }
133             mCharInfo->unlock();
134             break;
135
136         case 0x006d:
137             tempPlayer = readPlayerData(*msg, slot);
138             mCharInfo->unlock();
139             mCharInfo->select(slot);
140             mCharInfo->setEntry(tempPlayer);
141             loginData.slots++;
142             if (charSelectDialog)
143                 charSelectDialog->updatePlayerInfo();
144
145             // Close the character create dialog
146             if (charCreateDialog)
147                 destroy(charCreateDialog);
148
149             break;
150
151         case 0x006e:
152             new OkDialog(_("Error"), _("Failed to create character. Most "
153                                        "likely the name is already taken."));
154             if (charCreateDialog)
155                 charCreateDialog->unlock();
156             break;
157
158         case 0x006f:
159             delete mCharInfo->getEntry();
160             mCharInfo->setEntry(0);
161             mCharInfo->unlock();
162             loginData.slots--;
163             if (charSelectDialog)
164                 charSelectDialog->updatePlayerInfo();
165             new OkDialog(_("Info"), _("Character deleted."));
166             break;
167
168         case 0x0070:
169             mCharInfo->unlock();
170             new OkDialog(_("Error"), _("Failed to delete character."));
171             break;
172
173         case 0x0071:
174             player_node = mCharInfo->getEntry();
175             slot = mCharInfo->getPos();
176             msg->skip(4); // CharID, must be the same as player_node->charID
177             map_path = msg->readString(16);
178             loginData.hostname = ipToString(msg->readInt32());
179             loginData.port = msg->readInt16();
180             mCharInfo->unlock();
181             mCharInfo->select(0);
182             // Clear unselected players infos
183             do
184             {
185                 LocalPlayer *tmp = mCharInfo->getEntry();
186                 if (tmp != player_node)
187                 {
188                     destroy(tmp);
189                     mCharInfo->setEntry(0);
190                 }
191                 mCharInfo->next();
192             } while (mCharInfo->getPos());
193
194             mCharInfo->select(slot);
195             state = CONNECTING_STATE;
196             break;
197     }
198 }
199
200 LocalPlayer *CharServerHandler::readPlayerData(MessageIn &msg, int &slot)
201 {
202     LocalPlayer *tempPlayer = new LocalPlayer(loginData.account_ID, 0, NULL);
203     tempPlayer->setGender((loginData.sex == 0) ? GENDER_FEMALE : GENDER_MALE);
204
205     tempPlayer->mCharId = msg.readInt32();
206     tempPlayer->setXp(msg.readInt32());
207     tempPlayer->mGp = msg.readInt32();
208     tempPlayer->mJobXp = msg.readInt32();
209     tempPlayer->mJobLevel = msg.readInt32();
210     tempPlayer->setSprite(Being::SHOE_SPRITE, msg.readInt16());
211     tempPlayer->setSprite(Being::GLOVES_SPRITE, msg.readInt16());
212     tempPlayer->setSprite(Being::CAPE_SPRITE, msg.readInt16());
213     tempPlayer->setSprite(Being::MISC1_SPRITE, msg.readInt16());
214     msg.readInt32();                       // option
215     msg.readInt32();                       // karma
216     msg.readInt32();                       // manner
217     msg.skip(2);                           // unknown
218     tempPlayer->mHp = msg.readInt16();
219     tempPlayer->mMaxHp = msg.readInt16();
220     tempPlayer->mMp = msg.readInt16();
221     tempPlayer->mMaxMp = msg.readInt16();
222     tempPlayer->setWalkSpeed(msg.readInt16());  // speed
223     msg.readInt16();                            // class
224     int hairStyle = msg.readInt16();
225     tempPlayer->setSprite(Being::WEAPON_SPRITE, msg.readInt16());
226     tempPlayer->mLevel = msg.readInt16();
227     msg.readInt16();                       // skill point
228     tempPlayer->setSprite(Being::BOTTOMCLOTHES_SPRITE, msg.readInt16()); // head bottom
229     tempPlayer->setSprite(Being::SHIELD_SPRITE, msg.readInt16());
230     tempPlayer->setSprite(Being::HAT_SPRITE, msg.readInt16()); // head option top
231     tempPlayer->setSprite(Being::TOPCLOTHES_SPRITE, msg.readInt16()); // head option mid
232     int hairColor = msg.readInt16();
233     tempPlayer->setHairStyle(hairStyle, hairColor);
234     tempPlayer->setSprite(Being::MISC2_SPRITE, msg.readInt16());
235     tempPlayer->setName(msg.readString(24));
236
237     for (int i = 0; i < 6; i++)
238         tempPlayer->mAttr[i] = msg.readInt8();
239
240     slot = msg.readInt8(); // character slot
241     msg.readInt8();        // unknown
242
243     return tempPlayer;
244 }
245
246 void CharServerHandler::login(LockedArray<LocalPlayer*> *charInfo)
247 {
248     logger->log("Sending server client version and getting character data...");
249     network->disconnect();
250     network->connect(loginData.hostname, loginData.port);
251     network->registerHandler(this);
252     mCharInfo = charInfo;
253
254     // Send login infos
255     MessageOut outMsg(0x0065);
256     outMsg.writeInt32(loginData.account_ID);
257     outMsg.writeInt32(loginData.session_ID1);
258     outMsg.writeInt32(loginData.session_ID2);
259     // [Fate] The next word is unused by the old char server, so we squeeze in
260     //        tmw client version information
261     outMsg.writeInt16(CLIENT_PROTOCOL_VERSION);
262     outMsg.writeInt8(loginData.sex);
263
264     // We get 4 useless bytes before the real answer comes in
265     network->skip(4);
266 }
267