summaryrefslogblamecommitdiff
path: root/src/gui/char_select.cpp
blob: 209284f77dbbd49a043ab2d66837529147fd79b5 (plain) (tree)


















                                                                             

        
   

                        

                  
                 
                
 

                                    

                      


                            
                     

                    

                          

                             
                              
                           
                            
 


                                                                            
                         




                                                                            
                                     
                           























                                                    


     
                                     
                                                           
 
                                    
                                        
                                      
                                         

                                            



                                                
                                




                                        

                                           
 
                
                
                         




                                                                  

                                                                  











                                                                      



                       

                        









                                           

                                            
 
                                 
                                       
                        

 

















                                           

                                                         

                                           
                     


                                         


                                          
                    
     

                                 
                           
     



                                       
                                         
                                                     
         


                                 
                           

                            
                                        
         
     







                                     

 

                                                     



                                                                              

                                                





                                                    





                                             

                                                 






                                               


                                         





                                      
 
                                          
 
                                 
                      
                              
                                                   
                                      
 
 

                                        
                                       
 


                              


                                       


                                                     

                                   
                                                                   
                              

          
                                               
                              
     

 
                                          

                                  
                      
                              
                                   
 
 



                                   
                                       



                             
 

                                                                     
 

                              
                                  
                                                
                                                                       

                                      









                                              
                                 
 
                                                             
                                                                         
                              
                          
     

                                   
                                 
                   
                                               

                      
                                                    
                      
                    
                                                                     
                      
         
                              
     

                                   
                                 


                                                    
                   
                                                     

                      
                                                  

                      
                                                          

                      
                          
                            
     
 


                              

                              


                                               
     


                     
                          







                              

 

                                                                     
 
                                  







                                                   


                                        
 
                                    




                                                 
                                       
 

                
                         

















                                                                       




                                                 
                                          
 
                   








                             
                      
 
                                       

 














                              


                                                         

                                              
                                            
                                
                        




                                                                    


                                              
     
                                      
                               

                                      
                                                   

                                      
                               

                                      
                                                   

     

                                           

 

                                       


                                
                                          
 

                           
                              
                                      





                        
                            

                                                
 
 

                                        



                                       






                                                  
                                                        


                                                        
                                                        



                                            

                                                       


                                                




                                                                 
                                                
                                                         







                                                    
                                                         
 


                                              


                                   
                                                                  
                                       


        
                                                     
                                       
     
 
                          
 
 
                                                        
 
                                            
     
                           
     
 
/*
 *  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 <sstream>
#include <string>
#include <SDL.h>

#include <guichan/widgets/label.hpp>

#include "button.h"
#include "ok_dialog.h"
#include "playerbox.h"
#include "textfield.h"
#include "windowcontainer.h"
#include "../being.h"
#include "../game.h"
#include "../log.h"
#include "../main.h"
#include "../playerinfo.h"

#include "../net/messagein.h"
#include "../net/messageout.h"
#include "../net/network.h"
#include "../net/protocol.h"

CharSelectDialog::CharDeleteConfirm::CharDeleteConfirm(CharSelectDialog *m):
    ConfirmDialog(m,
            "Confirm", "Are you sure you want to delete this character?"),
    master(m), mStatus(0)
{
}

void CharSelectDialog::CharDeleteConfirm::action(const std::string &eventId)
{
    //ConfirmDialog::action(eventId);
    if (eventId == "yes") {
        master->attemptCharDelete();
        ConfirmDialog::yesButton->setEnabled(false);
        ConfirmDialog::noButton->setEnabled(false);
        mStatus = 1;
    }
    else
    {
        ConfirmDialog::action(eventId);
    }
}

void CharSelectDialog::CharDeleteConfirm::logic()
{
    if (mStatus == 1)
    {
        if (packetReady())
        {
            master->checkCharDelete();
            ConfirmDialog::action("yes");
        }
        else
        {
            flush();
        }
    }
}

CharSelectDialog::CharSelectDialog():
    Window("Select Character"), mStatus(0), mCurrentSlot(0)
{
    selectButton = new Button("Ok");
    cancelButton = new Button("Cancel");
    newCharButton = new Button("New");
    delCharButton = new Button("Delete");
    previousButton = new Button("Previous");
    nextButton = new Button("Next");
    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");
    previousButton->setEventId("previous");
    nextButton->setEventId("next");

    int w = 195;
    int h = 220;
    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));
    previousButton->setPosition(5, 170);
    nextButton->setPosition(previousButton->getWidth() + 10, 170);
    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(previousButton);
    add(nextButton);
    add(nameLabel);
    add(levelLabel);
    add(jobLevelLabel);
    add(moneyLabel);

    // Set up event listener
    selectButton->addActionListener(this);
    cancelButton->addActionListener(this);
    newCharButton->addActionListener(this);
    delCharButton->addActionListener(this);
    previousButton->addActionListener(this);
    nextButton->addActionListener(this);

    selectButton->requestFocus();
    setLocationRelativeTo(getParent());
    setPlayerInfo(NULL);
}

void CharSelectDialog::changeSlot(int slot)
{
    mCurrentSlot = slot;
    if (mCurrentSlot < 0)
    {
        mCurrentSlot = MAX_SLOT;
    }
    else if (mCurrentSlot > MAX_SLOT)
    {
        mCurrentSlot = 0;
    }
    
    if (char_info[mCurrentSlot] == NULL)
    {
        newCharButton->setEnabled(true);
    }
}

void CharSelectDialog::action(const std::string& eventId)
{
    if (eventId == "ok" && n_character > 0)
    {
        // Start game
        newCharButton->setEnabled(false);
        delCharButton->setEnabled(false);
        selectButton->setEnabled(false);
        previousButton->setEnabled(false);
        nextButton->setEnabled(false);
        attemptCharSelect();
        mStatus = 1;
    }
    else if (eventId == "cancel")
    {
        state = EXIT_STATE;
    }
    else if (eventId == "new")
    {
        if (n_character < MAX_SLOT + 1)
        {
            // Start new character dialog
            new CharCreateDialog(this, mCurrentSlot);
        }
    }
    else if (eventId == "delete")
    {
        // Delete character
        if (n_character > 0)
        {
            new CharDeleteConfirm(this);
        }
    }
    else if (eventId == "previous")
    {
        changeSlot(mCurrentSlot - 1);
    }
    else if (eventId == "next")
    {
        changeSlot(mCurrentSlot + 1);
    }
}

void CharSelectDialog::setPlayerInfo(PLAYER_INFO *pi)
{
    if (pi) {
        std::stringstream nameCaption, levelCaption, jobCaption, moneyCaption;

        nameCaption << pi->name;
        levelCaption << "Lvl: " << pi->lvl;
        jobCaption << "Job Lvl: " << pi->jobLvl;
        moneyCaption << "Gold: " << pi->gp;

        nameLabel->setCaption(nameCaption.str());
        levelLabel->setCaption(levelCaption.str());
        jobLevelLabel->setCaption(jobCaption.str());
        moneyLabel->setCaption(moneyCaption.str());
        if (mStatus != 1)
        {
            newCharButton->setEnabled(false);
            delCharButton->setEnabled(true);
            selectButton->setEnabled(true);
        }
        playerBox->hairStyle = pi->hairStyle - 1;
        playerBox->hairColor = pi->hairColor - 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::attemptCharDelete()
{
    // Request character deletion
    MessageOut outMsg;
    outMsg.writeInt16(0x0068);
    outMsg.writeInt32(char_info[mCurrentSlot]->id);
    outMsg.writeString("a@a.com", 40);
}

void CharSelectDialog::checkCharDelete()
{
    MessageIn msg = get_next_message();

    if (msg.getId() == 0x006f)
    {
        skip(msg.getLength());
        delete char_info[mCurrentSlot];
        n_character--;
        char_info[mCurrentSlot] = NULL;
        setPlayerInfo(NULL);
        new OkDialog(this, "Info", "Player deleted");
    }
    else if (msg.getId() == 0x0070)
    {
        new OkDialog(this, "Error", "Failed to delete character.");
        skip(msg.getLength());
    }
    else {
        new OkDialog(this, "Error", "Unknown");
        skip(msg.getLength());
    }
}

void CharSelectDialog::attemptCharSelect()
{
    // Request character selection
    MessageOut outMsg;
    outMsg.writeInt16(0x0066);
    outMsg.writeInt8(mCurrentSlot);
}

void
CharSelectDialog::checkCharSelect()
{
    // Receive reply
    MessageIn msg = get_next_message();
    if (state == ERROR_STATE)
    {
        return;
    }

    logger->log("CharSelect: Packet ID: %x, Length: %d, in_size: %d",
                msg.getId(), msg.getLength(), in_size);

    if (msg.getId() == 0x0071)
    {
        char_ID = msg.readInt32();
        map_path = "maps/" + msg.readString(16);
        map_path = map_path.substr(0, map_path.rfind(".")) + ".tmx.gz";
        map_address = msg.readInt32();
        map_port = msg.readInt16();
        player_info = char_info[mCurrentSlot];
        // Clear unselected players infos
        for (int i = 0; i < MAX_SLOT + 1; i++)
        {
            if (i != mCurrentSlot)
            {
                delete char_info[i];
            }
        }
        free(char_info);
        state = CONNECTING_STATE;

        logger->log("CharSelect: Map: %s", map_path.c_str());
        logger->log("CharSelect: Server: %s:%i", iptostring(map_address),
                    map_port);
        closeConnection();
    }
    else if (msg.getId() == 0x006c)
    {
        switch (msg.readInt8()) {
            case 0:
                errorMessage = "Access denied";
                break;
            case 1:
                errorMessage = "Cannot use this ID";
                break;
            default:
                errorMessage = "Unknown failure to select character";
                break;
        }
        skip(msg.getLength());
    }
    else if (msg.getId() == 0x0081)
    {
        switch (msg.readInt8()) {
            case 1:
                errorMessage = "Map server offline";
                break;
            case 3:
                errorMessage = "Speed hack detected";
                break;
            case 8:
                errorMessage = "Duplicated login";
                break;
            default:
                errorMessage = "Unkown error with 0x0081";
                break;
        }
        closeConnection();
        state = ERROR_STATE;
    }

    // Todo: add other packets
}

void CharSelectDialog::logic()
{
    if (n_character > 0)
    {
        setPlayerInfo(char_info[mCurrentSlot]);
    }
    
    if (mStatus == 1)
    {
        if (packetReady())
        {
            checkCharSelect();
        }
        else
        {
            flush();
        }
    }
}

CharCreateDialog::CharCreateDialog(Window *parent, int slot):
    Window("Create Character", true, parent), mStatus(0), mSlot(slot)
{
    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());
}

void CharCreateDialog::logic()
{
    if (mStatus == 1)
    {
        if (packetReady())
        {
            checkCharCreate();
        }
        else
        {
            flush();
        }
    }
}

void CharCreateDialog::action(const std::string& eventId)
{
    if (eventId == "create") {
        if (getName().length() >= 4) {
            // Attempt to create the character
            createButton->setEnabled(false);
            attemptCharCreate();
            mStatus = 1;
        }
        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::attemptCharCreate()
{
    // Send character infos
    MessageOut outMsg;
    outMsg.writeInt16(0x0067);
    outMsg.writeString(getName(), 24);
    outMsg.writeInt8(5);
    outMsg.writeInt8(5);
    outMsg.writeInt8(5);
    outMsg.writeInt8(5);
    outMsg.writeInt8(5);
    outMsg.writeInt8(5);
    outMsg.writeInt8(mSlot);
    outMsg.writeInt16(playerBox->hairColor + 1);
    outMsg.writeInt16(playerBox->hairStyle + 1);
}

void CharCreateDialog::checkCharCreate()
{
    MessageIn msg = get_next_message();

    if (msg.getId() == 0x006d)
    {
        PLAYER_INFO *tempPlayer = new PLAYER_INFO;

        tempPlayer->id = msg.readInt32();
        tempPlayer->xp = msg.readInt32();
        tempPlayer->gp = msg.readInt32();
        tempPlayer->jobXp = msg.readInt32();
        tempPlayer->jobLvl = msg.readInt32();
        msg.skip(8);                          // unknown
        msg.readInt32();                       // option
        msg.readInt32();                       // karma
        msg.readInt32();                       // manner
        msg.skip(2);                          // unknown
        tempPlayer->hp = msg.readInt16();
        tempPlayer->maxHp = msg.readInt16();
        tempPlayer->mp = msg.readInt16();
        tempPlayer->maxMp = msg.readInt16();
        msg.readInt16();                       // speed
        msg.readInt16();                       // class
        tempPlayer->hairStyle = msg.readInt16();
        tempPlayer->weapon = msg.readInt16();
        tempPlayer->lvl = msg.readInt16();
        msg.readInt16();                       // skill point
        msg.readInt16();                       // head bottom
        msg.readInt16();                       // shield
        msg.readInt16();                       // head option top
        msg.readInt16();                       // head option mid
        tempPlayer->hairColor = msg.readInt16();
        msg.readInt16();                       // unknown
        tempPlayer->name = msg.readString(24);
        tempPlayer->STR = msg.readInt8();
        tempPlayer->AGI = msg.readInt8();
        tempPlayer->VIT = msg.readInt8();
        tempPlayer->INT = msg.readInt8();
        tempPlayer->DEX = msg.readInt8();
        tempPlayer->LUK = msg.readInt8();
        int slot = msg.readInt8(); // character slot
        msg.readInt8();                        // unknown

        n_character++;
        char_info[slot] = tempPlayer;
        windowContainer->scheduleDelete(this);
    }
    else if (msg.getId() == 0x006e)
    {
        new OkDialog(this, "Error", "Failed to create character");
        createButton->setEnabled(true);
    }
    else
    {
        new OkDialog(this, "Error", "Unknown error");
        createButton->setEnabled(true);
    }

    skip(msg.getLength());
}

void charSelectInputHandler(SDL_KeyboardEvent *keyEvent)
{
    if (keyEvent->keysym.sym == SDLK_ESCAPE)
    {
        state = EXIT_STATE;
    }
}