/* * The Mana World * Copyright 2004 The Mana World Development Team * * This file is part of The Mana World. * * The Mana World is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * The Mana World is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ */ #include "char_select.h" #include "textfield.h" #include "../graphic/graphic.h" #include "../graphic/2xsai.h" CharSelectDialog::CharSelectDialog(gcn::Container *parent) : Window(parent, "Select Character") { selectButton = new Button(" OK "); cancelButton = new Button("Cancel"); newCharButton = new Button(" New "); delCharButton = new Button("Delete"); nameLabel = new gcn::Label("Name"); levelLabel = new gcn::Label("Level"); jobLevelLabel = new gcn::Label("Job Level"); moneyLabel = new gcn::Label("Money"); nameLabel->setDimension(gcn::Rectangle(0, 0, 128, 16)); levelLabel->setDimension(gcn::Rectangle(0, 0, 128, 16)); jobLevelLabel->setDimension(gcn::Rectangle(0, 0, 128, 16)); moneyLabel->setDimension(gcn::Rectangle(0, 0, 128, 16)); selectButton->setEventId("ok"); newCharButton->setEventId("new"); cancelButton->setEventId("cancel"); delCharButton->setEventId("delete"); selectButton->setPosition(128, 180); cancelButton->setPosition(166, 180); newCharButton->setPosition(4, 180); delCharButton->setPosition(64, 180); nameLabel->setPosition(10, 100); levelLabel->setPosition(10, 116); jobLevelLabel->setPosition(10, 132); moneyLabel->setPosition(10, 148); add(selectButton); add(cancelButton); add(newCharButton); add(delCharButton); add(nameLabel); add(levelLabel); add(jobLevelLabel); add(moneyLabel); // Set up event listener selectButton->addActionListener(this); cancelButton->addActionListener(this); newCharButton->addActionListener(this); delCharButton->addActionListener(this); setSize(240, 216); setLocationRelativeTo(getParent()); } CharSelectDialog::~CharSelectDialog() { delete selectButton; delete cancelButton; delete newCharButton; } void CharSelectDialog::action(const std::string& eventId) { if (eventId == "ok") { // Start game state = GAME; } else if (eventId == "cancel") { state = EXIT; } else if (eventId == "new") { // Create new character if (n_character > 0) return; // Start new character dialog... charCreate(); } else if (eventId == "delete") { // Delete character if (n_character <= 0) return; serverCharDelete(); } } #define MAX_HAIR_STYLE 3 #define MAX_HAIR_COLOR 9 int curHairColor = 0; int curHairStyle = 0; std::string curName; CharCreateDialog::CharCreateDialog(gcn::Container *parent) : Window(parent, "Create Character") { nameField = new TextField(""); nameLabel = new gcn::Label("Name:"); nextHairColorButton = new Button(">"); prevHairColorButton = new Button("<"); hairColorLabel = new gcn::Label("Hair Color:"); nextHairStyleButton = new Button(">"); prevHairStyleButton = new Button("<"); hairStyleLabel = new gcn::Label("Hair Style:"); createButton = new Button("Create"); nextHairColorButton->setEventId("nextcolor"); prevHairColorButton->setEventId("prevcolor"); nextHairStyleButton->setEventId("nextstyle"); prevHairStyleButton->setEventId("prevstyle"); createButton->setEventId("create"); nameField->setDimension(gcn::Rectangle(0, 0, 96, 16)); nameField->setPosition(40, 4); nameLabel->setPosition(4, 4); nextHairColorButton->setPosition(160, 32); prevHairColorButton->setPosition(96, 32); hairColorLabel->setPosition(4, 34); nextHairStyleButton->setPosition(160, 64); prevHairStyleButton->setPosition(96, 64); hairStyleLabel->setPosition(4, 66); createButton->setPosition(125, 96); nextHairColorButton->addActionListener(this); prevHairColorButton->addActionListener(this); nextHairStyleButton->addActionListener(this); prevHairStyleButton->addActionListener(this); createButton->addActionListener(this); add(nameField); add(nameLabel); add(nextHairColorButton); add(prevHairColorButton); add(hairColorLabel); add(nextHairStyleButton); add(prevHairStyleButton); add(hairStyleLabel); add(createButton); setSize(200, 128); setLocationRelativeTo(getParent()); } CharCreateDialog::~CharCreateDialog() { delete nameField; delete nameLabel; delete nextHairColorButton; delete prevHairColorButton; delete hairColorLabel; delete nextHairStyleButton; delete prevHairStyleButton; delete hairStyleLabel; } void CharCreateDialog::action(const std::string& eventId) { if (eventId == "create") { // Create character (used to exit create dialog loop) state = CHAR_SELECT; } else if (eventId == "nextcolor") { curHairColor++; } else if (eventId == "prevcolor") { curHairColor--; } else if (eventId == "nextstyle") { curHairStyle++; } else if (eventId == "prevstyle") { curHairStyle--; } if (curHairColor < 0) curHairColor = 0; if (curHairColor > MAX_HAIR_COLOR) curHairColor = MAX_HAIR_COLOR; if (curHairStyle < 0) curHairStyle = 0; if (curHairStyle > MAX_HAIR_STYLE) curHairStyle = MAX_HAIR_STYLE; } void charSelect() { CharSelectDialog *sel; sel = new CharSelectDialog(guiTop); state = LOGIN; while (!key[KEY_ESC] && !key[KEY_ENTER] && state != EXIT && state == LOGIN) { if (n_character > 0) { char tmpBuf[64]; sel->setName(char_info->name); sprintf(tmpBuf, "Lvl: %d", char_info->lv); sel->setLevel(tmpBuf); sprintf(tmpBuf, "Job Lvl: %d", char_info->job_lv); sel->setJobLevel(tmpBuf); sprintf(tmpBuf, "Gold: %d", char_info->gp); sel->setMoney(tmpBuf); } // Draw background blit((BITMAP *)graphic[LOGIN_BMP].dat, buffer, 0, 0, 0, 0, 800, 600); gui_update(NULL); // Draw character const int pX = 16, pY = 32; if (n_character > 0) { masked_blit(playerset, buffer, 0, 0, pX + sel->getDimension().x, pY + sel->getDimension().y, 80, 60); masked_blit(hairset, buffer, 20 * (char_info->hair_color - 1), 20 * 4 * (char_info->hair_style - 1), pX + 31 + sel->getDimension().x, pY + 15 + sel->getDimension().y, 20, 20); } // Draw to screen blit(buffer, screen, 0, 0, 0, 0, 800, 600); } if (state == GAME) { serverCharSelect(); close_session(); } delete sel; } void serverCharSelect() { // Request character selection WFIFOW(0) = net_w_value(0x0066); WFIFOB(2) = net_b_value(0); WFIFOSET(3); while ((in_size < 3) || (out_size > 0)) { flush(); } log("CharSelect", "Packet ID: %x, Length: %d, Packet_in_size %d", RFIFOW(0), get_length(RFIFOW(0)), RFIFOW(2)); log("CharSelect", "In_size: %d", in_size); if (RFIFOW(0) == 0x0071) { while (in_size < 28) { flush(); } char_ID = RFIFOL(2); memset(map_path, '\0', 480); append_filename(map_path, "./data/map/", RFIFOP(6), 480); map_address = RFIFOL(22); map_port = RFIFOW(26); state = GAME; log("CharSelect", "Map: %s", map_name); log("CharSelect", "Server: %s:%d", iptostring(map_address), map_port); RFIFOSKIP(28); close_session(); } else if (RFIFOW(0) == 0x006c) { switch (RFIFOB(2)) { case 0: ok("Error", "Access denied"); break; case 1: ok("Error", "Cannot use this ID"); break; } state = CHAR_SELECT; RFIFOSKIP(3); } // Todo: add other packets } void charCreate() { CharCreateDialog *create = new CharCreateDialog(guiTop); state = LOGIN; while (!key[KEY_ESC] && !key[KEY_ENTER] && state != EXIT && state != CHAR_SELECT) { // Draw background blit((BITMAP *)graphic[LOGIN_BMP].dat, buffer, 0, 0, 0, 0, 800, 600); gui_update(NULL); // Draw character const int pX = 96, pY = 40; masked_blit(playerset, buffer, 0, 0, pX + create->getDimension().x, pY + create->getDimension().y, 80, 60); masked_blit(hairset, buffer, 20 * curHairColor, 20 * 4 * curHairStyle, pX + 31 + create->getDimension().x, pY + 15 + create->getDimension().y, 20, 20); // Draw to screen blit(buffer, screen, 0, 0, 0, 0, 800, 600); curName = create->getName(); } if (state == CHAR_SELECT) { serverCharCreate(); } delete create; } void serverCharDelete() { state = CHAR_SELECT; // Delete a character if (yes_no("Confirm", "Are you sure?")==0) { // Request character deletion WFIFOW(0) = net_w_value(0x0068); WFIFOL(2) = net_l_value(char_info->id); WFIFOSET(46); while ((in_size < 2) || (out_size > 0)) flush(); if (RFIFOW(0) == 0x006f) { RFIFOSKIP(2); ok("Info", "Player deleted"); free(char_info); n_character = 0; } else if (RFIFOW(0) == 0x006c) { switch (RFIFOB(2)) { case 0: ok("Error", "Access denied"); break; case 1: ok("Error", "Cannot use this ID"); break; } RFIFOSKIP(3); } else ok("Error", "Unknown error"); } } void serverCharCreate() { n_character = 1; WFIFOW(0) = net_w_value(0x0067); strcpy(WFIFOP(2), curName.c_str()); WFIFOB(26) = net_b_value(5); WFIFOB(27) = net_b_value(5); WFIFOB(28) = net_b_value(5); WFIFOB(29) = net_b_value(5); WFIFOB(30) = net_b_value(5); WFIFOB(31) = net_b_value(5); WFIFOB(32) = net_b_value(0); WFIFOW(33) = net_w_value(curHairColor + 1); WFIFOW(35) = net_w_value(curHairStyle + 1); WFIFOSET(37); while ((in_size < 3) || (out_size > 0)) flush(); if (RFIFOW(0) == 0x006d) { while (in_size < 108) flush(); char_info = (PLAYER_INFO *)malloc(sizeof(PLAYER_INFO)); char_info->id = RFIFOL(2);//account_ID; memset(char_info->name, '\0', 24); strcpy(char_info[0].name, RFIFOP(2+74)); char_info->hp = RFIFOW(2+42); char_info->max_hp = RFIFOW(2+44); char_info->sp = RFIFOW(2+46); char_info->max_sp = RFIFOW(2+48); char_info->job_lv = RFIFOL(2+16); char_info->job_xp = RFIFOL(2+12); char_info->lv = RFIFOW(2+58); char_info->xp = RFIFOL(2+4); char_info->gp = RFIFOL(2+8); char_info->STR = RFIFOB(2+98); char_info->AGI = RFIFOB(2+99); char_info->VIT = RFIFOB(2+100); char_info->INT = RFIFOB(2+101); char_info->DEX = RFIFOB(2+102); char_info->LUK = RFIFOB(2+103); char_info->hair_style = RFIFOW(2+54); char_info->hair_color = RFIFOW(2+70); char_info->weapon = RFIFOW(2+56); RFIFOSKIP(108); //n_character++; } else if (RFIFOW(0) == 0x006c) { switch (RFIFOB(2)) { case 0: ok("Error", "Access denied"); break; case 1: ok("Error", "Cannot use this ID"); break; } RFIFOSKIP(3); n_character = 0; } else { ok("Error", "Unknown error"); n_character = 0; } }