stk-code_catmod/src/states_screens/soccer_setup_screen.cpp

528 lines
18 KiB
C++

// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013-2015 Lionel Fuentes
//
// 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 "states_screens/soccer_setup_screen.hpp"
#include "audio/sfx_manager.hpp"
#include "config/user_config.hpp"
#include "graphics/render_info.hpp"
#include "guiengine/widgets/bubble_widget.hpp"
#include "guiengine/widgets/button_widget.hpp"
#include "guiengine/widgets/spinner_widget.hpp"
#include "guiengine/widgets/check_box_widget.hpp"
#include "guiengine/widgets/label_widget.hpp"
#include "guiengine/widgets/model_view_widget.hpp"
#include "guiengine/scalable_font.hpp"
#include "input/device_manager.hpp"
#include "input/input_manager.hpp"
#include "io/file_manager.hpp"
#include "karts/kart_model.hpp"
#include "karts/kart_properties.hpp"
#include "karts/kart_properties_manager.hpp"
#include "states_screens/arenas_screen.hpp"
#include "states_screens/state_manager.hpp"
using namespace GUIEngine;
#define KART_CONTINUOUS_ROTATION_SPEED 35.f
#define KART_CONFIRMATION_ROTATION_SPEED 4.f
#define KART_CONFIRMATION_TARGET_ANGLE 10.f
// -----------------------------------------------------------------------------
SoccerSetupScreen::SoccerSetupScreen() : Screen("soccer_setup.stkgui")
{
}
// -----------------------------------------------------------------------------
void SoccerSetupScreen::loadedFromFile()
{
}
// ----------------------------------------------------------------------------
void SoccerSetupScreen::eventCallback(Widget* widget, const std::string& name,
const int playerID)
{
if(m_schedule_continue)
return;
if(name == "continue")
{
int nb_players = (int)m_kart_view_info.size();
if(!areAllKartsConfirmed())
{
for(int i=0 ; i < nb_players ; i++)
{
if (!m_kart_view_info[i].confirmed)
{
m_kart_view_info[i].confirmed = true;
m_kart_view_info[i].view->setRotateTo( KART_CONFIRMATION_TARGET_ANGLE, KART_CONFIRMATION_ROTATION_SPEED );
m_kart_view_info[i].view->setBadge(OK_BADGE);
}
}
SFXManager::get()->quickSound( "wee" );
m_schedule_continue = true;
}
else
{
m_schedule_continue = true;
}
}
else if (name == "back")
{
StateManager::get()->escapePressed();
}
else if(name == "time_enabled")
{
CheckBoxWidget* timeEnabled = dynamic_cast<CheckBoxWidget*>(widget);
bool timed = timeEnabled->getState();
UserConfigParams::m_soccer_use_time_limit = timed;
getWidget<SpinnerWidget>("goalamount")->setActive(!timed);
getWidget<SpinnerWidget>("timeamount")->setActive(timed);
}
else if (name == "red_team")
{
if (m_kart_view_info.size() == 1)
{
changeTeam(0, SOCCER_TEAM_RED);
}
}
else if (name == "blue_team")
{
if (m_kart_view_info.size() == 1)
{
changeTeam(0, SOCCER_TEAM_BLUE);
}
}
} // eventCallback
// -----------------------------------------------------------------------------
void SoccerSetupScreen::beforeAddingWidget()
{
Widget* central_div = getWidget<Widget>("central_div");
// Add red/blue team icon above the karts
IconButtonWidget* red = getWidget<IconButtonWidget>("red_team");
IconButtonWidget* blue = getWidget<IconButtonWidget>("blue_team");
red->m_x = central_div->m_x + central_div->m_w/4;
red->m_y = central_div->m_y + red->m_h;
blue->m_x = central_div->m_x + (central_div->m_w/4)*3;
blue->m_y = central_div->m_y + blue->m_h;
// Add the 3D views for the karts
int nb_players = race_manager->getNumPlayers();
for(int i=0 ; i < nb_players ; i++)
{
const RemoteKartInfo& kart_info = race_manager->getKartInfo(i);
const std::string& kart_name = kart_info.getKartName();
const KartProperties* props = kart_properties_manager->getKart(kart_name);
const KartModel& kart_model = props->getMasterKartModel();
// Add the view
ModelViewWidget* kart_view = new ModelViewWidget();
// These values will be overriden by updateKartViewsLayout() anyway
kart_view->m_x = 0;
kart_view->m_y = 0;
kart_view->m_w = 200;
kart_view->m_h = 200;
kart_view->clearModels();
// Record info about it for further update
KartViewInfo info;
int single_team = UserConfigParams::m_soccer_default_team;
info.team = (nb_players == 1 ? (SoccerTeam)single_team :
(i&1 ? SOCCER_TEAM_BLUE : SOCCER_TEAM_RED));
// addModel requires loading the RenderInfo first
info.support_colorization = kart_model.supportColorization();
if (info.support_colorization)
{
kart_view->getModelViewRenderInfo()->setHue
(info.team == SOCCER_TEAM_BLUE ? 0.66f : 1.0f);
}
core::matrix4 model_location;
model_location.setScale(core::vector3df(35.0f, 35.0f, 35.0f));
// Add the kart model (including wheels and speed weight objects)
kart_view->addModel(kart_model.getModel(), model_location,
kart_model.getBaseFrame(), kart_model.getBaseFrame());
model_location.setScale(core::vector3df(1.0f, 1.0f, 1.0f));
for (unsigned i = 0; i < 4; i++)
{
model_location.setTranslation(kart_model
.getWheelGraphicsPosition(i).toIrrVector());
kart_view->addModel(kart_model.getWheelModel(i), model_location);
}
for (unsigned i = 0; i < kart_model.getSpeedWeightedObjectsCount();
i++)
{
const SpeedWeightedObject& obj =
kart_model.getSpeedWeightedObject(i);
core::matrix4 swol = obj.m_location;
if (!obj.m_bone_name.empty())
{
core::matrix4 inv =
kart_model.getInverseBoneMatrix(obj.m_bone_name);
swol = inv * obj.m_location;
}
kart_view->addModel(obj.m_model, swol, -1, -1, 0.0f,
obj.m_bone_name);
}
kart_view->setRotateContinuously( KART_CONTINUOUS_ROTATION_SPEED );
kart_view->update(0);
central_div->getChildren().push_back(kart_view);
info.view = kart_view;
info.confirmed = false;
m_kart_view_info.push_back(info);
race_manager->setKartSoccerTeam(i, info.team);
}
// Update layout
updateKartViewsLayout();
} // beforeAddingWidget
// -----------------------------------------------------------------------------
void SoccerSetupScreen::init()
{
m_schedule_continue = false;
Screen::init();
if (UserConfigParams::m_num_goals <= 0)
UserConfigParams::m_num_goals = 3;
if (UserConfigParams::m_soccer_time_limit <= 0)
UserConfigParams::m_soccer_time_limit = 3;
SpinnerWidget* goalamount = getWidget<SpinnerWidget>("goalamount");
goalamount->setValue(UserConfigParams::m_num_goals);
goalamount->setActive(!UserConfigParams::m_soccer_use_time_limit);
SpinnerWidget* timeAmount = getWidget<SpinnerWidget>("timeamount");
timeAmount->setValue(UserConfigParams::m_soccer_time_limit);
timeAmount->setActive(UserConfigParams::m_soccer_use_time_limit);
CheckBoxWidget* timeEnabled = getWidget<CheckBoxWidget>("time_enabled");
timeEnabled->setState(UserConfigParams::m_soccer_use_time_limit);
// Set focus on "continue"
ButtonWidget* bt_continue = getWidget<ButtonWidget>("continue");
bt_continue->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
// We need players to be able to choose their teams
input_manager->setMasterPlayerOnly(false);
// This flag will cause that a 'fire' event will be mapped to 'select' (if
// 'fire' is not assigned to a GUI event). This is done to support the old
// way of player joining by pressing 'fire' instead of 'select'.
input_manager->getDeviceManager()->mapFireToSelect(true);
} // init
// -----------------------------------------------------------------------------
void SoccerSetupScreen::tearDown()
{
Widget* central_div = getWidget<Widget>("central_div");
// Reset the 'map fire to select' option of the device manager
input_manager->getDeviceManager()->mapFireToSelect(false);
UserConfigParams::m_num_goals = getWidget<SpinnerWidget>("goalamount")->getValue();
UserConfigParams::m_soccer_time_limit = getWidget<SpinnerWidget>("timeamount")->getValue();
// Remove all ModelViewWidgets we created manually
PtrVector<Widget>& children = central_div->getChildren();
for(int i = children.size()-1 ; i >= 0 ; i--)
{
if(children[i].getType() == WTYPE_MODEL_VIEW)
children.erase(i);
}
m_kart_view_info.clear();
Screen::tearDown();
} // tearDown
void SoccerSetupScreen::changeTeam(int player_id, SoccerTeam team)
{
if (team == SOCCER_TEAM_NONE)
return;
if (team == m_kart_view_info[player_id].team)
return;
// Change the kart color
if (m_kart_view_info[player_id].support_colorization)
{
const float hue = team == SOCCER_TEAM_RED ? 1.0f : 0.66f;
m_kart_view_info[player_id].view->getModelViewRenderInfo()
->setHue(hue);
}
for (unsigned int i = 0; i < m_kart_view_info.size(); i++)
{
m_kart_view_info[i].view->unsetBadge(BAD_BADGE);
}
if (m_kart_view_info.size() == 1)
{
UserConfigParams::m_soccer_default_team = (int)team;
}
race_manager->setKartSoccerTeam(player_id, team);
m_kart_view_info[player_id].team = team;
updateKartViewsLayout();
}
// -----------------------------------------------------------------------------
GUIEngine::EventPropagation SoccerSetupScreen::filterActions(PlayerAction action,
int deviceID,
const unsigned int value,
Input::InputType type,
int playerId)
{
if(m_schedule_continue)
return EVENT_BLOCK;
const bool pressed_down = value > Input::MAX_VALUE*2/3;
if (!pressed_down)
return EVENT_BLOCK;
ButtonWidget* bt_continue = getWidget<ButtonWidget>("continue");
BubbleWidget* bubble = getWidget<BubbleWidget>("lblLeftRight");
switch (action)
{
case PA_MENU_LEFT:
if (bt_continue->isFocusedForPlayer(PLAYER_ID_GAME_MASTER) ||
bubble->isFocusedForPlayer(PLAYER_ID_GAME_MASTER))
{
if (m_kart_view_info[playerId].confirmed == false)
changeTeam(playerId, SOCCER_TEAM_RED);
return EVENT_BLOCK;
}
break;
case PA_MENU_RIGHT:
if (bt_continue->isFocusedForPlayer(PLAYER_ID_GAME_MASTER) ||
bubble->isFocusedForPlayer(PLAYER_ID_GAME_MASTER))
{
if (m_kart_view_info[playerId].confirmed == false)
changeTeam(playerId, SOCCER_TEAM_BLUE);
return EVENT_BLOCK;
}
break;
case PA_MENU_UP:
if (playerId != PLAYER_ID_GAME_MASTER)
return EVENT_BLOCK;
break;
case PA_MENU_DOWN:
if (playerId != PLAYER_ID_GAME_MASTER)
return EVENT_BLOCK;
break;
case PA_MENU_SELECT:
{
if (!bt_continue->isFocusedForPlayer(PLAYER_ID_GAME_MASTER) &&
!bubble->isFocusedForPlayer(PLAYER_ID_GAME_MASTER) &&
playerId == PLAYER_ID_GAME_MASTER)
{
return EVENT_LET;
}
if (!m_kart_view_info[playerId].confirmed)
{
// Confirm team selection
m_kart_view_info[playerId].confirmed = true;
m_kart_view_info[playerId].view->setRotateTo(
KART_CONFIRMATION_TARGET_ANGLE,
KART_CONFIRMATION_ROTATION_SPEED);
m_kart_view_info[playerId].view->setBadge(OK_BADGE);
m_kart_view_info[playerId].view->unsetBadge(BAD_BADGE);
SFXManager::get()->quickSound( "wee" );
}
if (areAllKartsConfirmed())
m_schedule_continue = true;
return EVENT_BLOCK;
}
case PA_MENU_CANCEL:
{
if (!bt_continue->isFocusedForPlayer(PLAYER_ID_GAME_MASTER) &&
!bubble->isFocusedForPlayer(PLAYER_ID_GAME_MASTER) &&
playerId == PLAYER_ID_GAME_MASTER)
{
return EVENT_LET;
}
if ((!m_kart_view_info[playerId].confirmed) &&
(playerId == PLAYER_ID_GAME_MASTER))
{
return EVENT_LET;
}
if (m_kart_view_info[playerId].confirmed)
{
// Un-confirm team selection
m_kart_view_info[playerId].confirmed = false;
m_kart_view_info[playerId].view->setRotateContinuously(
KART_CONTINUOUS_ROTATION_SPEED);
m_kart_view_info[playerId].view->unsetBadge(OK_BADGE);
for (unsigned int i = 0; i < m_kart_view_info.size(); i++)
{
m_kart_view_info[i].view->unsetBadge(BAD_BADGE);
}
}
return EVENT_BLOCK;
}
default:
break;
}
return EVENT_LET;
} // filterActions
// -----------------------------------------------------------------------------
void SoccerSetupScreen::onUpdate(float delta)
{
int nb_players = (int)m_kart_view_info.size();
if(m_schedule_continue)
{
for(int i=0 ; i < nb_players ; i++)
{
if (m_kart_view_info[i].view->isRotating() == true)
return;
}
m_schedule_continue = false;
prepareGame();
ArenasScreen::getInstance()->push();
}
} // onUpdate
// ----------------------------------------------------------------------------
bool SoccerSetupScreen::areAllKartsConfirmed() const
{
bool all_confirmed = true;
int nb_players = (int)m_kart_view_info.size();
for(int i=0 ; i < nb_players ; i++)
{
if(!m_kart_view_info[i].confirmed)
{
all_confirmed = false;
break;
}
}
return all_confirmed;
} // areAllKartsConfirmed
// -----------------------------------------------------------------------------
int SoccerSetupScreen::getNumConfirmedKarts()
{
int confirmed_karts = 0;
int nb_players = (int)m_kart_view_info.size();
for(int i=0 ; i < nb_players ; i++)
{
if(m_kart_view_info[i].confirmed == true)
confirmed_karts++;
}
return confirmed_karts;
}
// -----------------------------------------------------------------------------
void SoccerSetupScreen::updateKartViewsLayout()
{
Widget* central_div = getWidget<Widget>("central_div");
// Compute/get some dimensions
const int nb_columns = 2; // two karts maximum per column
const int kart_area_width = (central_div->m_w) / 2; // size of one half of the screen
const int kart_view_size = kart_area_width/nb_columns; // Size (width and height) of a kart view
const int center_x = central_div->m_x + central_div->m_w/2;
const int center_y = central_div->m_y + central_div->m_h/2;
// Count the number of karts per team
int nb_players = (int)m_kart_view_info.size();
int nb_karts_per_team[2] = {0,0};
for(int i=0 ; i < nb_players ; i++)
nb_karts_per_team[m_kart_view_info[i].team]++;
// - number of rows displayed for each team = ceil(nb_karts_per_team[i] / nb_columns)
const int nb_rows_per_team[2] = { (nb_karts_per_team[0] + nb_columns - 1) / nb_columns,
(nb_karts_per_team[1] + nb_columns - 1) / nb_columns};
// - where to start vertically
const int start_y[2] = {center_y - nb_rows_per_team[0] * kart_view_size / 2,
center_y - nb_rows_per_team[1] * kart_view_size / 2};
// - center of each half-screen
const int center_x_per_team[2] = { ( central_div->m_x + center_x ) / 2,
( central_div->m_x+central_div->m_w + center_x ) / 2,
};
// Update the layout of the 3D views for the karts
int cur_kart_per_team[2] = {0,0}; // counters
for(int i=0 ; i < nb_players ; i++)
{
const KartViewInfo& view_info = m_kart_view_info[i];
const SoccerTeam team = view_info.team;
// Compute the position
const int cur_row = cur_kart_per_team[team] / nb_columns;
const int pos_y = start_y[team] + cur_row*kart_view_size;
const int cur_col = cur_kart_per_team[team] % nb_columns;
int nb_karts_in_this_row = (nb_karts_per_team[team] - cur_row*nb_columns) % nb_columns;
if(nb_karts_in_this_row == 0 || nb_karts_per_team[team] > 1)
nb_karts_in_this_row = nb_columns; // TODO: not sure of the computation here...
const int pos_x = center_x_per_team[team] + cur_col*kart_view_size - nb_karts_in_this_row*kart_view_size/2;
cur_kart_per_team[team]++;
// Move the view
view_info.view->move(pos_x, pos_y, kart_view_size, kart_view_size);
}
} // updateKartViewsLayout
// -----------------------------------------------------------------------------
bool SoccerSetupScreen::onEscapePressed()
{
race_manager->setTimeTarget(0.0f);
return true;
} // onEscapePressed
// -----------------------------------------------------------------------------
void SoccerSetupScreen::prepareGame()
{
if (getWidget<SpinnerWidget>("goalamount")->isActivated())
race_manager->setMaxGoal(getWidget<SpinnerWidget>("goalamount")->getValue());
else
race_manager->setTimeTarget((float)getWidget<SpinnerWidget>("timeamount")->getValue() * 60);
input_manager->setMasterPlayerOnly(true);
} // prepareGame