Switch per player difficulty to player config

This commit is contained in:
Flakebi 2014-09-02 01:18:58 +02:00
parent 70ad37aeb7
commit e2089fcea6
17 changed files with 141 additions and 54 deletions

View File

@ -10,8 +10,6 @@
<placeholder id="playerskarts" width="100%" align="center" proportion="4"> <placeholder id="playerskarts" width="100%" align="center" proportion="4">
<!-- Contents is added programatically --> <!-- Contents is added programatically -->
</placeholder> </placeholder>
<placeholder id="perPlayerDifficulty" width="100%" align="center" proportion="0">
</placeholder>
<spacer height="15" width="25"/> <spacer height="15" width="25"/>

View File

@ -16,7 +16,7 @@
<div width="80%" align="center" layout="vertical-row" height="fit"> <div width="80%" align="center" layout="vertical-row" height="fit">
<div width="100%" height="fit" layout="horizontal-row" > <div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the user screen" text="Multiplayer Boost/Handicap"/> <label proportion="1" height="100%" text_align="left" I18N="In the user screen" text="Multiplayer Boost/Handicap"/>
<gauge id="difficulty" min_value="1" max_value="5" width="300" align="center" /> <gauge id="difficulty" min_value="0" max_value="4" width="300" align="center" />
</div> </div>
<div width="100%" height="fit" layout="horizontal-row" > <div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the user screen" text="Apply Boost/Handicap in singleplayer too"/> <label proportion="1" height="100%" text_align="left" I18N="In the user screen" text="Apply Boost/Handicap in singleplayer too"/>

View File

@ -25,7 +25,7 @@
<div width="80%" align="center" layout="vertical-row" height="fit"> <div width="80%" align="center" layout="vertical-row" height="fit">
<div width="100%" height="fit" layout="horizontal-row" > <div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the user screen" text="Multiplayer Boost/Handicap"/> <label proportion="1" height="100%" text_align="left" I18N="In the user screen" text="Multiplayer Boost/Handicap"/>
<gauge id="difficulty" min_value="1" max_value="5" width="300" align="center" /> <gauge id="difficulty" min_value="0" max_value="4" width="300" align="center" />
</div> </div>
<div width="100%" height="fit" layout="horizontal-row" > <div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the user screen" text="Apply Boost/Handicap in singleplayer too"/> <label proportion="1" height="100%" text_align="left" I18N="In the user screen" text="Apply Boost/Handicap in singleplayer too"/>

View File

@ -338,7 +338,9 @@
</ai> </ai>
<!-- The per-player difficulties in multiplayer games. <!-- The per-player difficulties in multiplayer games.
These values are multiplied with the current values of a car. --> These values are multiplied with the current values of a car
so 1 means that nothing changes.
The meaning of the different values is explained below this tag. -->
<difficulties> <difficulties>
<easiest> <easiest>
<mass value="1.0"/> <mass value="1.0"/>

View File

