/* * 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 #include #include #include "button.h" #include "gui.h" #include "ok_dialog.h" #include "playerbox.h" #include "textfield.h" #include "windowcontainer.h" #include "../being.h" #include "../game.h" #include "../graphics.h" #include "../log.h" #include "../main.h" #include "../playerinfo.h" #include "../net/network.h" #include "../net/protocol.h" extern Graphics *graphics; CharSelectDialog::CharDeleteConfirm::CharDeleteConfirm(CharSelectDialog *m): ConfirmDialog(m, "Confirm", "Are you sure you want to delete this character?"), master(m) { } void CharSelectDialog::CharDeleteConfirm::action(const std::string &eventId) { ConfirmDialog::action(eventId); if (eventId == "yes") { master->serverCharDelete(); } } CharSelectDialog::CharSelectDialog(): Window("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"); playerBox = new PlayerBox(); selectButton->setEventId("ok"); newCharButton->setEventId("new"); cancelButton->setEventId("cancel"); delCharButton->setEventId("delete"); int w = 195; int h = 195; setContentSize(w, h); playerBox->setDimension(gcn::Rectangle(5, 5, w - 10, 90)); nameLabel->setDimension(gcn::Rectangle(10, 100, 128, 16)); levelLabel->setDimension(gcn::Rectangle(10, 116, 128, 16)); jobLevelLabel->setDimension(gcn::Rectangle(10, 132, 128, 16)); moneyLabel->setDimension(gcn::Rectangle(10, 148, 128, 16)); newCharButton->setPosition(5, h - 5 - newCharButton->getHeight()); delCharButton->setPosition( 5 + newCharButton->getWidth() + 5, newCharButton->getY()); cancelButton->setPosition( w - 5 - cancelButton->getWidth(), newCharButton->getY()); selectButton->setPosition( cancelButton->getX() - 5 - selectButton->getWidth(), newCharButton->getY()); add(playerBox); 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); selectButton->requestFocus(); setLocationRelativeTo(getParent()); setPlayerInfo(NULL); } CharSelectDialog::~CharSelectDialog() { delete selectButton; delete cancelButton; delete newCharButton; delete delCharButton; delete nameLabel; delete levelLabel; delete jobLevelLabel; delete moneyLabel; delete playerBox; } void CharSelectDialog::action(const std::string& eventId) { if (eventId == "ok" && n_character > 0) { // Start game serverCharSelect(); close_session(); } else if (eventId == "cancel") { state = EXIT; } else if (eventId == "new") { if (n_character == 0) { // Start new character dialog new CharCreateDialog(this); } } else if (eventId == "delete") { // Delete character if (n_character > 0) { new CharDeleteConfirm(this); } } } void CharSelectDialog::setPlayerInfo(PLAYER_INFO *pi) { if (pi) { std::stringstream nameCaption, levelCaption, jobCaption, moneyCaption; nameCaption << pi->name; levelCaption << "Lvl: " << pi->lv; jobCaption << "Job Lvl: " << pi->job_lv; moneyCaption << "Gold: " << pi->gp; nameLabel->setCaption(nameCaption.str()); levelLabel->setCaption(levelCaption.str()); jobLevelLabel->setCaption(jobCaption.str()); moneyLabel->setCaption(moneyCaption.str()); newCharButton->setEnabled(false); delCharButton->setEnabled(true); selectButton->setEnabled(true); playerBox->hairStyle = pi->hair_style - 1; playerBox->hairColor = pi->hair_color - 1; playerBox->showPlayer = true; } else { nameLabel->setCaption("Name"); levelLabel->setCaption("Level"); jobLevelLabel->setCaption("Job Level"); moneyLabel->setCaption("Money"); newCharButton->setEnabled(true); delCharButton->setEnabled(false); selectButton->setEnabled(false); playerBox->hairStyle = 0; playerBox->hairColor = 0; playerBox->showPlayer = false; } } void CharSelectDialog::serverCharDelete() { // 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); free(char_info); n_character = 0; setPlayerInfo(NULL); new OkDialog(this, "Info", "Player deleted"); } else if (RFIFOW(0) == 0x0070) { new OkDialog(this, "Error", "Failed to delete character."); RFIFOSKIP(3); } else { new OkDialog(this, "Error", "Unknown"); } } void CharSelectDialog::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(); } logger->log("CharSelect: Packet ID: %x, Length: %d, Packet_in_size %d", RFIFOW(0), get_length(RFIFOW(0)), RFIFOW(2)); logger->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); strcat(map_path, "maps/"); strncat(map_path, RFIFOP(6), 479 - strlen(map_path)); map_address = RFIFOL(22); map_port = RFIFOW(26); state = GAME; logger->log("CharSelect: Map: %s", map_name); logger->log("CharSelect: Server: %s:%d", iptostring(map_address), map_port); RFIFOSKIP(28); close_session(); } else if (RFIFOW(0) == 0x006c) { switch (RFIFOB(2)) { case 0: new OkDialog(this, "Error", "Access denied"); break; case 1: new OkDialog(this, "Error", "Cannot use this ID"); break; } RFIFOSKIP(3); } else if (RFIFOW(0) == 0x0081) { new OkDialog(this, "Error", "Map server is down, please try again later"); close_session(); state = LOGIN; } // Todo: add other packets } CharCreateDialog::CharCreateDialog(Window *parent): Window("Create Character", true, parent) { 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"); cancelButton = new Button("Cancel"); playerBox = new PlayerBox(); playerBox->showPlayer = true; nameField->setEventId("create"); nextHairColorButton->setEventId("nextcolor"); prevHairColorButton->setEventId("prevcolor"); nextHairStyleButton->setEventId("nextstyle"); prevHairStyleButton->setEventId("prevstyle"); createButton->setEventId("create"); cancelButton->setEventId("cancel"); int w = 200; int h = 150; setContentSize(w, h); playerBox->setDimension(gcn::Rectangle(80, 30, 110, 85)); nameLabel->setPosition(5, 5); nameField->setDimension( gcn::Rectangle(45, 5, w - 45 - 7, nameField->getHeight())); prevHairColorButton->setPosition(90, 35); nextHairColorButton->setPosition(165, 35); hairColorLabel->setPosition(5, 40); prevHairStyleButton->setPosition(90, 64); nextHairStyleButton->setPosition(165, 64); hairStyleLabel->setPosition(5, 70); cancelButton->setPosition( w - 5 - cancelButton->getWidth(), h - 5 - cancelButton->getHeight()); createButton->setPosition( cancelButton->getX() - 5 - createButton->getWidth(), h - 5 - cancelButton->getHeight()); nameField->addActionListener(this); nextHairColorButton->addActionListener(this); prevHairColorButton->addActionListener(this); nextHairStyleButton->addActionListener(this); prevHairStyleButton->addActionListener(this); createButton->addActionListener(this); cancelButton->addActionListener(this); add(playerBox); add(nameField); add(nameLabel); add(nextHairColorButton); add(prevHairColorButton); add(hairColorLabel); add(nextHairStyleButton); add(prevHairStyleButton); add(hairStyleLabel); add(createButton); add(cancelButton); setLocationRelativeTo(getParent()); } CharCreateDialog::~CharCreateDialog() { delete nameField; delete nameLabel; delete nextHairColorButton; delete prevHairColorButton; delete hairColorLabel; delete nextHairStyleButton; delete prevHairStyleButton; delete hairStyleLabel; delete playerBox; } void CharCreateDialog::action(const std::string& eventId) { if (eventId == "create") { if (getName().length() >= 4) { // Attempt to create the character serverCharCreate(); } else { new OkDialog(this, "Error", "Your name needs to be at least 4 characters."); } } else if (eventId == "cancel") { windowContainer->scheduleDelete(this); } else if (eventId == "nextcolor") { playerBox->hairColor++; } else if (eventId == "prevcolor") { playerBox->hairColor += NR_HAIR_COLORS - 1; } else if (eventId == "nextstyle") { playerBox->hairStyle++; } else if (eventId == "prevstyle") { playerBox->hairStyle += NR_HAIR_STYLES - 1; } playerBox->hairColor %= NR_HAIR_COLORS; playerBox->hairStyle %= NR_HAIR_STYLES; } std::string CharCreateDialog::getName() { return nameField->getText(); } void CharCreateDialog::serverCharCreate() { n_character = 1; WFIFOW(0) = net_w_value(0x0067); strcpy(WFIFOP(2), getName().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(playerBox->hairColor + 1); WFIFOW(35) = net_w_value(playerBox->hairStyle + 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) == 0x006e) { new OkDialog(this, "Error", "Failed to create character"); RFIFOSKIP(3); n_character = 0; } else { new OkDialog(this, "Error", "Unknown error"); n_character = 0; } // Remove window when succeeded if (n_character == 1) { windowContainer->scheduleDelete(this); } } void charSelect() { CharSelectDialog *sel; sel = new CharSelectDialog(); state = CHAR_SELECT; while (/*!key[KEY_ESC] && !key[KEY_ENTER] &&*/ state == CHAR_SELECT) { // Handle SDL events SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: state = EXIT; break; case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) { state = EXIT; } break; } guiInput->pushInput(event); } if (n_character > 0) { sel->setPlayerInfo(char_info); } gui->logic(); graphics->drawImage(login_wallpaper, 0, 0); gui->draw(); graphics->updateScreen(); } delete sel; }