git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/irrlicht@4155 178a84e3-b1eb-0310-8ba1-8eac791a3b58
866 lines
32 KiB
C++
866 lines
32 KiB
C++
// $Id$
|
|
//
|
|
// SuperTuxKart - a fun racing game with go-kart
|
|
// Copyright (C) 2006
|
|
//
|
|
// This program 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 3
|
|
// of the License, or (at your option) any later version.
|
|
//
|
|
// This program 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 this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
#include "config/player.hpp"
|
|
#include "config/user_config.hpp"
|
|
#include "kart_selection.hpp"
|
|
#include "graphics/irr_driver.hpp"
|
|
#include "guiengine/widget.hpp"
|
|
#include "guiengine/engine.hpp"
|
|
#include "guiengine/screen.hpp"
|
|
#include "input/input.hpp"
|
|
#include "input/input_manager.hpp"
|
|
#include "input/device_manager.hpp"
|
|
#include "input/input_device.hpp"
|
|
#include "items/item_manager.hpp"
|
|
#include "io/file_manager.hpp"
|
|
#include "karts/kart.hpp"
|
|
#include "karts/kart_properties_manager.hpp"
|
|
#include "states_screens/race_setup_screen.hpp"
|
|
#include "states_screens/state_manager.hpp"
|
|
#include "utils/translation.hpp"
|
|
#include "utils/random_generator.hpp"
|
|
#include "utils/string_utils.hpp"
|
|
|
|
#include <string>
|
|
|
|
InputDevice* player_1_device = NULL;
|
|
|
|
using namespace GUIEngine;
|
|
|
|
class PlayerKartWidget;
|
|
|
|
// ref only since we're adding them to a Screen, and the Screen will take ownership of these widgets
|
|
ptr_vector<PlayerKartWidget, REF> g_player_karts;
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark PlayerKartWidget
|
|
#endif
|
|
|
|
class PlayerNameSpinner : public SpinnerWidget
|
|
{
|
|
int playerID;
|
|
|
|
virtual EventPropagation focused(const int playerID) ;
|
|
|
|
public:
|
|
PlayerNameSpinner(const int playerID)
|
|
{
|
|
PlayerNameSpinner::playerID = playerID;
|
|
}
|
|
void setID(const int playerID)
|
|
{
|
|
PlayerNameSpinner::playerID = playerID;
|
|
}
|
|
};
|
|
|
|
class PlayerKartWidget : public Widget
|
|
{
|
|
float x_speed, y_speed, w_speed, h_speed;
|
|
|
|
public:
|
|
LabelWidget* playerIDLabel;
|
|
PlayerNameSpinner* playerName;
|
|
ModelViewWidget* modelView;
|
|
LabelWidget* kartName;
|
|
|
|
ActivePlayer* m_associatedPlayer;
|
|
|
|
int playerID;
|
|
std::string spinnerID;
|
|
|
|
int player_id_x, player_id_y, player_id_w, player_id_h;
|
|
int player_name_x, player_name_y, player_name_w, player_name_h;
|
|
int model_x, model_y, model_w, model_h;
|
|
int kart_name_x, kart_name_y, kart_name_w, kart_name_h;
|
|
int m_irrlicht_widget_ID;
|
|
|
|
int target_x, target_y, target_w, target_h;
|
|
|
|
LabelWidget *getPlayerIDLabel() {return playerIDLabel;}
|
|
std::string deviceName;
|
|
std::string m_kartInternalName;
|
|
|
|
PlayerKartWidget(ActivePlayer* associatedPlayer, Widget* area, const int playerID, const int irrlichtWidgetID=-1) : Widget()
|
|
{
|
|
m_associatedPlayer = associatedPlayer;
|
|
x_speed = 1.0f;
|
|
y_speed = 1.0f;
|
|
w_speed = 1.0f;
|
|
h_speed = 1.0f;
|
|
|
|
m_irrlicht_widget_ID = irrlichtWidgetID;
|
|
|
|
this->playerID = playerID;
|
|
this->m_properties[PROP_ID] = StringUtils::insertValues("@p%i", playerID);
|
|
|
|
setSize(area->x, area->y, area->w, area->h);
|
|
target_x = x;
|
|
target_y = y;
|
|
target_w = w;
|
|
target_h = h;
|
|
|
|
if (associatedPlayer->getDevice()->getType() == DT_KEYBOARD)
|
|
{
|
|
deviceName += "keyboard";
|
|
}
|
|
else if (associatedPlayer->getDevice()->getType() == DT_GAMEPAD)
|
|
{
|
|
deviceName += "gamepad";
|
|
}
|
|
|
|
playerIDLabel = new LabelWidget();
|
|
|
|
playerIDLabel->m_text =
|
|
//I18N: In kart selection screen (Will read like 'Player 1 (foobartech gamepad)')
|
|
StringUtils::insertValues(_("Player %i (%s)"), playerID + 1, deviceName.c_str());
|
|
|
|
playerIDLabel->m_properties[PROP_TEXT_ALIGN] = "center";
|
|
playerIDLabel->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_label", playerID);
|
|
playerIDLabel->x = player_id_x;
|
|
playerIDLabel->y = player_id_y;
|
|
playerIDLabel->w = player_id_w;
|
|
playerIDLabel->h = player_id_h;
|
|
|
|
//playerID->setParent(this);
|
|
m_children.push_back(playerIDLabel);
|
|
|
|
playerName = new PlayerNameSpinner(playerID);
|
|
playerName->x = player_name_x;
|
|
playerName->y = player_name_y;
|
|
playerName->w = player_name_w;
|
|
playerName->h = player_name_h;
|
|
|
|
if (irrlichtWidgetID == -1)
|
|
{
|
|
// FIXME : don't rely so hard on player 0 being the "root" ?
|
|
playerName->m_tab_down_root = g_player_karts[0].playerName->getIrrlichtElement()->getID();
|
|
}
|
|
|
|
spinnerID = StringUtils::insertValues("@p%i_spinner", playerID);
|
|
|
|
const int playerAmount = UserConfigParams::m_all_players.size();
|
|
playerName->m_properties[PROP_MIN_VALUE] = "0";
|
|
playerName->m_properties[PROP_MAX_VALUE] = (playerAmount-1);
|
|
playerName->m_properties[PROP_ID] = spinnerID;
|
|
//playerName->setParent(this);
|
|
m_children.push_back(playerName);
|
|
|
|
|
|
playerName->m_event_handler = this;
|
|
|
|
modelView = new ModelViewWidget();
|
|
|
|
modelView->x = model_x;
|
|
modelView->y = model_y;
|
|
modelView->w = model_w;
|
|
modelView->h = model_h;
|
|
modelView->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_model", playerID);
|
|
//modelView->setParent(this);
|
|
m_children.push_back(modelView);
|
|
|
|
// Init kart model
|
|
std::string& default_kart = UserConfigParams::m_default_kart;
|
|
const KartProperties* props = kart_properties_manager->getKart(default_kart);
|
|
KartModel* kartModel = props->getKartModel();
|
|
|
|
this->modelView->addModel( kartModel->getModel() );
|
|
this->modelView->addModel( kartModel->getWheelModel(0), kartModel->getWheelGraphicsPosition(0) );
|
|
this->modelView->addModel( kartModel->getWheelModel(1), kartModel->getWheelGraphicsPosition(1) );
|
|
this->modelView->addModel( kartModel->getWheelModel(2), kartModel->getWheelGraphicsPosition(2) );
|
|
this->modelView->addModel( kartModel->getWheelModel(3), kartModel->getWheelGraphicsPosition(3) );
|
|
|
|
kartName = new LabelWidget();
|
|
kartName->m_text = props->getName();
|
|
kartName->m_properties[PROP_TEXT_ALIGN] = "center";
|
|
kartName->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_kartname", playerID);
|
|
kartName->x = kart_name_x;
|
|
kartName->y = kart_name_y;
|
|
kartName->w = kart_name_w;
|
|
kartName->h = kart_name_h;
|
|
//kartName->setParent(this);
|
|
m_children.push_back(kartName);
|
|
}
|
|
|
|
~PlayerKartWidget()
|
|
{
|
|
if (playerIDLabel->getIrrlichtElement() != NULL)
|
|
playerIDLabel->getIrrlichtElement()->remove();
|
|
|
|
if (playerName->getIrrlichtElement() != NULL)
|
|
playerName->getIrrlichtElement()->remove();
|
|
|
|
if (modelView->getIrrlichtElement() != NULL)
|
|
modelView->getIrrlichtElement()->remove();
|
|
|
|
if (kartName->getIrrlichtElement() != NULL)
|
|
kartName->getIrrlichtElement()->remove();
|
|
|
|
getCurrentScreen()->manualRemoveWidget(this);
|
|
}
|
|
|
|
void setPlayerID(const int newPlayerID)
|
|
{
|
|
if (StateManager::get()->getActivePlayers().get(newPlayerID) != m_associatedPlayer)
|
|
{
|
|
printf("Player: %p\nIndex: %d\nm_associatedPlayer: %p\n", StateManager::get()->getActivePlayers().get(newPlayerID), newPlayerID, m_associatedPlayer);
|
|
std::cerr << "Internal inconsistency, PlayerKartWidget has IDs and pointers that do not correspond to one player\n";
|
|
assert(false);
|
|
}
|
|
|
|
playerID = newPlayerID;
|
|
|
|
//I18N: In kart selection screen (Will read like 'Player 1 (foobartech gamepad)')
|
|
irr::core::stringw newLabel = StringUtils::insertValues(_("Player %i (%s)"), playerID + 1, deviceName.c_str());
|
|
playerIDLabel->setText( newLabel );
|
|
playerIDLabel->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_label", playerID);
|
|
playerName->setID(playerID);
|
|
}
|
|
|
|
virtual void add()
|
|
{
|
|
playerIDLabel->add();
|
|
|
|
// the first player will have an ID of its own to allow for keyboard navigation despite this widget being added last
|
|
if (m_irrlicht_widget_ID != -1) playerName->m_reserved_id = m_irrlicht_widget_ID;
|
|
else playerName->m_reserved_id = Widget::getNewNoFocusID();
|
|
|
|
playerName->add();
|
|
playerName->getIrrlichtElement()->setTabStop(false);
|
|
|
|
modelView->add();
|
|
kartName->add();
|
|
|
|
modelView->update(0);
|
|
|
|
playerName->clearLabels();
|
|
const int playerAmount = UserConfigParams::m_all_players.size();
|
|
for(int n=0; n<playerAmount; n++)
|
|
{
|
|
playerName->addLabel( UserConfigParams::m_all_players[n].getName() );
|
|
}
|
|
|
|
}
|
|
|
|
void move(const int x, const int y, const int w, const int h)
|
|
{
|
|
target_x = x;
|
|
target_y = y;
|
|
target_w = w;
|
|
target_h = h;
|
|
|
|
x_speed = abs( this->x - x ) / 300.0f;
|
|
y_speed = abs( this->y - y ) / 300.0f;
|
|
w_speed = abs( this->w - w ) / 300.0f;
|
|
h_speed = abs( this->h - h ) / 300.0f;
|
|
}
|
|
|
|
void onUpdate(float delta)
|
|
{
|
|
if (target_x == x && target_y == y && target_w == w && target_h == h) return;
|
|
|
|
int move_step = (int)(delta*1000.0f);
|
|
|
|
// move x towards target
|
|
if (x < target_x)
|
|
{
|
|
x += (int)(move_step*x_speed);
|
|
if (x > target_x) x = target_x; // don't move to the other side of the target
|
|
}
|
|
else if (x > target_x)
|
|
{
|
|
x -= (int)(move_step*x_speed);
|
|
if (x < target_x) x = target_x; // don't move to the other side of the target
|
|
}
|
|
|
|
// move y towards target
|
|
if (y < target_y)
|
|
{
|
|
y += (int)(move_step*y_speed);
|
|
if (y > target_y) y = target_y; // don't move to the other side of the target
|
|
}
|
|
else if (y > target_y)
|
|
{
|
|
y -= (int)(move_step*y_speed);
|
|
if (y < target_y) y = target_y; // don't move to the other side of the target
|
|
}
|
|
|
|
// move w towards target
|
|
if (w < target_w)
|
|
{
|
|
w += (int)(move_step*w_speed);
|
|
if (w > target_w) w = target_w; // don't move to the other side of the target
|
|
}
|
|
else if (w > target_w)
|
|
{
|
|
w -= (int)(move_step*w_speed);
|
|
if (w < target_w) w = target_w; // don't move to the other side of the target
|
|
}
|
|
// move h towards target
|
|
if (h < target_h)
|
|
{
|
|
h += (int)(move_step*h_speed);
|
|
if (h > target_h) h = target_h; // don't move to the other side of the target
|
|
}
|
|
else if (h > target_h)
|
|
{
|
|
h -= (int)(move_step*h_speed);
|
|
if (h < target_h) h = target_h; // don't move to the other side of the target
|
|
}
|
|
|
|
setSize(x, y, w, h);
|
|
|
|
playerIDLabel->move(player_id_x,
|
|
player_id_y,
|
|
player_id_w,
|
|
player_id_h);
|
|
playerName->move(player_name_x,
|
|
player_name_y,
|
|
player_name_w,
|
|
player_name_h );
|
|
modelView->move(model_x,
|
|
model_y,
|
|
model_w,
|
|
model_h);
|
|
kartName->move(kart_name_x,
|
|
kart_name_y,
|
|
kart_name_w,
|
|
kart_name_h);
|
|
|
|
}
|
|
// disabled but some events were disptached twice (e.g. spinner clicks)
|
|
#if 0
|
|
virtual bool transmitEvent(Widget* w, std::string& originator, const int playerID)
|
|
{
|
|
std::cout << "= kart selection :: transmitEvent " << originator << "=\n";
|
|
Widget* topmost = w;
|
|
/* Find topmost parent. Stop looping if a widget event handler's is itself, to not fall
|
|
in an infinite loop (this can happen e.g. in checkboxes, where they need to be
|
|
notified of clicks onto themselves so they can toggle their state. )
|
|
*/
|
|
while (topmost->m_event_handler != NULL && topmost->m_event_handler != topmost)
|
|
{
|
|
// transmit events to all listeners in the chain
|
|
std::cout << "transmitting event to widget " << topmost->m_type << std::endl;
|
|
if (!topmost->transmitEvent(w, originator, playerID)) return false;
|
|
topmost = topmost->m_event_handler;
|
|
|
|
std::string name = topmost->m_properties[PROP_ID];
|
|
|
|
if (name == spinnerID)
|
|
{
|
|
m_associatedPlayer->setPlayerProfile( UserConfigParams::m_all_players.get(playerName->getValue()) );
|
|
|
|
// transmit events to all listeners in the chain
|
|
std::cout << "transmitting event to widget " << topmost->m_type << std::endl;
|
|
if (!topmost->transmitEvent(w, originator, playerID)) return false;
|
|
|
|
return false; // do not continue propagating the event
|
|
}
|
|
|
|
}
|
|
|
|
return true; // continue propagating the event
|
|
}
|
|
#endif
|
|
void setSize(const int x, const int y, const int w, const int h)
|
|
{
|
|
this->x = x;
|
|
this->y = y;
|
|
this->w = w;
|
|
this->h = h;
|
|
|
|
// -- sizes
|
|
player_id_w = w;
|
|
player_id_h = 25;
|
|
|
|
player_name_h = 40;
|
|
player_name_w = std::min(400, w);
|
|
|
|
kart_name_w = w;
|
|
kart_name_h = 25;
|
|
|
|
// for shrinking effect
|
|
if (h < 175)
|
|
{
|
|
const float factor = h / 175.0f;
|
|
kart_name_h = (int)(kart_name_h*factor);
|
|
player_name_h = (int)(player_name_h*factor);
|
|
player_id_h = (int)(player_id_h*factor);
|
|
}
|
|
|
|
// --- layout
|
|
player_id_x = x;
|
|
player_id_y = y;
|
|
|
|
player_name_x = x + w/2 - player_name_w/2;
|
|
player_name_y = y + player_id_h;
|
|
|
|
const int modelMaxHeight = h - kart_name_h - player_name_h - player_id_h;
|
|
const int modelMaxWidth = w;
|
|
const int bestSize = std::min(modelMaxWidth, modelMaxHeight);
|
|
const int modelY = y + player_name_h + player_id_h;
|
|
model_x = x + w/2 - (int)(bestSize/2);
|
|
model_y = modelY + modelMaxHeight/2 - bestSize/2;
|
|
model_w = (int)(bestSize);
|
|
model_h = bestSize;
|
|
|
|
kart_name_x = x;
|
|
kart_name_y = y + h - kart_name_h;
|
|
}
|
|
void setKartInternalName(const std::string& whichKart)
|
|
{
|
|
m_kartInternalName = whichKart;
|
|
}
|
|
};
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark KartHoverListener
|
|
#endif
|
|
|
|
class KartHoverListener : public DynamicRibbonHoverListener
|
|
{
|
|
public:
|
|
void onSelectionChanged(DynamicRibbonWidget* theWidget, const std::string& selectionID,
|
|
const irr::core::stringw& selectionText, const int playerID)
|
|
{
|
|
ModelViewWidget* w3 = g_player_karts[playerID].modelView;
|
|
assert( w3 != NULL );
|
|
|
|
if (selectionID == "gui/track_random.png")
|
|
{
|
|
scene::IMesh* model = item_manager->getItemModel(Item::ITEM_BONUS_BOX);
|
|
w3->clearModels();
|
|
w3->addModel( model, Vec3(0.0f, 0.0f, -12.0f) );
|
|
w3->update(0);
|
|
g_player_karts[playerID].kartName->setText( _("Random Kart") );
|
|
}
|
|
else
|
|
{
|
|
//printf("%s\n", selectionID.c_str());
|
|
const KartProperties* kart = kart_properties_manager->getKart(selectionID);
|
|
if (kart == NULL) return;
|
|
KartModel* kartModel = kart->getKartModel();
|
|
|
|
w3->clearModels();
|
|
w3->addModel( kartModel->getModel() );
|
|
w3->addModel( kartModel->getWheelModel(0), kartModel->getWheelGraphicsPosition(0) );
|
|
w3->addModel( kartModel->getWheelModel(1), kartModel->getWheelGraphicsPosition(1) );
|
|
w3->addModel( kartModel->getWheelModel(2), kartModel->getWheelGraphicsPosition(2) );
|
|
w3->addModel( kartModel->getWheelModel(3), kartModel->getWheelGraphicsPosition(3) );
|
|
w3->update(0);
|
|
|
|
g_player_karts[playerID].kartName->setText( selectionText.c_str() );
|
|
}
|
|
|
|
g_player_karts[playerID].setKartInternalName(selectionID);
|
|
}
|
|
};
|
|
KartHoverListener* karthoverListener = NULL;
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark KartSelectionScreen
|
|
#endif
|
|
|
|
KartSelectionScreen::KartSelectionScreen() : Screen("karts.stkgui")
|
|
{
|
|
}
|
|
|
|
// Return true if event was handled successfully
|
|
bool KartSelectionScreen::playerJoin(InputDevice* device, bool firstPlayer)
|
|
{
|
|
std::cout << "playerJoin() ==========\n";
|
|
|
|
DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("karts");
|
|
if (w == NULL)
|
|
{
|
|
std::cerr << "playerJoin(): Called outside of kart selection screen.\n";
|
|
return false;
|
|
}
|
|
else if (device == NULL)
|
|
{
|
|
std::cerr << "playerJoin(): Passed null pointer\n";
|
|
return false;
|
|
}
|
|
|
|
// ---- Get available area for karts
|
|
// make a copy of the area, ands move it to be outside the screen
|
|
Widget rightarea = *this->getWidget("playerskarts");
|
|
rightarea.x = irr_driver->getFrameSize().Width; // start at the rightmost of the screen
|
|
|
|
// ---- Create new active player
|
|
int id = StateManager::get()->createActivePlayer( UserConfigParams::m_all_players.get(0), device );
|
|
ActivePlayer *aplayer = StateManager::get()->getActivePlayer(id);
|
|
|
|
// ---- Create player/kart widget
|
|
PlayerKartWidget* newPlayer;
|
|
if (firstPlayer)
|
|
newPlayer = new PlayerKartWidget(aplayer, &rightarea, g_player_karts.size(), rightarea.m_reserved_id);
|
|
else
|
|
newPlayer = new PlayerKartWidget(aplayer, &rightarea, g_player_karts.size());
|
|
|
|
//FIXME : currently, only player 0's spinner is focusable - and it dispatches focus to one of
|
|
// the others as needed. But if player 0 leaves, it will be impossible for remaining players
|
|
// to select their ident
|
|
|
|
this->manualAddWidget(newPlayer);
|
|
newPlayer->add();
|
|
|
|
g_player_karts.push_back(newPlayer);
|
|
|
|
// ---- Divide screen space among all karts
|
|
const int amount = g_player_karts.size();
|
|
Widget* fullarea = this->getWidget("playerskarts");
|
|
const int splitWidth = fullarea->w / amount;
|
|
|
|
for (int n=0; n<amount; n++)
|
|
{
|
|
g_player_karts[n].move( fullarea->x + splitWidth*n, fullarea->y, splitWidth, fullarea->h );
|
|
}
|
|
|
|
// ---- Focus a kart for this player
|
|
const int playerID = amount-1;
|
|
w->setSelection(playerID, playerID);
|
|
|
|
return true;
|
|
}
|
|
|
|
PlayerKartWidget* removedWidget = NULL;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Return true if event was handled succesfully
|
|
bool KartSelectionScreen::playerQuit(ActivePlayer* player)
|
|
{
|
|
int playerID = -1;
|
|
|
|
DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("karts");
|
|
if (w == NULL)
|
|
{
|
|
std::cout << "playerQuit() called outside of kart selection screen.\n";
|
|
return false;
|
|
}
|
|
|
|
// If last player quits, return to main menu
|
|
if (g_player_karts.size() <= 1) return false;
|
|
|
|
std::cout << "playerQuit() ==========\n";
|
|
|
|
for (int n=0; n<g_player_karts.size(); n++)
|
|
{
|
|
if (g_player_karts[n].m_associatedPlayer == player)
|
|
{
|
|
playerID = n;
|
|
break;
|
|
}
|
|
}
|
|
if (playerID == -1)
|
|
{
|
|
std::cout << "void playerQuit(ActivePlayer* player) : cannot find passed player\n";
|
|
return false;
|
|
}
|
|
|
|
// Just a cheap way to check if there is any discrepancy
|
|
// between g_player_karts and the active player array
|
|
assert( g_player_karts.size() == StateManager::get()->activePlayerCount() );
|
|
|
|
// unset selection of this player
|
|
// FIXME: will only work if the player that quits is the last of the list
|
|
if (GUIEngine::g_focus_for_player[playerID] != NULL)
|
|
{
|
|
GUIEngine::g_focus_for_player[playerID]->unsetFocusForPlayer(playerID);
|
|
}
|
|
GUIEngine::g_focus_for_player[playerID] = NULL;
|
|
|
|
removedWidget = g_player_karts.remove(playerID);
|
|
StateManager::get()->removeActivePlayer(playerID);
|
|
renumberKarts();
|
|
Widget* fullarea = this->getWidget("playerskarts");
|
|
removedWidget->move( removedWidget->x + removedWidget->w/2, fullarea->y + fullarea->h, 0, 0);
|
|
return true;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void KartSelectionScreen::onUpdate(float delta, irr::video::IVideoDriver*)
|
|
{
|
|
const int amount = g_player_karts.size();
|
|
for (int n=0; n<amount; n++)
|
|
{
|
|
g_player_karts[n].onUpdate(delta);
|
|
}
|
|
|
|
if (removedWidget != NULL)
|
|
{
|
|
removedWidget->onUpdate(delta);
|
|
|
|
if (removedWidget->w == 0 || removedWidget->h == 0)
|
|
{
|
|
// destruct when too small (for "disappear" effects)
|
|
this->manualRemoveWidget(removedWidget);
|
|
delete removedWidget;
|
|
removedWidget = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
void KartSelectionScreen::tearDown()
|
|
{
|
|
//g_player_karts.clearWithoutDeleting();
|
|
g_player_karts.clearAndDeleteAll();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
void KartSelectionScreen::init()
|
|
{
|
|
// FIXME: Reload previous kart selection screen state
|
|
g_player_karts.clearAndDeleteAll();
|
|
StateManager::get()->resetActivePlayers();
|
|
input_manager->getDeviceList()->setAssignMode(DETECT_NEW);
|
|
|
|
DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("karts");
|
|
assert( w != NULL );
|
|
|
|
if (karthoverListener == NULL)
|
|
{
|
|
karthoverListener = new KartHoverListener();
|
|
w->registerHoverListener(karthoverListener);
|
|
}
|
|
|
|
// Build kart list
|
|
// (it is built everytikme, to account for .g. locking)
|
|
w->clearItems();
|
|
std::vector<int> group = kart_properties_manager->getKartsInGroup("standard");
|
|
const int kart_amount = group.size();
|
|
|
|
// add Tux (or whatever default kart) first
|
|
std::string& default_kart = UserConfigParams::m_default_kart;
|
|
for(int n=0; n<kart_amount; n++)
|
|
{
|
|
const KartProperties* prop = kart_properties_manager->getKartById(group[n]);
|
|
if (prop->getIdent() == default_kart)
|
|
{
|
|
std::string icon_path = file_manager->getDataDir() ;
|
|
icon_path += "/karts/" + prop->getIdent() + "/" + prop->getIconFile();
|
|
w->addItem(prop->getName(), prop->getIdent().c_str(), icon_path.c_str());
|
|
//std::cout << "Add item : " << prop->getIdent().c_str() << std::endl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// add others
|
|
for(int n=0; n<kart_amount; n++)
|
|
{
|
|
const KartProperties* prop = kart_properties_manager->getKartById(group[n]);
|
|
if (prop->getIdent() != default_kart)
|
|
{
|
|
std::string icon_path = file_manager->getDataDir() ;
|
|
icon_path += "/karts/" + prop->getIdent() + "/" + prop->getIconFile();
|
|
w->addItem(prop->getName(), prop->getIdent().c_str(), icon_path.c_str());
|
|
//std::cout << "Add item : " << prop->getIdent().c_str() << std::endl;
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
TODO: Ultimately, it'd be nice to *not* delete g_player_karts so that
|
|
when players return to the kart selection screen, it will appear as
|
|
it did when they left (at least when returning from the track menu).
|
|
Rebuilding the screen is a little tricky.
|
|
|
|
*/
|
|
|
|
if (g_player_karts.size() > 0)
|
|
{
|
|
// FIXME: trying to rebuild the screen
|
|
for (int n = 0; n < g_player_karts.size(); n++)
|
|
{
|
|
PlayerKartWidget *pkw;
|
|
pkw = g_player_karts.get(n);
|
|
this->manualAddWidget(pkw);
|
|
pkw->add();
|
|
}
|
|
|
|
}
|
|
else // For now this is what will happen
|
|
{
|
|
playerJoin( input_manager->getDeviceList()->getLatestUsedDevice(), true );
|
|
w->updateItemDisplay();
|
|
}
|
|
|
|
// Player 0 select first kart (Tux)
|
|
w->setSelection(0, 0);
|
|
w->m_rows[0].requestFocus();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
/**
|
|
* Callback handling events from the kart selection menu
|
|
*/
|
|
void KartSelectionScreen::eventCallback(Widget* widget, const std::string& name)
|
|
{
|
|
if (name == "kartgroups")
|
|
{
|
|
RibbonWidget* tabs = this->getWidget<RibbonWidget>("kartgroups");
|
|
assert(tabs != NULL);
|
|
|
|
std::string selection = tabs->getSelectionIDString(GUI_PLAYER_ID);
|
|
|
|
DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("karts");
|
|
w->clearItems();
|
|
|
|
// TODO : preserve selection of karts for all players
|
|
|
|
if (selection == "all")
|
|
{
|
|
const int kart_amount = kart_properties_manager->getNumberOfKarts();
|
|
|
|
for(int n=0; n<kart_amount; n++)
|
|
{
|
|
const KartProperties* prop = kart_properties_manager->getKartById(n);
|
|
|
|
std::string icon_path = file_manager->getDataDir() ;
|
|
icon_path += "/karts/" + prop->getIdent() + "/" + prop->getIconFile();
|
|
w->addItem(prop->getName().c_str(), prop->getIdent().c_str(), icon_path.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::vector<int> group = kart_properties_manager->getKartsInGroup(selection);
|
|
const int kart_amount = group.size();
|
|
|
|
for(int n=0; n<kart_amount; n++)
|
|
{
|
|
const KartProperties* prop = kart_properties_manager->getKartById(group[n]);
|
|
|
|
std::string icon_path = file_manager->getDataDir() ;
|
|
icon_path += "/karts/" + prop->getIdent() + "/" + prop->getIconFile();
|
|
w->addItem(prop->getName().c_str(), prop->getIdent().c_str(), icon_path.c_str());
|
|
}
|
|
}
|
|
|
|
w->updateItemDisplay();
|
|
|
|
}
|
|
else if (name == "karts")
|
|
{
|
|
DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("karts");
|
|
assert( w != NULL );
|
|
|
|
ptr_vector< ActivePlayer, HOLD >& players = StateManager::get()->getActivePlayers();
|
|
std::cout << "==========\n" << players.size() << " players :\n";
|
|
for(int n=0; n<players.size(); n++)
|
|
{
|
|
std::cout << " Player " << n << " is " << players[n].getProfile()->getName() << " on " << players[n].getDevice()->m_name << std::endl;
|
|
}
|
|
std::cout << "==========\n";
|
|
|
|
race_manager->setNumPlayers( players.size() );
|
|
race_manager->setNumLocalPlayers( players.size() );
|
|
|
|
RandomGenerator random;
|
|
|
|
//g_player_karts.clearAndDeleteAll();
|
|
//race_manager->setLocalKartInfo(0, w->getSelectionIDString());
|
|
for (int n = 0; n < g_player_karts.size(); n++)
|
|
{
|
|
std::string selection = g_player_karts[n].m_kartInternalName;
|
|
|
|
if (selection == "gui/track_random.png")
|
|
{
|
|
// FIXME: in multiplayer game, if two players select' random' make sure they don't select
|
|
// the same kart or an already selected kart
|
|
const std::vector<ItemDescription>& items = w->getItems();
|
|
const int randomID = random.get(items.size());
|
|
selection = items[randomID].m_code_name;
|
|
}
|
|
// std::cout << "selection=" << selection.c_str() << std::endl;
|
|
|
|
race_manager->setLocalKartInfo(n, selection);
|
|
}
|
|
|
|
//Return to assign mode
|
|
input_manager->getDeviceList()->setAssignMode(ASSIGN);
|
|
|
|
StateManager::get()->pushScreen( RaceSetupScreen::getInstance() );
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void KartSelectionScreen::renumberKarts()
|
|
{
|
|
DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("karts");
|
|
assert( w != NULL );
|
|
Widget* fullarea = this->getWidget("playerskarts");
|
|
const int splitWidth = fullarea->w / g_player_karts.size();
|
|
|
|
printf("Renumbering karts...");
|
|
for (int n=0; n < g_player_karts.size(); n++)
|
|
{
|
|
g_player_karts[n].setPlayerID(n);
|
|
g_player_karts[n].move( fullarea->x + splitWidth*n, fullarea->y, splitWidth, fullarea->h );
|
|
}
|
|
|
|
w->updateItemDisplay();
|
|
printf("OK\n");
|
|
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
// FIXME : clean this mess, this file should not contain so many classes
|
|
GUIEngine::EventPropagation PlayerNameSpinner::focused(const int playerID)
|
|
{
|
|
std::cout << "Player name spinner " << this->playerID << " focused by " << playerID << std::endl;
|
|
|
|
// since this screen is multiplayer, redirect focus to the right widget
|
|
if (this->playerID != playerID)
|
|
{
|
|
const int amount = g_player_karts.size();
|
|
for (int n=0; n<amount; n++)
|
|
{
|
|
if (g_player_karts[n].playerID == playerID)
|
|
{
|
|
std::cout << "--> Redirecting focus for player " << playerID << " from spinner " << this->playerID <<
|
|
" (ID " << m_element->getID() <<
|
|
") to spinner " << n << " (ID " << g_player_karts[n].playerName->m_element->getID() << ")" << std::endl;
|
|
int IDbefore = GUIEngine::getGUIEnv()->getFocus()->getID();
|
|
|
|
g_player_karts[n].playerName->setFocusForPlayer(playerID);
|
|
|
|
int IDafter = GUIEngine::getGUIEnv()->getFocus()->getID();
|
|
std::cout << "--> ID before : " << IDbefore << "; ID after : " << IDafter << std::endl;
|
|
|
|
return GUIEngine::EVENT_BLOCK;
|
|
}
|
|
}
|
|
assert(false);
|
|
}
|
|
|
|
std::cout << "--> right spinner nothing to do\n";
|
|
return GUIEngine::EVENT_LET;
|
|
} // focused
|
|
|