@ -41,6 +41,8 @@ PlayerProfile::PlayerProfile(const core::stringw& name, bool is_guest)
m_local_name = name; m_local_name = name;
m_is_guest_account = is_guest; m_is_guest_account = is_guest;
m_use_frequency = is_guest ? -1 : 0; m_use_frequency = is_guest ? -1 : 0;
m_difficulty = PLAYER_DIFFICULTY_NORMAL;
m_singleplayer_difficulty = false;
m_unique_id = PlayerManager::get()->getUniqueId(); m_unique_id = PlayerManager::get()->getUniqueId();
m_saved_session = false; m_saved_session = false;
m_saved_token = ""; m_saved_token = "";
@ -68,6 +70,8 @@ PlayerProfile::PlayerProfile(const core::stringw& name, bool is_guest)
*/ */
PlayerProfile::PlayerProfile(const XMLNode* node) PlayerProfile::PlayerProfile(const XMLNode* node)
{ {
m_difficulty = PLAYER_DIFFICULTY_NORMAL;
m_singleplayer_difficulty = false;
m_saved_session = false; m_saved_session = false;
m_saved_token = ""; m_saved_token = "";
m_saved_user_id = 0; m_saved_user_id = 0;
@ -81,6 +85,8 @@ PlayerProfile::PlayerProfile(const XMLNode* node)
node->get("name", &m_local_name ); node->get("name", &m_local_name );
node->get("guest", &m_is_guest_account ); node->get("guest", &m_is_guest_account );
node->get("use-frequency", &m_use_frequency ); node->get("use-frequency", &m_use_frequency );
node->get("difficulty", (int*) &m_difficulty);
node->get("singleplayer-difficulty", &m_singleplayer_difficulty);
node->get("unique-id", &m_unique_id ); node->get("unique-id", &m_unique_id );
node->get("saved-session", &m_saved_session ); node->get("saved-session", &m_saved_session );
node->get("saved-user", &m_saved_user_id ); node->get("saved-user", &m_saved_user_id );
@ -198,7 +204,10 @@ void PlayerProfile::save(UTFWriter &out)
<< L"\" guest=\"" << m_is_guest_account << L"\" guest=\"" << m_is_guest_account
<< L"\" use-frequency=\"" << m_use_frequency << L"\"\n"; << L"\" use-frequency=\"" << m_use_frequency << L"\"\n";
out << L" icon-filename=\"" << m_icon_filename <<L"\"\n"; out << L" icon-filename=\"" << m_icon_filename << L"\"\n";
out << L" difficulty=\"" << m_difficulty
<< L"\" singleplayer-difficulty=\"" << m_singleplayer_difficulty << L"\"\n";
out << L" unique-id=\"" << m_unique_id out << L" unique-id=\"" << m_unique_id
<< L"\" saved-session=\"" << m_saved_session << L"\"\n"; << L"\" saved-session=\"" << m_saved_session << L"\"\n";

View File

@ -20,6 +20,7 @@
#define HEADER_PLAYER_PROFILE_HPP #define HEADER_PLAYER_PROFILE_HPP
#include "challenges/story_mode_status.hpp" #include "challenges/story_mode_status.hpp"
#include "network/remote_kart_info.hpp"
#include "utils/leak_check.hpp" #include "utils/leak_check.hpp"
#include "utils/no_copy.hpp" #include "utils/no_copy.hpp"
#include "utils/types.hpp" #include "utils/types.hpp"
@ -66,6 +67,10 @@ public:
private: private:
LEAK_CHECK() LEAK_CHECK()
#ifdef DEBUG
unsigned int m_magic_number;
#endif
/** The name of the player (wide string, so it can be in native /** The name of the player (wide string, so it can be in native
* language). */ * language). */
core::stringw m_local_name; core::stringw m_local_name;
@ -73,10 +78,6 @@ private:
/** True if this account is a guest account. */ /** True if this account is a guest account. */
bool m_is_guest_account; bool m_is_guest_account;
#ifdef DEBUG
unsigned int m_magic_number;
#endif
/** Counts how often this player was used (always -1 for guests). */ /** Counts how often this player was used (always -1 for guests). */
int m_use_frequency; int m_use_frequency;
@ -86,6 +87,13 @@ private:
/** Absolute path of the icon file for this player. */ /** Absolute path of the icon file for this player. */
std::string m_icon_filename; std::string m_icon_filename;
/** The difficulty (boost or handicap) for this player. */
PerPlayerDifficulty m_difficulty;
/** If the per player difficulty should be applied for singleplayer games.
Story mode is excluded to prevent cheating. */
bool m_singleplayer_difficulty;
/** True if this user has a saved session. */ /** True if this user has a saved session. */
bool m_saved_session; bool m_saved_session;
@ -111,8 +119,8 @@ private:
public: public:
PlayerProfile(const core::stringw &name, bool is_guest = false); PlayerProfile(const core::stringw &name, bool is_guest = false);
PlayerProfile(const XMLNode *node); PlayerProfile(const XMLNode *node);
virtual ~PlayerProfile(); virtual ~PlayerProfile();
void save(UTFWriter &out); void save(UTFWriter &out);
void loadRemainingData(const XMLNode *node); void loadRemainingData(const XMLNode *node);
@ -159,6 +167,42 @@ public:
return m_local_name.c_str(); return m_local_name.c_str();
} // getName } // getName
// ------------------------------------------------------------------------
/** Sets the per player difficulty for this player. */
void setDifficulty(const PerPlayerDifficulty difficulty)
{
#ifdef DEBUG
assert(m_magic_number == 0xABCD1234);
#endif
m_difficulty = difficulty;
} // setDifficulty
// ------------------------------------------------------------------------
/** Returns the per player difficulty of this player. */
PerPlayerDifficulty getDifficulty() const
{
assert(m_magic_number == 0xABCD1234);
return m_difficulty;
} // getDifficulty
// ------------------------------------------------------------------------
/** Sets the singleplayer difficulty for this player. */
void setSingleplayerDifficulty(const bool singleplayer_difficulty)
{
#ifdef DEBUG
assert(m_magic_number == 0xABCD1234);
#endif
m_singleplayer_difficulty = singleplayer_difficulty;
} // setSingleplayerDifficulty
// ------------------------------------------------------------------------
/** Returns the per player difficulty of this player. */
bool isSingleplayerDifficulty() const
{
assert(m_magic_number == 0xABCD1234);
return m_singleplayer_difficulty;
} // getDifficulty
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns true if this player is a guest account. */ /** Returns true if this player is a guest account. */
bool isGuestAccount() const bool isGuestAccount() const

