summaryrefslogblamecommitdiff
path: root/src/gui/char_select.cpp
blob: f7042c70d5abb845568c47001c01813fd145275d (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 <string>

#include <guichan/widgets/label.hpp>

#include "button.h"
#include "confirm_dialog.h"
#include "ok_dialog.h"
#include "playerbox.h"
#include "slider.h"
#include "textfield.h"

#include "unregisterdialog.h"

#include "widgets/layout.h"

#include "../game.h"
#include "../localplayer.h"
#include "../main.h"
#include "../logindata.h"

#include "../net/accountserver/account.h"
#include "../net/charserverhandler.h"
#include "../net/messageout.h"

#include "../utils/gettext.h"
#include "../utils/strprintf.h"
#include "../utils/tostring.h"
#include "../utils/trim.h"

// Defined in main.cpp, used here for setting the char create dialog
extern CharServerHandler charServerHandler;

/**
 * Listener for confirming character deletion.
 */
class CharDeleteConfirm : public ConfirmDialog
{
    public:
        CharDeleteConfirm(CharSelectDialog *master);
        void action(const gcn::ActionEvent &event);
    private:
        CharSelectDialog *master;
};

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

void CharDeleteConfirm::action(const gcn::ActionEvent &event)
{
    //ConfirmDialog::action(event);
    if (event.getId() == "yes") {
        master->attemptCharDelete();
    }
    ConfirmDialog::action(event);
}

CharSelectDialog::CharSelectDialog(LockedArray<LocalPlayer*> *charInfo,
                                   LoginData *loginData):
    Window(_("Select Character")),
    mCharInfo(charInfo), mCharSelected(false), mLoginData(loginData)
{

    mSelectButton = new Button(_("Ok"), "ok", this);
    mCancelButton = new Button(_("Cancel"), "cancel", this);
    mNewCharButton = new Button(_("New"), "new", this);
    mDelCharButton = new Button(_("Delete"), "delete", this);
    mPreviousButton = new Button(_("Previous"), "previous", this);
    mNextButton = new Button(_("Next"), "next", this);
    mUnRegisterButton = new Button(_("Unregister"), "unregister", this);

    mNameLabel = new gcn::Label(strprintf(_("Name: %s"), ""));
    mLevelLabel = new gcn::Label(strprintf(_("Level: %d"), 0));
    mMoneyLabel = new gcn::Label(strprintf(_("Money: %d"), 0));
    mPlayerBox = new PlayerBox();

    Layout &layout = getLayout();
    place(0, 0, mPlayerBox, 1, 5).setPadding(3);
    place(1, 0, mNameLabel, 3);
    place(1, 1, mLevelLabel, 3);
    place(1, 2, mMoneyLabel, 3);
    place(1, 3, mPreviousButton);
    place(2, 3, mNextButton);
    place(1, 4, mNewCharButton);
    place(2, 4, mDelCharButton);
    layout.setWidth(250);
    layout.setColWidth(0, 80);
    layout.setColWidth(3, Layout::FILL);
    layout.matchColWidth(1, 2);
    layout.setRowHeight(5, 5);
    layout.flush();
    place(0, 0, mUnRegisterButton);
    place(2, 0, mSelectButton);
    place(3, 0, mCancelButton);
    layout.setColWidth(1, Layout::FILL);
    reflowLayout();
    forgetLayout();

    setLocationRelativeTo(getParent());
    setVisible(true);
    mSelectButton->requestFocus();
    updatePlayerInfo();
}

void CharSelectDialog::action(const gcn::ActionEvent &event)
{
    // The pointers are set to NULL if there is no character stored
    if (event.getId() == "ok" && (mCharInfo->getEntry()))
    {
        // Start game
        mNewCharButton->setEnabled(false);
        mDelCharButton->setEnabled(false);
        mSelectButton->setEnabled(false);
        mUnRegisterButton->setEnabled(false);
        mPreviousButton->setEnabled(false);
        mNextButton->setEnabled(false);
        mCharSelected = true;
        Net::AccountServer::Account::selectCharacter(mCharInfo->getPos());
        mCharInfo->lock();
    }
    else if (event.getId() == "cancel")
    {
        state = STATE_EXIT;
    }
    else if (event.getId() == "new")
    {
        // TODO: Search the first free slot, and start CharCreateDialog
        //       maybe add that search to the constructor.
        if (!(mCharInfo->getEntry()))
        {
            // Start new character dialog
            CharCreateDialog *charCreateDialog =
                new CharCreateDialog(this, mCharInfo->getPos());
            charServerHandler.setCharCreateDialog(charCreateDialog);
        }
    }
    else if (event.getId() == "delete")
    {
        // Delete character
        if (mCharInfo->getEntry())
        {
            new CharDeleteConfirm(this);
        }
    }
    else if (event.getId() == "previous")
    {
        mCharInfo->prev();
    }
    else if (event.getId() == "next")
    {
        mCharInfo->next();
    }
    else if (event.getId() == "unregister")
    {
        new UnRegisterDialog(this, mLoginData);
    }
}

void CharSelectDialog::updatePlayerInfo()
{
    LocalPlayer *pi = mCharInfo->getEntry();

    if (pi)
    {
        mNameLabel->setCaption(strprintf(_("Name: %s"), pi->getName().c_str()));
        mLevelLabel->setCaption(strprintf(_("Level: %d"), pi->getLevel()));
        mMoneyLabel->setCaption(strprintf(_("Money: %d"), pi->getMoney()));
        if (!mCharSelected)
        {
            mNewCharButton->setEnabled(false);
            mDelCharButton->setEnabled(true);
            mSelectButton->setEnabled(true);
        }
    }
    else {
        mNameLabel->setCaption(strprintf(_("Name: %s"), ""));
        mLevelLabel->setCaption(strprintf(_("Level: %d"), 0));
        mMoneyLabel->setCaption(strprintf(_("Money: %d"), 0));
        mNewCharButton->setEnabled(true);
        mDelCharButton->setEnabled(false);
        mSelectButton->setEnabled(false);
    }

    mPlayerBox->setPlayer(pi);
}

void CharSelectDialog::attemptCharDelete()
{
    Net::AccountServer::Account::deleteCharacter(mCharInfo->getPos());
    mCharInfo->lock();
}

void CharSelectDialog::logic()
{
    updatePlayerInfo();
}

bool CharSelectDialog::selectByName(const std::string &name)
{
    if (mCharInfo->isLocked())
        return false;

    unsigned int oldPos = mCharInfo->getPos();

    mCharInfo->select(0);
    do {
        LocalPlayer *player = mCharInfo->getEntry();

        if (player && player->getName() == name)
            return true;

        mCharInfo->next();
    } while (mCharInfo->getPos());

    mCharInfo->select(oldPos);

    return false;
}

CharCreateDialog::CharCreateDialog(Window *parent, int slot):
    Window(_("Create Character"), true, parent), mSlot(slot)
{
    mPlayer = new Player(0, 0, NULL);
    mPlayer->setHairStyle(rand() % NR_HAIR_STYLES);
    mPlayer->setHairColor(rand() % NR_HAIR_COLORS);

    mNameField = new TextField("");
    mNameLabel = new gcn::Label(_("Name:"));
    mNextHairColorButton = new Button(">", "nextcolor", this);
    mPrevHairColorButton = new Button("<", "prevcolor", this);
    mHairColorLabel = new gcn::Label(_("Hair Color:"));
    mNextHairStyleButton = new Button(">", "nextstyle", this);
    mPrevHairStyleButton = new Button("<", "prevstyle", this);
    mHairStyleLabel = new gcn::Label(_("Hair Style:"));
    mCreateButton = new Button(_("Create"), "create", this);
    mCancelButton = new Button(_("Cancel"), "cancel", this);
    mPlayerBox = new PlayerBox(mPlayer);
    mAttributeLabel[0] = new gcn::Label(_("Strength:"));
    mAttributeLabel[1] = new gcn::Label(_("Agility:"));
    mAttributeLabel[2] = new gcn::Label(_("Dexterity:"));
    mAttributeLabel[3] = new gcn::Label(_("Vitality:"));
    mAttributeLabel[4] = new gcn::Label(_("Intelligence:"));
    mAttributeLabel[5] = new gcn::Label(_("Willpower:"));
    mAttributeLabel[6] = new gcn::Label(_("Charisma:"));
    for (int i=0; i<7; i++)
    {
        mAttributeLabel[i]->setWidth(70);
        mAttributeSlider[i] = new Slider(1, 20);
        mAttributeValue[i] = new gcn::Label("1");
    };

    mAttributesLeft = new gcn::Label(strprintf(_("Please distribute %d points"), 99));

    mNameField->setActionEventId("create");

    int w = 200;
    int h = 330;
    setContentSize(w, h);
    mPlayerBox->setDimension(gcn::Rectangle(80, 30, 110, 85));
    mNameLabel->setPosition(5, 5);
    mNameField->setDimension(
            gcn::Rectangle(45, 5, w - 45 - 7, mNameField->getHeight()));
    mPrevHairColorButton->setPosition(90, 35);
    mNextHairColorButton->setPosition(165, 35);
    mHairColorLabel->setPosition(5, 40);
    mPrevHairStyleButton->setPosition(90, 64);
    mNextHairStyleButton->setPosition(165, 64);
    mHairStyleLabel->setPosition(5, 70);
    for (int i=0; i<7; i++)
    {
        mAttributeSlider[i]->setValue(10);
        mAttributeSlider[i]->setDimension(gcn::Rectangle(   75, 140 + i*20,
                                                            100, 10));
        mAttributeSlider[i]->setActionEventId("statslider");
        mAttributeSlider[i]->addActionListener(this);
        mAttributeValue[i]->setPosition(180, 140 + i*20);
        mAttributeLabel[i]->setPosition(5, 140 + i*20);
    };
    mAttributesLeft->setPosition(15, 280);
    UpdateSliders();
    mCancelButton->setPosition(
            w - 5 - mCancelButton->getWidth(),
            h - 5 - mCancelButton->getHeight());
    mCreateButton->setPosition(
            mCancelButton->getX() - 5 - mCreateButton->getWidth(),
            h - 5 - mCancelButton->getHeight());

    mNameField->addActionListener(this);

    add(mPlayerBox);
    add(mNameField);
    add(mNameLabel);
    add(mNextHairColorButton);
    add(mPrevHairColorButton);
    add(mHairColorLabel);
    add(mNextHairStyleButton);
    add(mPrevHairStyleButton);
    add(mHairStyleLabel);
    for (int i=0; i<7; i++)
    {
        add(mAttributeSlider[i]);
        add(mAttributeValue[i]);
        add(mAttributeLabel[i]);
    };
    add(mAttributesLeft);
    add(mCreateButton);
    add(mCancelButton);

    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)
{
    if (event.getId() == "create") {
        if (getName().length() >= 4) {
            // Attempt to create the character
            mCreateButton->setEnabled(false);
            Net::AccountServer::Account::createCharacter(
                    getName(),
                    mPlayer->getHairStyle(),
                    mPlayer->getHairColor(),
                    0,   // gender
                    (int) mAttributeSlider[0]->getValue(),  // STR
                    (int) mAttributeSlider[1]->getValue(),  // AGI
                    (int) mAttributeSlider[2]->getValue(),  // DEX
                    (int) mAttributeSlider[3]->getValue(),  // VIT
                    (int) mAttributeSlider[4]->getValue(),  // INT
                    (int) mAttributeSlider[5]->getValue(),  // WILL
                    (int) mAttributeSlider[6]->getValue()   // CHAR
            );
        }
        else {
            new OkDialog(_("Error"),
                    _("Your name needs to be at least 4 characters."), this);
        }
    }
    else if (event.getId() == "cancel") {
        scheduleDelete();
    }
    else if (event.getId() == "nextcolor") {
        mPlayer->setHairColor((mPlayer->getHairColor() + 1) % NR_HAIR_COLORS);
    }
    else if (event.getId() == "prevcolor") {
        int prevColor = mPlayer->getHairColor() + NR_HAIR_COLORS - 1;
        mPlayer->setHairColor(prevColor % NR_HAIR_COLORS);
    }
    else if (event.getId() == "nextstyle") {
        mPlayer->setHairStyle((mPlayer->getHairStyle() + 1) % NR_HAIR_STYLES);
    }
    else if (event.getId() == "prevstyle") {
        int prevStyle = mPlayer->getHairStyle() + NR_HAIR_STYLES - 1;
        mPlayer->setHairStyle(prevStyle % NR_HAIR_STYLES);
    }
    else if (event.getId() == "statslider") {
        UpdateSliders();
    }
}

std::string
CharCreateDialog::getName()
{
    std::string name = mNameField->getText();
    trim(name);
    return name;
}

void CharCreateDialog::UpdateSliders()
{
    for (int i = 0; i < 7; i++)
    {
        // Update captions
        mAttributeValue[i]->setCaption(
                toString((int) (mAttributeSlider[i]->getValue())));
        mAttributeValue[i]->adjustSize();
    }

    // Update distributed points
    int pointsLeft = 70 - getDistributedPoints();
    if (pointsLeft == 0)
    {
        mAttributesLeft->setCaption(_("Character stats OK"));
        mCreateButton->setEnabled(true);
    }
    else
    {
        mCreateButton->setEnabled(false);
        if (pointsLeft > 0)
        {
            mAttributesLeft->setCaption(strprintf(_("Please distribute %d points"), pointsLeft));
        }
        else
        {
            mAttributesLeft->setCaption(strprintf(_("Please remove %d points"), -pointsLeft));
        }
    }

    mAttributesLeft->adjustSize();
}

void
CharCreateDialog::unlock()
{
    mCreateButton->setEnabled(true);
}

int CharCreateDialog::getDistributedPoints()
{
    int points = 0;

    for (int i = 0; i < 7; i++)
    {
        points += (int) mAttributeSlider[i]->getValue();
    }
    return points;
}