View File

@ -2082,6 +2082,20 @@ void Skin::drawBadgeOn(const Widget* widget, const core::recti& rect)
"hourglass.png"); "hourglass.png");
doDrawBadge(texture, rect, max_icon_size, true); doDrawBadge(texture, rect, max_icon_size, true);
} }
if (widget->m_badges & ZIPPER_BADGE)
{
float max_icon_size = 0.43f;
video::ITexture* texture = irr_driver->getTexture(FileManager::MODEL,
"zipper_collect.png");
doDrawBadge(texture, rect, max_icon_size, false);
}
if (widget->m_badges & ANCHOR_BADGE)
{
float max_icon_size = 0.43f;
video::ITexture* texture = irr_driver->getTexture(FileManager::MODEL,
"anchor-icon.png");
doDrawBadge(texture, rect, max_icon_size, false);
}
} // drawBadgeOn } // drawBadgeOn
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -60,19 +60,23 @@ namespace GUIEngine
enum BadgeType enum BadgeType
{ {
/** display a lock on the widget, to mean a certain game feature is locked */ /** display a lock on the widget, to mean a certain game feature is locked */
LOCKED_BADGE = 1, LOCKED_BADGE = 1,
/** display a green check on a widget, useful e.g. to display confirmation */ /** display a green check on a widget, useful e.g. to display confirmation */
OK_BADGE = 2, OK_BADGE = 1 << 1,
/** display a red mark badge on the widget, useful e.g. to warn of an invalid choice */ /** display a red mark badge on the widget, useful e.g. to warn of an invalid choice */
BAD_BADGE = 4, BAD_BADGE = 1 << 2,
/** display a trophy badge on the widget, useful e.g. for challenges */ /** display a trophy badge on the widget, useful e.g. for challenges */
TROPHY_BADGE = 8, TROPHY_BADGE = 1 << 3,
/** A gamepad icon */ /** A gamepad icon */
GAMEPAD_BADGE = 16, GAMEPAD_BADGE = 1 << 4,
/** A keyboard icon */ /** A keyboard icon */
KEYBOARD_BADGE = 32, KEYBOARD_BADGE = 1 << 5,
/** An hourglass badge to indicate loading */ /** An hourglass badge to indicate loading */
LOADING_BADGE = 64 LOADING_BADGE = 1 << 6,
/** A zipper badge to indicate that this player receives a boost */
ZIPPER_BADGE = 1 << 7,
/** A anchor badge to indicate that this player receives a handicap */
ANCHOR_BADGE = 1 << 8
}; };

View File

@ -53,7 +53,6 @@ namespace GUIEngine
int model_x, model_y, model_w, model_h; int model_x, model_y, model_w, model_h;
int kart_name_x, kart_name_y, kart_name_w, kart_name_h; int kart_name_x, kart_name_y, kart_name_w, kart_name_h;
int m_kart_stats_x, m_kart_stats_y, m_kart_stats_w, m_kart_stats_h; int m_kart_stats_x, m_kart_stats_y, m_kart_stats_w, m_kart_stats_h;
int m_difficulty_x, m_difficulty_y, m_difficulty_w, m_difficulty_h;
/** A reserved ID for this widget if any, -1 otherwise. (If no ID is /** A reserved ID for this widget if any, -1 otherwise. (If no ID is
* reserved, widget will not be in the regular tabbing order */ * reserved, widget will not be in the regular tabbing order */
@ -85,7 +84,6 @@ namespace GUIEngine
/** Sub-widgets created by this widget */ /** Sub-widgets created by this widget */
PlayerNameSpinner* m_player_ident_spinner; PlayerNameSpinner* m_player_ident_spinner;
SpinnerWidget* m_difficulty;
KartStatsWidget* m_kart_stats; KartStatsWidget* m_kart_stats;
ModelViewWidget* m_model_view; ModelViewWidget* m_model_view;
LabelWidget* m_kart_name; LabelWidget* m_kart_name;

View File

@ -25,7 +25,7 @@
GhostKart::GhostKart(const std::string& ident) GhostKart::GhostKart(const std::string& ident)
: Kart(ident, /*world kart id*/99999, : Kart(ident, /*world kart id*/99999,
/*position*/-1, btTransform(), stk_config->getPlayerDifficulty( /*position*/-1, btTransform(), stk_config->getPlayerDifficulty(
PLAYER_DIFFICULTY_NORMAL)) //TODO Ghost races PerPlayerDifficulty PLAYER_DIFFICULTY_NORMAL))
{ {
m_current_transform = 0; m_current_transform = 0;
m_next_event = 0; m_next_event = 0;

View File

@ -26,7 +26,7 @@
#include "utils/log.hpp" #include "utils/log.hpp"
/** /**
* The constructor initialises all values with default values (mostly 1). * The constructor initialises all values with default values.
*/ */
PlayerDifficulty::PlayerDifficulty(const std::string &filename) PlayerDifficulty::PlayerDifficulty(const std::string &filename)
{ {

View File

@ -27,12 +27,10 @@
class XMLNode; class XMLNode;
/** /**
* \brief This class stores the properties of a kart. * \brief This class stores values that modify the properties of a kart.
* This includes size, name, identifier, physical properties etc. * This includes physical properties like speed and the effect of items.
* It is atm also the base class for STKConfig, which stores the default values * The values stored in this class get multiplied with the current
* for all physics constants. * properties of the kart. If all values here are set to 1, nothing changes.
* Note that KartProperies is copied (when setting the default values from
* stk_config.
* *
* \ingroup karts * \ingroup karts
*/ */
@ -161,8 +159,8 @@ private:
public: public:
PlayerDifficulty (const std::string &filename=""); PlayerDifficulty (const std::string &filename="");
~PlayerDifficulty (); ~PlayerDifficulty ();
void getAllData (const XMLNode * root); void getAllData (const XMLNode * root);
std::string getIdent() const; std::string getIdent() const;
float getStartupBoost () const; float getStartupBoost () const;

View File

@ -307,7 +307,8 @@ void RaceManager::startNew(bool from_overworld)
// Create the kart status data structure to keep track of scores, times, ... // Create the kart status data structure to keep track of scores, times, ...
// ========================================================================== // ==========================================================================
m_kart_status.clear(); m_kart_status.clear();
Log::verbose("RaceManager", "Nb of karts=%u, ai:%lu players:%lu\n", (unsigned int)m_num_karts, m_ai_kart_list.size(), m_player_karts.size()); Log::verbose("RaceManager", "Nb of karts=%u, ai:%lu players:%lu\n",
(unsigned int) m_num_karts, m_ai_kart_list.size(), m_player_karts.size());
assert((unsigned int)m_num_karts == m_ai_kart_list.size()+m_player_karts.size()); assert((unsigned int)m_num_karts == m_ai_kart_list.size()+m_player_karts.size());
// First add the AI karts (randomly chosen) // First add the AI karts (randomly chosen)

View File

@ -507,6 +507,16 @@ bool KartSelectionScreen::joinPlayer(InputDevice* device, bool first_player)
newPlayerWidget->add(); newPlayerWidget->add();
// Add badge for per player difficulty if necessary
if (!m_from_overworld && (m_multiplayer || !profile_to_use->isSingleplayerDifficulty()))
{
PerPlayerDifficulty difficulty = profile_to_use->getDifficulty();
if (difficulty < PLAYER_DIFFICULTY_NORMAL)
m_kart_widgets[new_player_id].m_model_view->setBadge(ZIPPER_BADGE);
else if (difficulty > PLAYER_DIFFICULTY_NORMAL)
m_kart_widgets[new_player_id].m_model_view->setBadge(ANCHOR_BADGE);
}
// ---- Divide screen space among all karts // ---- Divide screen space among all karts
const int amount = m_kart_widgets.size(); const int amount = m_kart_widgets.size();
Widget* fullarea = getWidget("playerskarts"); Widget* fullarea = getWidget("playerskarts");
@ -1179,6 +1189,10 @@ void KartSelectionScreen::allPlayersDone()
// std::cout << "selection=" << selection.c_str() << std::endl; // std::cout << "selection=" << selection.c_str() << std::endl;
race_manager->setLocalKartInfo(n, selected_kart); race_manager->setLocalKartInfo(n, selected_kart);
// Set per player difficulty if needed
const PlayerProfile* profile = StateManager::get()->getActivePlayerProfile(n);
if (!m_from_overworld && (m_multiplayer || !profile->isSingleplayerDifficulty()))
race_manager->setPlayerDifficulty(n, profile->getDifficulty());
} }
// ---- Switch to assign mode // ---- Switch to assign mode

View File

@ -48,7 +48,6 @@ class KartSelectionScreen : public GUIEngine::Screen
friend class KartHoverListener; friend class KartHoverListener;
friend class PlayerNameSpinner; friend class PlayerNameSpinner;
friend class FocusDispatcher; friend class FocusDispatcher;
friend class FocusDispatcher2;
protected: protected:
/** Contains the custom widget shown for every player. (ref only since /** Contains the custom widget shown for every player. (ref only since
* we're adding them to a Screen, and the Screen will take ownership * we're adding them to a Screen, and the Screen will take ownership
@ -196,14 +195,6 @@ public:
virtual GUIEngine::EventPropagation focused(const int playerID); virtual GUIEngine::EventPropagation focused(const int playerID);
}; // FocusDispatcher }; // FocusDispatcher
class FocusDispatcher2 : public FocusDispatcher
{
public:
FocusDispatcher2(KartSelectionScreen *parent);
virtual GUIEngine::EventPropagation focused(const int playerID);
};
//!---------------------------------------------------------------------------- //!----------------------------------------------------------------------------
//! KartHoverListener : //! KartHoverListener :
class KartHoverListener : public GUIEngine::DynamicRibbonHoverListener class KartHoverListener : public GUIEngine::DynamicRibbonHoverListener

View File

@ -59,6 +59,17 @@ void BaseUserScreen::loadedFromFile()
void BaseUserScreen::init() void BaseUserScreen::init()
{ {
m_difficulty = getWidget<SpinnerWidget>("difficulty");
assert(m_difficulty);
m_difficulty->clearLabels();
m_difficulty->addLabel(_("Big boost"));
m_difficulty->addLabel(_("Boost"));
m_difficulty->addLabel(_("Normal"));
m_difficulty->addLabel(_("Handicap"));
m_difficulty->addLabel(_("Big handicap"));
m_singleplayer_difficulty = getWidget<CheckBoxWidget>("singleplayer-difficulty");
assert(m_singleplayer_difficulty);
m_online_cb = getWidget<CheckBoxWidget>("online"); m_online_cb = getWidget<CheckBoxWidget>("online");
assert(m_online_cb); assert(m_online_cb);
m_username_tb = getWidget<TextBoxWidget >("username"); m_username_tb = getWidget<TextBoxWidget >("username");
@ -155,23 +166,15 @@ void BaseUserScreen::selectUser(int index)
m_players->setSelection(StringUtils::toString(index), PLAYER_ID_GAME_MASTER, m_players->setSelection(StringUtils::toString(index), PLAYER_ID_GAME_MASTER,
/*focusIt*/ true); /*focusIt*/ true);
// Last game was not online, so make the offline settings the default // Display the saved data if the user was online last time and change the visibility
// (i.e. unckeck online checkbox, and make entry fields invisible). m_difficulty->setValue(profile->getDifficulty());
m_singleplayer_difficulty->setState(profile->isSingleplayerDifficulty());
if (!profile->wasOnlineLastTime() || profile->getLastOnlineName() == "") m_online_cb->setState(profile->wasOnlineLastTime() && profile->getLastOnlineName().size() > 0);
{
m_online_cb->setState(false);
makeEntryFieldsVisible();
return;
}
// Now last use was with online --> Display the saved data
m_online_cb->setState(true);
makeEntryFieldsVisible(); makeEntryFieldsVisible();
m_username_tb->setText(profile->getLastOnlineName()); m_username_tb->setText(profile->getLastOnlineName());
getWidget<CheckBoxWidget>("remember-user")->setState( getWidget<CheckBoxWidget>("remember-user")->setState(
profile->rememberPassword()); profile->rememberPassword());
if(profile->getLastOnlineName().size()>0) if(profile->getLastOnlineName().size() > 0)
m_username_tb->setDeactivated(); m_username_tb->setDeactivated();
else else
m_username_tb->setActivated(); m_username_tb->setActivated();
@ -353,6 +356,10 @@ void BaseUserScreen::login()
PlayerManager::get()->setCurrentPlayer(player); PlayerManager::get()->setCurrentPlayer(player);
assert(player); assert(player);
// Save difficulty
player->setDifficulty((PerPlayerDifficulty) m_difficulty->getValue());
player->setSingleplayerDifficulty(m_singleplayer_difficulty->getState());
// If no online login requested, log the player out (if necessary) // If no online login requested, log the player out (if necessary)
// and go to the main menu screen (though logout needs to finish first) // and go to the main menu screen (though logout needs to finish first)
if(!m_online_cb->getState()) if(!m_online_cb->getState())

View File

@ -22,6 +22,7 @@
#include <string> #include <string>
#include "guiengine/screen.hpp" #include "guiengine/screen.hpp"
#include "guiengine/widgets/spinner_widget.hpp"
namespace GUIEngine namespace GUIEngine
{ {
@ -64,6 +65,12 @@ private:
* display more meaningful sign-out message. */ * display more meaningful sign-out message. */
irr::core::stringw m_sign_in_name; irr::core::stringw m_sign_in_name;
/** Per player difficulty. */
GUIEngine::SpinnerWidget *m_difficulty;
/** Apply per player difficulty in singleplayer mode. */
GUIEngine::CheckBoxWidget *m_singleplayer_difficulty;
/** Online check box. */ /** Online check box. */
GUIEngine::CheckBoxWidget *m_online_cb; GUIEngine::CheckBoxWidget *m_online_cb;