diff --git a/data/stk_config.xml b/data/stk_config.xml index a2e4e4d2d..84d3c09c0 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -145,7 +145,7 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sources.cmake b/sources.cmake index 81ebb999d..c054f1b47 100644 --- a/sources.cmake +++ b/sources.cmake @@ -1,6 +1,5 @@ # Modify this file to change the last-modified date when you add/remove a file. -# This will then trigger a new cmake run automatically. +# This will then trigger a new cmake run automatically. file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp") file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp") -file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*") - +file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*") \ No newline at end of file diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp index c904349de..70878d778 100644 --- a/src/config/stk_config.cpp +++ b/src/config/stk_config.cpp @@ -50,6 +50,13 @@ STKConfig::~STKConfig() if(m_default_kart_properties) delete m_default_kart_properties; + + for(std::map::iterator it = m_kart_properties.begin(); + it != m_kart_properties.end(); ++it) + { + if (it->second) + delete it->second; + } } // ~STKConfig //----------------------------------------------------------------------------- @@ -380,6 +387,15 @@ void STKConfig::getAllData(const XMLNode * root) throw std::runtime_error(msg.str()); } m_default_kart_properties->getAllData(node); + const XMLNode *types = node->getNode("kart-type"); + + for (unsigned int i = 0; i < types->getNumNodes(); ++i) + { + const XMLNode* type = types->getNode(i); + m_kart_properties[type->getName()] = new KartProperties(); + m_kart_properties[type->getName()]->copyFrom(m_default_kart_properties); + m_kart_properties[type->getName()]->getAllData(type); + } } // getAllData diff --git a/src/config/stk_config.hpp b/src/config/stk_config.hpp index 3ccbc82f5..0a94d3db8 100644 --- a/src/config/stk_config.hpp +++ b/src/config/stk_config.hpp @@ -30,6 +30,7 @@ #include #include +#include class KartProperties; class MusicInformation; @@ -47,6 +48,7 @@ class STKConfig : public NoCopy protected: /** Default kart properties. */ KartProperties *m_default_kart_properties; + std::map m_kart_properties; public: /** What to do if a kart already has a powerup when it hits a bonus box: @@ -170,6 +172,9 @@ public: /** Returns the default kart properties for each kart. */ const KartProperties & getDefaultKartProperties() const {return *m_default_kart_properties; } + + const KartProperties & + getKartProperties(std::string type) { return *m_kart_properties[type]; } } ; // STKConfig diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 4d3436ade..fcfe0feda 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -99,7 +99,7 @@ const int MIN_SUPPORTED_WIDTH = 800; * So we create a dummy device here to begin with, which is then later (once * the real device exists) changed in initDevice(). */ -IrrDriver::IrrDriver() +IrrDriver::IrrDriver() : object_count{} { m_resolution_changing = RES_CHANGE_NONE; m_phase = SOLID_NORMAL_AND_DEPTH_PASS; @@ -110,8 +110,8 @@ IrrDriver::IrrDriver() m_post_processing = NULL; m_wind = new Wind(); m_mipviz = m_wireframe = m_normals = m_ssaoviz = \ - m_lightviz = m_shadowviz = m_distortviz = m_rsm = m_rh = m_gi = 0; - SkyboxCubeMap = 0; + m_lightviz = m_shadowviz = m_distortviz = m_rsm = m_rh = m_gi = false; + SkyboxCubeMap = m_last_light_bucket_distance = 0; } // IrrDriver // ---------------------------------------------------------------------------- @@ -1657,8 +1657,14 @@ void IrrDriver::displayFPS() if (UserConfigParams::m_artist_debug_mode) { - sprintf(buffer, "FPS: %i/%i/%i - Objects (P1:%d P2:%d T:%d) - LightDst : ~%d", - min, fps, max, object_count[SOLID_NORMAL_AND_DEPTH_PASS], object_count[SOLID_NORMAL_AND_DEPTH_PASS], object_count[TRANSPARENT_PASS], m_last_light_bucket_distance); + sprintf( + buffer, "FPS: %i/%i/%i - Objects (P1:%d P2:%d T:%d) - LightDst : ~%d", + min, fps, max, + object_count[SOLID_NORMAL_AND_DEPTH_PASS], + object_count[SOLID_NORMAL_AND_DEPTH_PASS], + object_count[TRANSPARENT_PASS], + m_last_light_bucket_distance + ); object_count[SOLID_NORMAL_AND_DEPTH_PASS] = 0; object_count[SOLID_NORMAL_AND_DEPTH_PASS] = 0; object_count[TRANSPARENT_PASS] = 0; diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index a9fd70691..7957a7f34 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -821,7 +821,9 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz core::aabbox3df trackbox(vmin->toIrrVector(), vmax->toIrrVector() - core::vector3df(0, 30, 0)); if (trackbox.MinEdge.X != trackbox.MaxEdge.X && - trackbox.MinEdge.Y != trackbox.MaxEdge.Y) + trackbox.MinEdge.Y != trackbox.MaxEdge.Y && + // Cover the case where SunCamViewMatrix is null + SunCamViewMatrix.getScale() != core::vector3df(0., 0., 0.)) { SunCamViewMatrix.transformBoxEx(trackbox); core::matrix4 tmp_matrix; diff --git a/src/guiengine/widgets/kart_stats_widget.cpp b/src/guiengine/widgets/kart_stats_widget.cpp new file mode 100644 index 000000000..55c40108c --- /dev/null +++ b/src/guiengine/widgets/kart_stats_widget.cpp @@ -0,0 +1,170 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009-2013 Marianne Gagnon +// +// 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 "guiengine/engine.hpp" +#include "guiengine/widgets/kart_stats_widget.hpp" +#include "utils/string_utils.hpp" +#include +#include "karts/kart_properties.hpp" +#include "karts/kart_properties_manager.hpp" + +#include "utils/log.hpp" +#include "utils/string_utils.hpp" + +#include "config/user_config.hpp" + +#include +#include +#include + +using namespace GUIEngine; +using namespace irr::core; +using namespace irr; + +// ----------------------------------------------------------------------------- + +KartStatsWidget::KartStatsWidget(core::recti area, const int player_id, + std::string kart_group, + bool multiplayer) : Widget(WTYPE_DIV) +{ + m_player_id = player_id; + + setSize(area.UpperLeftCorner.X, area.UpperLeftCorner.Y, + area.getWidth(), area.getHeight() ); + + const std::string default_kart = UserConfigParams::m_default_kart; + const KartProperties* props = + kart_properties_manager->getKart(default_kart); + if(!props) + { + // If the default kart can't be found (e.g. previously a addon + // kart was used, but the addon package was removed), use the + // first kart as a default. This way we don't have to hardcode + // any kart names. + int id = kart_properties_manager->getKartByGroup(kart_group, 0); + if (id == -1) + { + props = kart_properties_manager->getKartById(0); + } + else + { + props = kart_properties_manager->getKartById(id); + } + + if(!props) + { + fprintf(stderr, + "[KartSelectionScreen] WARNING: Can't find default " + "kart '%s' nor any other kart.\n", + default_kart.c_str()); + exit(-1); + } + } + + + const int offset = (m_h - (SKILL_COUNT*m_skill_bar_h)) / 2; + for (int i = 0; i < SKILL_COUNT; ++i) + { + irr::core::recti skillArea(m_skill_bar_x, m_skill_bar_y + offset*i, + m_skill_bar_x + m_skill_bar_w, + m_skill_bar_y + m_skill_bar_h + offset*i); + + SkillLevelWidget* skill_bar = NULL; + + skill_bar = new SkillLevelWidget(skillArea, m_player_id, multiplayer); + + m_skills.push_back(skill_bar); + m_children.push_back(skill_bar); + } + + m_skills[SKILL_MASS]->setValue((int)(props->getMass()/5)); + m_skills[SKILL_MASS]->setLabel("WEIGHT"); + m_skills[SKILL_MASS]->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_mass", m_player_id); + + m_skills[SKILL_SPEED]->setValue((int)((props->getAbsMaxSpeed()-20)*20)); + m_skills[SKILL_SPEED]->setLabel("SPEED"); + m_skills[SKILL_SPEED]->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_speed", m_player_id); + + m_skills[SKILL_POWER]->setValue((int)(props->getAvgPower())); + m_skills[SKILL_POWER]->setLabel("POWER"); + m_skills[SKILL_POWER]->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_power", m_player_id); + +} // KartStatsWidget + +// ----------------------------------------------------------------------------- + +void KartStatsWidget::add() +{ + for (int i = 0; i < SKILL_COUNT; ++i) { + m_skills[i]->add(); + } +} + +void KartStatsWidget::move(int x, int y, int w, int h) +{ + Widget::move(x,y,w,h); + setSize(m_x, m_y, m_w, m_h); + int offset = (m_h - (SKILL_COUNT*m_skill_bar_h)) / 2; + for (int i = 0; i < SKILL_COUNT; ++i) + { + m_skills[i]->move(m_skill_bar_x, + m_y + offset + m_skill_bar_h*i, + m_skill_bar_w, + m_skill_bar_h); + } +} //move + +// ----------------------------------------------------------------------------- + +// ---- set value for given type +void KartStatsWidget::setValue(Stats type, int value) +{ + m_skills[type]->setValue(value); +} //setValue + +// ----------------------------------------------------------------------------- + +// ---- get value for given type +int KartStatsWidget::getValue(Stats type) +{ + return m_skills[type]->getValue(); +} // getVAlue + +// ---- set size for widgets inside KartStatsWidget +void KartStatsWidget::setSize(const int x, const int y, const int w, const int h) +{ + m_x = x; + m_y = y; + m_w = w; + m_h = h; + + // -- sizes + m_skill_bar_w = w; + m_skill_bar_h = GUIEngine::getTitleFontHeight(); + + // for shrinking effect + if (h < 175) + { + const float factor = h / 175.0f; + m_skill_bar_h = (int)(m_skill_bar_h*factor); + } + + m_skill_bar_x = x; + m_skill_bar_y = y + h/2 - m_skill_bar_h/2; +} // setSize + +// ----------------------------------------------------------------------------- diff --git a/src/guiengine/widgets/kart_stats_widget.hpp b/src/guiengine/widgets/kart_stats_widget.hpp new file mode 100644 index 000000000..c1e7f5a9d --- /dev/null +++ b/src/guiengine/widgets/kart_stats_widget.hpp @@ -0,0 +1,104 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009-2013 Marianne Gagnon +// +// 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. + + + +#ifndef HEADER_KART_STATS_HPP +#define HEADER_KART_STATS_HPP + +#include + +#include "guiengine/widget.hpp" +#include "utils/leak_check.hpp" +#include "utils/ptr_vector.hpp" + +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/progress_bar_widget.hpp" +#include "guiengine/widgets/skill_level_widget.hpp" + + +namespace GUIEngine +{ + /** + * \brief A progress bar widget. + * \ingroup widgetsgroup + */ + + +class KartStatsWidget : public Widget + { + /** When inferring widget size from its label length, this method will be called to + * if/how much space must be added to the raw label's size for the widget to be large enough */ + virtual int getWidthNeededAroundLabel() const { return 35; } + + /** When inferring widget size from its label length, this method will be called to + * if/how much space must be added to the raw label's size for the widget to be large enough */ + virtual int getHeightNeededAroundLabel() const { return 4; } + + /** widget coordinates */ + int m_skill_bar_x, m_skill_bar_y, m_skill_bar_h, m_skill_bar_w; + + int m_player_id; + + std::vector m_skills; + + + public: + + enum Stats + { + SKILL_MASS, + SKILL_SPEED, + SKILL_POWER, + SKILL_COUNT + }; + + LEAK_CHECK() + + KartStatsWidget(core::recti area, const int player_id, + std::string kart_group, + bool multiplayer); + virtual ~KartStatsWidget() {}; + + // ------------------------------------------------------------------------ + /** Add the widgets to the current screen */ + virtual void add(); + + /** Move the widget and its children */ + virtual void move(const int x, const int y, const int w, const int h); + + // ------------------------------------------------------------------------- + /** Updates the animation (moving/shrinking/etc.) */ + void onUpdate(float delta); + + // ------------------------------------------------------------------------- + /** Event callback */ + + // ------------------------------------------------------------------------- + /** Sets the size of the widget as a whole, and placed children widgets + * inside itself */ + void setSize(const int x, const int y, const int w, const int h); + + /** Change the value of the widget, it must be a percent. */ + void setValue(Stats type, int value); + + /** Get the current values of the widget. */ + int getValue(Stats type); + }; +} + +#endif diff --git a/src/guiengine/widgets/model_view_widget.cpp b/src/guiengine/widgets/model_view_widget.cpp index 745500998..031de875e 100644 --- a/src/guiengine/widgets/model_view_widget.cpp +++ b/src/guiengine/widgets/model_view_widget.cpp @@ -33,7 +33,7 @@ using namespace irr::core; using namespace irr::gui; ModelViewWidget::ModelViewWidget() : - IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_TEXTURE_ASPECT_RATIO, false, false) +IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_TEXTURE_ASPECT_RATIO, false, false) { m_frame_buffer = NULL; m_rtt_main_node = NULL; @@ -42,17 +42,17 @@ ModelViewWidget::ModelViewWidget() : m_type = WTYPE_MODEL_VIEW; m_rtt_provider = NULL; m_rotation_mode = ROTATE_OFF; - + // so that the base class doesn't complain there is no icon defined m_properties[PROP_ICON]="gui/main_help.png"; - + m_rtt_unsupported = false; } // ----------------------------------------------------------------------------- ModelViewWidget::~ModelViewWidget() { GUIEngine::needsUpdate.remove(this); - + delete m_rtt_provider; m_rtt_provider = NULL; } @@ -61,18 +61,18 @@ void ModelViewWidget::add() { // so that the base class doesn't complain there is no icon defined m_properties[PROP_ICON]="gui/main_help.png"; - + IconButtonWidget::add(); - + /* FIXME: remove this unclean thing, I think irrlicht provides this feature: - virtual void IGUIElement::OnPostRender (u32 timeMs) - \brief animate the element and its children. + virtual void IGUIElement::OnPostRender (u32 timeMs) + \brief animate the element and its children. */ GUIEngine::needsUpdate.push_back(this); - + angle = 0; - + } // add // ----------------------------------------------------------------------------- @@ -82,11 +82,11 @@ void ModelViewWidget::clearModels() m_model_location.clear(); m_model_scale.clear(); m_model_frames.clear(); - + if (m_rtt_main_node != NULL) m_rtt_main_node->remove(); if (m_light != NULL) m_light->remove(); if (m_camera != NULL) m_camera->remove(); - + m_rtt_main_node = NULL; m_camera = NULL; m_light = NULL; @@ -98,7 +98,7 @@ void ModelViewWidget::addModel(irr::scene::IMesh* mesh, const Vec3& location, const Vec3& scale, const int frame) { if(!mesh) return; - + m_models.push_back(mesh); m_model_location.push_back(location); m_model_scale.push_back(scale); @@ -109,7 +109,7 @@ void ModelViewWidget::addModel(irr::scene::IMesh* mesh, const Vec3& location, void ModelViewWidget::update(float delta) { if (m_rtt_unsupported) return; - + if (m_rotation_mode == ROTATE_CONTINUOUSLY) { angle += delta*m_rotation_speed; @@ -121,10 +121,10 @@ void ModelViewWidget::update(float delta) // (taking wrap-arounds into account) const int angle_distance_from_end = (int)(360 - angle); const int target_distance_from_end = (int)(360 - angle); - + int distance_with_positive_rotation; int distance_with_negative_rotation; - + if (angle < m_rotation_target) { distance_with_positive_rotation = (int)(m_rotation_target - angle); @@ -135,10 +135,10 @@ void ModelViewWidget::update(float delta) distance_with_positive_rotation = (int)(angle_distance_from_end + m_rotation_target); distance_with_negative_rotation = (int)(angle - m_rotation_target); } - + //std::cout << "distance_with_positive_rotation=" << distance_with_positive_rotation << //" distance_with_negative_rotation=" << distance_with_negative_rotation << " angle="<< angle < 360) angle -= 360; if (angle < 0) angle += 360; - + // stop rotating when target reached if (fabsf(angle - m_rotation_target) < 2.0f) m_rotation_mode = ROTATE_OFF; } - + if (!irr_driver->isGLSL()) return; - + if (m_rtt_provider == NULL) { std::string name = "model view "; name += m_properties[PROP_ID].c_str(); - + m_rtt_provider = new RTT(512, 512); } - + if (m_rtt_main_node == NULL) { setupRTTScene(m_models, m_model_location, m_model_scale, m_model_frames); } - + m_rtt_main_node->setRotation(core::vector3df(0.0f, angle, 0.0f)); m_rtt_main_node->setVisible(true); @@ -180,22 +180,22 @@ void ModelViewWidget::update(float delta) } void ModelViewWidget::setupRTTScene(PtrVector& mesh, - AlignedArray& mesh_location, - AlignedArray& mesh_scale, - const std::vector& model_frames) + AlignedArray& mesh_location, + AlignedArray& mesh_scale, + const std::vector& model_frames) { irr_driver->suppressSkyBox(); - + if (m_rtt_main_node != NULL) m_rtt_main_node->remove(); if (m_light != NULL) m_light->remove(); if (m_camera != NULL) m_camera->remove(); - + m_rtt_main_node = NULL; m_camera = NULL; m_light = NULL; - + irr_driver->clearLights(); - + if (model_frames[0] == -1) { scene::ISceneNode* node = irr_driver->addMesh(mesh.get(0), NULL); @@ -207,27 +207,27 @@ void ModelViewWidget::setupRTTScene(PtrVector& mesh, else { scene::IAnimatedMeshSceneNode* node = - irr_driver->addAnimatedMesh((scene::IAnimatedMesh*)mesh.get(0), NULL); + irr_driver->addAnimatedMesh((scene::IAnimatedMesh*)mesh.get(0), NULL); node->setPosition(mesh_location[0].toIrrVector()); node->setFrameLoop(model_frames[0], model_frames[0]); node->setAnimationSpeed(0); node->setScale(mesh_scale[0].toIrrVector()); node->setMaterialFlag(video::EMF_FOG_ENABLE, false); - + m_rtt_main_node = node; } - + assert(m_rtt_main_node != NULL); assert(mesh.size() == mesh_location.size()); assert(mesh.size() == model_frames.size()); - + const int mesh_amount = mesh.size(); for (int n = 1; naddMesh(mesh.get(n), m_rtt_main_node); + irr_driver->addMesh(mesh.get(n), m_rtt_main_node); node->setPosition(mesh_location[n].toIrrVector()); node->updateAbsolutePosition(); node->setScale(mesh_scale[n].toIrrVector()); @@ -235,8 +235,8 @@ void ModelViewWidget::setupRTTScene(PtrVector& mesh, else { scene::IAnimatedMeshSceneNode* node = - irr_driver->addAnimatedMesh((scene::IAnimatedMesh*)mesh.get(n), - m_rtt_main_node); + irr_driver->addAnimatedMesh((scene::IAnimatedMesh*)mesh.get(n), + m_rtt_main_node); node->setPosition(mesh_location[n].toIrrVector()); node->setFrameLoop(model_frames[n], model_frames[n]); node->setAnimationSpeed(0); @@ -245,32 +245,32 @@ void ModelViewWidget::setupRTTScene(PtrVector& mesh, //std::cout << "(((( set frame " << model_frames[n] << " ))))\n"; } } - + irr_driver->getSceneManager()->setAmbientLight(video::SColor(255, 35, 35, 35)); - + const core::vector3df &spot_pos = core::vector3df(0, 30, 40); m_light = irr_driver->addLight(spot_pos, 0.3f /* energy */, 10 /* distance */, 1.0f /* r */, 1.0f /* g */, 1.0f /* g*/, true, NULL); - + m_rtt_main_node->setMaterialFlag(video::EMF_GOURAUD_SHADING, true); m_rtt_main_node->setMaterialFlag(video::EMF_LIGHTING, true); - + const int materials = m_rtt_main_node->getMaterialCount(); for (int n = 0; ngetMaterial(n).setFlag(video::EMF_LIGHTING, true); - + // set size of specular highlights m_rtt_main_node->getMaterial(n).Shininess = 100.0f; m_rtt_main_node->getMaterial(n).SpecularColor.set(255, 50, 50, 50); m_rtt_main_node->getMaterial(n).DiffuseColor.set(255, 150, 150, 150); - + m_rtt_main_node->getMaterial(n).setFlag(video::EMF_GOURAUD_SHADING, - true); + true); } - + m_camera = irr_driver->getSceneManager()->addCameraSceneNode(); m_camera->setAspectRatio(1.0f); - + m_camera->setPosition(core::vector3df(0.0, 20.0f, 70.0f)); m_camera->setUpVector(core::vector3df(0.0, 1.0, 0.0)); m_camera->setTarget(core::vector3df(0, 10, 0.0f)); diff --git a/src/guiengine/widgets/progress_bar_widget.cpp b/src/guiengine/widgets/progress_bar_widget.cpp index fc79403c5..10c493b2b 100644 --- a/src/guiengine/widgets/progress_bar_widget.cpp +++ b/src/guiengine/widgets/progress_bar_widget.cpp @@ -30,9 +30,10 @@ using namespace irr; // ----------------------------------------------------------------------------- -ProgressBarWidget::ProgressBarWidget() : Widget(WTYPE_PROGRESS) +ProgressBarWidget::ProgressBarWidget(bool show_label) : Widget(WTYPE_PROGRESS) { m_value = 0; + m_show_label = show_label; } // ----------------------------------------------------------------------------- @@ -52,7 +53,10 @@ void ProgressBarWidget::add() void ProgressBarWidget::setValue(int value) { m_value = value; - setLabel(std::string(StringUtils::toString(value) + "%").c_str()); + if (m_show_label) + { + setLabel(std::string(StringUtils::toString(value) + "%").c_str()); + } } // ----------------------------------------------------------------------------- diff --git a/src/guiengine/widgets/progress_bar_widget.hpp b/src/guiengine/widgets/progress_bar_widget.hpp index 06cfaadcb..7ec8c8b91 100644 --- a/src/guiengine/widgets/progress_bar_widget.hpp +++ b/src/guiengine/widgets/progress_bar_widget.hpp @@ -45,12 +45,12 @@ namespace GUIEngine /** Change the label on the widget */ void setLabel(const irr::core::stringw label); int m_value; + bool m_show_label; public: LEAK_CHECK() - - ProgressBarWidget(); + ProgressBarWidget(bool show_label = true); virtual ~ProgressBarWidget() {} /** Change the value of the widget, it must be a percent. */ diff --git a/src/guiengine/widgets/skill_level_widget.cpp b/src/guiengine/widgets/skill_level_widget.cpp new file mode 100644 index 000000000..97786bf1e --- /dev/null +++ b/src/guiengine/widgets/skill_level_widget.cpp @@ -0,0 +1,152 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009-2013 Marianne Gagnon +// +// 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 "guiengine/engine.hpp" +#include "guiengine/widgets/skill_level_widget.hpp" +#include "utils/string_utils.hpp" +#include +#include "karts/kart_properties.hpp" +#include "karts/kart_properties_manager.hpp" + +#include "utils/log.hpp" +#include "utils/string_utils.hpp" + +#include "config/user_config.hpp" + +#include +#include +#include + +using namespace GUIEngine; +using namespace irr::core; +using namespace irr; + +// ----------------------------------------------------------------------------- + +SkillLevelWidget::SkillLevelWidget(core::recti area, const int player_id, + bool multiplayer, const int value, + const stringw& label) : Widget(WTYPE_DIV) +{ + m_player_id = player_id; + + setSize(area.UpperLeftCorner.X, area.UpperLeftCorner.Y, + area.getWidth(), area.getHeight() ); + + // ---- Mass skill level widget + m_bar = NULL; + + m_bar = new ProgressBarWidget(false); + m_bar->setValue(value); + + m_bar->m_x = m_bar_x; + m_bar->m_y = m_bar_y; + m_bar->m_w = m_bar_w; + m_bar->m_h = m_bar_h; + m_bar->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_skill_bar", m_player_id); + + m_label = NULL; + + m_label = new LabelWidget(!multiplayer, true); + m_label->setText(label,false); + + m_label->m_x = m_label_x; + m_label->m_y = m_label_y; + m_label->m_w = m_label_w; + m_label->m_h = m_label_h; + m_label->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_skill_label", m_player_id); + + m_children.push_back(m_bar); + m_children.push_back(m_label); +} // KartStatsWidget + +// ----------------------------------------------------------------------------- + +void SkillLevelWidget::add() +{ + m_bar->add(); + m_label->add(); +} + +// ----------------------------------------------------------------------------- + + +void SkillLevelWidget::move(const int x, const int y, const int w, const int h) +{ + Widget::move(x,y,w,h); + setSize(m_x, m_y, m_w, m_h); + + if (m_bar != NULL) + { + m_bar->move(m_bar_x, + m_bar_y, + m_bar_w, + m_bar_h ); + } + if (m_label != NULL) + { + m_label->move(m_label_x, + m_label_y, + m_label_w, + m_label_h); + } +} + +// ------------------------------------------------------------------------- + +void SkillLevelWidget::setSize(const int x, const int y, const int w, const int h) +{ + m_x = x; + m_y = y; + m_w = w; + m_h = h; + + // -- sizes + m_bar_w = 3*(w/2)/4; + m_bar_h = h; + m_label_w = w/2; + m_label_h = h; + + // for shrinking effect + if (h < 175) + { + const float factor = h / 175.0f; + m_bar_h = (int)(m_bar_h*factor); + m_label_h = (int)(m_label_h*factor); + } + + m_bar_x = x + w/2; + m_bar_y = y + m_h/2 - m_bar_h/2; + + m_label_x = x; + m_label_y = y + m_h/2 - m_label_h/2; +} // setSize + +// ----------------------------------------------------------------------------- + +void SkillLevelWidget::setValue(const int value) +{ + m_bar->setValue(value); + +} + +// ----------------------------------------------------------------------------- + +void SkillLevelWidget::setLabel(const irr::core::stringw& label) +{ + m_label->setText(label, false); +} + diff --git a/src/guiengine/widgets/skill_level_widget.hpp b/src/guiengine/widgets/skill_level_widget.hpp new file mode 100644 index 000000000..a621e6786 --- /dev/null +++ b/src/guiengine/widgets/skill_level_widget.hpp @@ -0,0 +1,102 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009-2013 Marianne Gagnon +// +// 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. + + + +#ifndef HEADER_SKILL_LEVEL_HPP +#define HEADER_SKILL_LEVEL_HPP + +#include + +#include "guiengine/widget.hpp" +#include "utils/leak_check.hpp" +#include "utils/ptr_vector.hpp" + +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/progress_bar_widget.hpp" + + +namespace GUIEngine +{ + /** + * \brief A skill level widget. + * \ingroup widgetsgroup + */ + +class SkillLevelWidget : public Widget + { + /** When inferring widget size from its label length, this method will be called to + * if/how much space must be added to the raw label's size for the widget to be large enough */ + virtual int getWidthNeededAroundLabel() const { return 35; } + + /** When inferring widget size from its label length, this method will be called to + * if/how much space must be added to the raw label's size for the widget to be large enough */ + virtual int getHeightNeededAroundLabel() const { return 4; } + + /** widget coordinates */ + int m_bar_x, m_bar_y, m_bar_h, m_bar_w; + int m_label_x, m_label_y, m_label_h, m_label_w; + + std::string m_label_name; + + int m_player_id; + + public: + + LEAK_CHECK() + + LabelWidget* m_label; + ProgressBarWidget* m_bar; + + SkillLevelWidget(core::recti area, const int player_id, bool multiplayer, + const int value = 0, const irr::core::stringw& label = "default"); + + virtual ~SkillLevelWidget() {}; + + // ------------------------------------------------------------------------ + /** Add the widgets to the current screen */ + virtual void add(); + + // ------------------------------------------------------------------------- + + virtual void move(const int x, const int y, const int w, const int h); + + // ------------------------------------------------------------------------- + + /** Sets the size of the widget as a whole, and placed children widgets + * inside itself */ + void setSize(const int x, const int y, const int w, const int h); + + /** Change the value of the widget, it must be a percent. */ + void setValue(const int value); + + /** Get the current values of the widget. */ + int getValue() {return m_bar->getValue(); }; + + /** Change the label of the widget */ + void setLabel(const irr::core::stringw& label); + + /** Get the current label of the widget. */ + const irr::core::stringw& getLabel() + { + return m_label->getText(); + } + + }; +} + +#endif diff --git a/src/input/device_manager.cpp b/src/input/device_manager.cpp index dc1dca670..c82a02068 100644 --- a/src/input/device_manager.cpp +++ b/src/input/device_manager.cpp @@ -74,15 +74,16 @@ bool DeviceManager::initialize() } const int keyboard_amount = m_keyboard_configs.size(); - for (int n=0; ngetDevice()->activateJoysticks(m_irrlicht_gamepads); + int num_gamepads = m_irrlicht_gamepads.size(); if(UserConfigParams::logMisc()) { @@ -90,8 +91,6 @@ bool DeviceManager::initialize() num_gamepads); } - - // Create GamePadDevice for each physical gamepad and find a GamepadConfig to match for (int id = 0; id < num_gamepads; id++) { @@ -112,6 +111,7 @@ bool DeviceManager::initialize() { Log::info("Device manager","#%d: %s detected...", id, name.c_str()); } + // Returns true if new configuration was created if (getConfigForGamepad(id, name, &gamepadConfig) == true) { @@ -135,6 +135,7 @@ bool DeviceManager::initialize() } // end for if (created) serialize(); + return created; } // initialize diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index 203704ea9..940bf5c7a 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -172,13 +172,19 @@ void KartProperties::load(const std::string &filename, const std::string &node) { // Get the default values from STKConfig. This will also allocate any // pointers used in KartProperties - copyFrom(&stk_config->getDefaultKartProperties()); + + const XMLNode* root = new XMLNode(filename); + std::string kart_type; + if (root->get("type", &kart_type)) + copyFrom(&stk_config->getKartProperties(kart_type)); + else + copyFrom(&stk_config->getDefaultKartProperties()); + // m_kart_model must be initialised after assigning the default // values from stk_config (otherwise all kart_properties will // share the same KartModel m_kart_model = new KartModel(/*is_master*/true); - const XMLNode * root = 0; m_root = StringUtils::getPath(filename)+"/"; m_ident = StringUtils::getBasename(StringUtils::getPath(filename)); // If this is an addon kart, add "addon_" to the identifier - just in @@ -188,7 +194,6 @@ void KartProperties::load(const std::string &filename, const std::string &node) m_ident = Addon::createAddonId(m_ident); try { - root = new XMLNode(filename); if(!root || root->getName()!="kart") { std::ostringstream msg; @@ -286,7 +291,7 @@ void KartProperties::load(const std::string &filename, const std::string &node) */ void KartProperties::getAllData(const XMLNode * root) { - root->get("version", &m_version); + root->get("version", &m_version); root->get("name", &m_name ); @@ -307,50 +312,11 @@ void KartProperties::getAllData(const XMLNode * root) root->get("shadow-x-offset", &m_shadow_x_offset ); root->get("shadow-y-offset", &m_shadow_y_offset ); + root->get("type", &m_kart_type ); + if(const XMLNode *dimensions_node = root->getNode("center")) dimensions_node->get("gravity-shift", &m_gravity_center_shift); - if(const XMLNode *nitro_node = root->getNode("nitro")) - { - nitro_node->get("consumption", &m_nitro_consumption ); - nitro_node->get("small-container", &m_nitro_small_container ); - nitro_node->get("big-container", &m_nitro_big_container ); - nitro_node->get("max-speed-increase", &m_nitro_max_speed_increase); - nitro_node->get("engine-force", &m_nitro_engine_force ); - nitro_node->get("duration", &m_nitro_duration ); - nitro_node->get("fade-out-time", &m_nitro_fade_out_time ); - nitro_node->get("max", &m_nitro_max ); - nitro_node->get("min-consumption-time", &m_nitro_min_consumption ); - } - - if(const XMLNode *bubble_node = root->getNode("bubblegum")) - { - bubble_node->get("time", &m_bubblegum_time ); - bubble_node->get("speed-fraction", &m_bubblegum_speed_fraction); - bubble_node->get("fade-in-time", &m_bubblegum_fade_in_time ); - bubble_node->get("torque", &m_bubblegum_torque ); - } - - if(const XMLNode *rescue_node = root->getNode("rescue")) - { - rescue_node->get("vert-offset", &m_rescue_vert_offset); - rescue_node->get("time", &m_rescue_time ); - rescue_node->get("height", &m_rescue_height ); - } - - if(const XMLNode *explosion_node = root->getNode("explosion")) - { - explosion_node->get("time", &m_explosion_time ); - explosion_node->get("radius", &m_explosion_radius); - explosion_node->get("invulnerability-time", - &m_explosion_invulnerability_time); - } - - if(const XMLNode *skid_node = root->getNode("skid")) - { - m_skidding_properties->load(skid_node); - } - if(const XMLNode *ai_node = root->getNode("ai")) { const XMLNode *easy = ai_node->getNode("easy"); @@ -363,59 +329,6 @@ void KartProperties::getAllData(const XMLNode * root) m_ai_properties[RaceManager::DIFFICULTY_BEST]->load(best); } - if(const XMLNode *slipstream_node = root->getNode("slipstream")) - { - slipstream_node->get("length", &m_slipstream_length ); - slipstream_node->get("width", &m_slipstream_width ); - slipstream_node->get("collect-time", &m_slipstream_collect_time ); - slipstream_node->get("use-time", &m_slipstream_use_time ); - slipstream_node->get("add-power", &m_slipstream_add_power ); - slipstream_node->get("min-speed", &m_slipstream_min_speed ); - slipstream_node->get("max-speed-increase", - &m_slipstream_max_speed_increase); - slipstream_node->get("duration", &m_slipstream_duration ); - slipstream_node->get("fade-out-time",&m_slipstream_fade_out_time ); - } - - if(const XMLNode *turn_node = root->getNode("turn")) - { - turn_node->get("time-full-steer", &m_time_full_steer ); - turn_node->get("time-reset-steer", &m_time_reset_steer ); - turn_node->get("turn-radius", &m_turn_angle_at_speed ); - // For now store the turn radius in turn angle, the correct - // value can only be determined later in ::load - } - - if(const XMLNode *engine_node = root->getNode("engine")) - { - engine_node->get("brake-factor", &m_brake_factor); - engine_node->get("max-speed-reverse-ratio", &m_max_speed_reverse_ratio); - engine_node->get("power", &m_engine_power); - if(m_engine_power.size()!=RaceManager::DIFFICULTY_COUNT) - { - Log::fatal("[KartProperties]", - "Incorrect engine-power specifications for kart '%s'", - getIdent().c_str()); - } - engine_node->get("max-speed", &m_max_speed); - if(m_max_speed.size()!=RaceManager::DIFFICULTY_COUNT) - { - Log::fatal("[KartProperties]", - "Incorrect max-speed specifications for kart '%s'", - getIdent().c_str()); - } - } // if getNode("engine") - - if(const XMLNode *gear_node = root->getNode("gear")) - { - gear_node->get("switch-ratio", &m_gear_switch_ratio ); - gear_node->get("power-increase", &m_gear_power_increase); - } - - if(const XMLNode *mass_node = root->getNode("mass")) - mass_node->get("value", &m_mass); - - if(const XMLNode *suspension_node = root->getNode("suspension")) { suspension_node->get("stiffness", &m_suspension_stiffness); @@ -488,50 +401,6 @@ void KartProperties::getAllData(const XMLNode * root) //TODO: listed as an attribute in the xml file after wheel-radius //TODO: same goes for their rear equivalents - if(const XMLNode *plunger_node= root->getNode("plunger")) - { - plunger_node->get("band-max-length", &m_rubber_band_max_length ); - plunger_node->get("band-force", &m_rubber_band_force ); - plunger_node->get("band-duration", &m_rubber_band_duration ); - plunger_node->get("band-speed-increase",&m_rubber_band_speed_increase); - plunger_node->get("band-fade-out-time", &m_rubber_band_fade_out_time ); - plunger_node->get("in-face-time", &m_plunger_in_face_duration); - if(m_plunger_in_face_duration.size()!=RaceManager::DIFFICULTY_COUNT) - { - Log::fatal("KartProperties", - "Invalid plunger in-face-time specification."); - } - } - - if(const XMLNode *zipper_node= root->getNode("zipper")) - { - zipper_node->get("time", &m_zipper_time ); - zipper_node->get("fade-out-time", &m_zipper_fade_out_time ); - zipper_node->get("force", &m_zipper_force ); - zipper_node->get("speed-gain", &m_zipper_speed_gain ); - zipper_node->get("max-speed-increase", &m_zipper_max_speed_increase); - } - - if(const XMLNode *swatter_node= root->getNode("swatter")) - { - swatter_node->get("duration", &m_swatter_duration ); - swatter_node->get("squash-duration", &m_squash_duration ); - swatter_node->get("squash-slowdown", &m_squash_slowdown ); - if(swatter_node->get("distance", &m_swatter_distance2) ) - { - // Avoid squaring if distance is not defined, so that - // distance2 remains UNDEFINED (which is a negative value) - m_swatter_distance2 *= m_swatter_distance2; - } - } - - if(const XMLNode *lean_node= root->getNode("lean")) - { - lean_node->get("max", &m_max_lean ); - lean_node->get("speed", &m_lean_speed); - m_max_lean *= DEGREE_TO_RAD; - m_lean_speed *= DEGREE_TO_RAD; - } if(const XMLNode *jump_node= root->getNode("jump")) { @@ -547,12 +416,6 @@ void KartProperties::getAllData(const XMLNode * root) m_camera_backward_up_angle *= DEGREE_TO_RAD; } - if(const XMLNode *startup_node= root->getNode("startup")) - { - startup_node->get("time", &m_startup_times); - startup_node->get("boost", &m_startup_boost); - } - if(const XMLNode *sounds_node= root->getNode("sounds")) { std::string s; @@ -598,6 +461,151 @@ void KartProperties::getAllData(const XMLNode * root) #endif } // if sounds-node exist + if(const XMLNode *nitro_node = root->getNode("nitro")) + { + nitro_node->get("consumption", &m_nitro_consumption ); + nitro_node->get("small-container", &m_nitro_small_container ); + nitro_node->get("big-container", &m_nitro_big_container ); + nitro_node->get("max-speed-increase", &m_nitro_max_speed_increase); + nitro_node->get("engine-force", &m_nitro_engine_force ); + nitro_node->get("duration", &m_nitro_duration ); + nitro_node->get("fade-out-time", &m_nitro_fade_out_time ); + nitro_node->get("max", &m_nitro_max ); + nitro_node->get("min-consumption-time", &m_nitro_min_consumption ); + } + + if(const XMLNode *bubble_node = root->getNode("bubblegum")) + { + bubble_node->get("time", &m_bubblegum_time ); + bubble_node->get("speed-fraction", &m_bubblegum_speed_fraction); + bubble_node->get("fade-in-time", &m_bubblegum_fade_in_time ); + bubble_node->get("torque", &m_bubblegum_torque ); + } + + if(const XMLNode *rescue_node = root->getNode("rescue")) + { + rescue_node->get("vert-offset", &m_rescue_vert_offset); + rescue_node->get("time", &m_rescue_time ); + rescue_node->get("height", &m_rescue_height ); + } + + if(const XMLNode *explosion_node = root->getNode("explosion")) + { + explosion_node->get("time", &m_explosion_time ); + explosion_node->get("radius", &m_explosion_radius); + explosion_node->get("invulnerability-time", + &m_explosion_invulnerability_time); + } + + if(const XMLNode *skid_node = root->getNode("skid")) + { + m_skidding_properties->load(skid_node); + } + + + if(const XMLNode *slipstream_node = root->getNode("slipstream")) + { + slipstream_node->get("length", &m_slipstream_length ); + slipstream_node->get("width", &m_slipstream_width ); + slipstream_node->get("collect-time", &m_slipstream_collect_time ); + slipstream_node->get("use-time", &m_slipstream_use_time ); + slipstream_node->get("add-power", &m_slipstream_add_power ); + slipstream_node->get("min-speed", &m_slipstream_min_speed ); + slipstream_node->get("max-speed-increase", + &m_slipstream_max_speed_increase); + slipstream_node->get("duration", &m_slipstream_duration ); + slipstream_node->get("fade-out-time",&m_slipstream_fade_out_time ); + } + + if(const XMLNode *turn_node = root->getNode("turn")) + { + turn_node->get("time-full-steer", &m_time_full_steer ); + turn_node->get("time-reset-steer", &m_time_reset_steer ); + turn_node->get("turn-radius", &m_turn_angle_at_speed ); + // For now store the turn radius in turn angle, the correct + // value can only be determined later in ::load + } + + if(const XMLNode *engine_node = root->getNode("engine")) + { + engine_node->get("brake-factor", &m_brake_factor); + engine_node->get("max-speed-reverse-ratio", &m_max_speed_reverse_ratio); + engine_node->get("power", &m_engine_power); + if(m_engine_power.size()!=RaceManager::DIFFICULTY_COUNT) + { + Log::fatal("[KartProperties]", + "Incorrect engine-power specifications for kart '%s'", + getIdent().c_str()); + } + engine_node->get("max-speed", &m_max_speed); + if(m_max_speed.size()!=RaceManager::DIFFICULTY_COUNT) + { + Log::fatal("[KartProperties]", + "Incorrect max-speed specifications for kart '%s'", + getIdent().c_str()); + } + } // if getNode("engine") + + if(const XMLNode *gear_node = root->getNode("gear")) + { + gear_node->get("switch-ratio", &m_gear_switch_ratio ); + gear_node->get("power-increase", &m_gear_power_increase); + } + + if(const XMLNode *mass_node = root->getNode("mass")) + mass_node->get("value", &m_mass); + + if(const XMLNode *plunger_node= root->getNode("plunger")) + { + plunger_node->get("band-max-length", &m_rubber_band_max_length ); + plunger_node->get("band-force", &m_rubber_band_force ); + plunger_node->get("band-duration", &m_rubber_band_duration ); + plunger_node->get("band-speed-increase",&m_rubber_band_speed_increase); + plunger_node->get("band-fade-out-time", &m_rubber_band_fade_out_time ); + plunger_node->get("in-face-time", &m_plunger_in_face_duration); + if(m_plunger_in_face_duration.size()!=RaceManager::DIFFICULTY_COUNT) + { + Log::fatal("KartProperties", + "Invalid plunger in-face-time specification."); + } + } + + if(const XMLNode *zipper_node= root->getNode("zipper")) + { + zipper_node->get("time", &m_zipper_time ); + zipper_node->get("fade-out-time", &m_zipper_fade_out_time ); + zipper_node->get("force", &m_zipper_force ); + zipper_node->get("speed-gain", &m_zipper_speed_gain ); + zipper_node->get("max-speed-increase", &m_zipper_max_speed_increase); + } + + if(const XMLNode *swatter_node= root->getNode("swatter")) + { + swatter_node->get("duration", &m_swatter_duration ); + swatter_node->get("squash-duration", &m_squash_duration ); + swatter_node->get("squash-slowdown", &m_squash_slowdown ); + if(swatter_node->get("distance", &m_swatter_distance2) ) + { + // Avoid squaring if distance is not defined, so that + // distance2 remains UNDEFINED (which is a negative value) + m_swatter_distance2 *= m_swatter_distance2; + } + } + + if(const XMLNode *lean_node= root->getNode("lean")) + { + lean_node->get("max", &m_max_lean ); + lean_node->get("speed", &m_lean_speed); + m_max_lean *= DEGREE_TO_RAD; + m_lean_speed *= DEGREE_TO_RAD; + } + + if(const XMLNode *startup_node= root->getNode("startup")) + { + startup_node->get("time", &m_startup_times); + startup_node->get("boost", &m_startup_boost); + } + if(m_kart_model) m_kart_model->loadInfo(*root); } // getAllData @@ -755,6 +763,7 @@ bool KartProperties::isInGroup(const std::string &group) const return std::find(m_groups.begin(), m_groups.end(), group) != m_groups.end(); } // isInGroups + // ---------------------------------------------------------------------------- /** Called the first time a kart accelerates after 'ready-set-go'. It searches * through m_startup_times to find the appropriate slot, and returns the @@ -771,4 +780,16 @@ float KartProperties::getStartupBoost() const } return 0; } // getStartupBoost + +// ---------------------------------------------------------------------------- +const float KartProperties::getAvgPower() const +{ + float sum = 0.0; + for (unsigned int i = 0; i < m_gear_power_increase.size(); ++i) + { + sum += m_gear_power_increase[i]*m_max_speed[0]; + } + return sum/m_gear_power_increase.size(); +} // getAvgPower + /* EOF */ diff --git a/src/karts/kart_properties.hpp b/src/karts/kart_properties.hpp index 621b14cec..e9b50c6d1 100644 --- a/src/karts/kart_properties.hpp +++ b/src/karts/kart_properties.hpp @@ -181,6 +181,9 @@ private: */ float m_nitro_min_consumption; + /** Type of the kart (for the properties) */ + std::string m_kart_type; + /** Filename of the wheel models. */ std::string m_wheel_filename[4]; /** Radius of the graphical wheels. */ @@ -543,7 +546,10 @@ public: // ------------------------------------------------------------------------ /** Returns parameters for the speed-weighted objects */ - const SpeedWeightedObject::Properties& getSpeedWeightedObjectProperties() const {return m_speed_weighted_object_properties;} + const SpeedWeightedObject::Properties& getSpeedWeightedObjectProperties() const + { + return m_speed_weighted_object_properties; + } // ------------------------------------------------------------------------ /** Returns the wheel base (distance front to rear axis). */ @@ -568,8 +574,17 @@ public: // ------------------------------------------------------------------------ /** Returns the maximum speed dependent on the difficult level. */ - float getMaxSpeed () const {return - m_max_speed[race_manager->getDifficulty()];} + float getMaxSpeed () const + { + return m_max_speed[race_manager->getDifficulty()]; + } + + // ------------------------------------------------------------------------ + /** Return the absolute maximum speed, independent on the difficulty. */ + float getAbsMaxSpeed () const + { + return m_max_speed[m_max_speed.size()-1]; + } // ------------------------------------------------------------------------ /** Returns the nitro consumption. */ @@ -826,6 +841,10 @@ public: const std::vector& getGearPowerIncrease () const {return m_gear_power_increase; } + // ------------------------------------------------------------------------ + /** Returns the average power of the kart (in all gears). */ + const float getAvgPower () const; + // ------------------------------------------------------------------------ /** Returns distance between kart and camera. */ float getCameraDistance () const {return m_camera_distance; } diff --git a/src/physics/btKart.cpp b/src/physics/btKart.cpp index c195e4535..bdb8f556c 100644 --- a/src/physics/btKart.cpp +++ b/src/physics/btKart.cpp @@ -589,7 +589,7 @@ void btKart::updateSuspension(btScalar deltaTime) btScalar current_length = wheel_info.m_raycastInfo.m_suspensionLength; btScalar length_diff = (susp_length - current_length); if(m_kart->getKartProperties()->getExpSpringResponse()) - length_diff *= length_diff/susp_length; + length_diff *= fabsf(length_diff)/susp_length; force = wheel_info.m_suspensionStiffness * length_diff * wheel_info.m_clippedInvContactDotSuspension; diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index df1d923e8..2e84fd276 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -232,6 +232,31 @@ PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent, m_player_ident_spinner->m_w = player_name_w; m_player_ident_spinner->m_h = player_name_h; + // ---- KartStatsWidget + m_kart_stats = NULL; + + // area for the stats widget + core::recti statsArea; + if (!parent->m_multiplayer) + { + statsArea = core::recti(m_kart_stats_x, + m_kart_stats_y, + m_kart_stats_x + m_kart_stats_w, + m_kart_stats_y + m_kart_stats_h); + } + else + { + statsArea = core::recti(m_x , m_y + m_h/2, + m_x + m_w, m_y + m_h); + } + + + m_kart_stats = new GUIEngine::KartStatsWidget(statsArea, player_id, kart_group, + m_parent_screen->m_multiplayer); + m_kart_stats->m_properties[PROP_ID] = + StringUtils::insertValues("@p%i_stats", m_player_id); + m_children.push_back(m_kart_stats); + if (parent->m_multiplayer && associated_player) { if (associated_player->getDevice()->getType() == DT_KEYBOARD) @@ -272,8 +297,6 @@ PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent, //m_player_ident_spinner->m_event_handler = this; m_children.push_back(m_player_ident_spinner); - - // ----- Kart model view m_model_view = new ModelViewWidget(); @@ -347,7 +370,7 @@ PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent, m_model_view->setRotateContinuously( 35.0f ); // ---- Kart name label - m_kart_name = new LabelWidget(); + m_kart_name = new LabelWidget(true, true); m_kart_name->setText(props->getName(), false); m_kart_name->m_properties[PROP_TEXT_ALIGN] = "center"; m_kart_name->m_properties[PROP_ID] = @@ -356,7 +379,6 @@ PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent, m_kart_name->m_y = kart_name_y; m_kart_name->m_w = kart_name_w; m_kart_name->m_h = kart_name_h; - //m_kart_name->setParent(this); m_children.push_back(m_kart_name); } // PlayerKartWidget // ------------------------------------------------------------------------ @@ -472,7 +494,7 @@ void PlayerKartWidget::add() m_player_ident_spinner->add(); m_player_ident_spinner->getIrrlichtElement()->setTabStop(false); m_player_ident_spinner->setListener(this); - + m_kart_stats->add(); m_model_view->add(); m_kart_name->add(); @@ -660,11 +682,25 @@ void PlayerKartWidget::onUpdate(float delta) core::recti(core::position2di(player_name_x, player_name_y), core::dimension2di(player_name_w, player_name_h)) ); } + if (!m_parent_screen->m_multiplayer) + { + m_kart_stats->move(m_kart_stats_x, + m_kart_stats_y, + m_kart_stats_w, + m_kart_stats_h); + } + else + { + m_kart_stats->move(m_x, m_y + m_h/2, + m_w, m_h/2); + } + m_model_view->move(model_x, model_y, model_w, model_h); + m_kart_name->move(kart_name_x, kart_name_y, kart_name_w, @@ -757,15 +793,41 @@ void PlayerKartWidget::setSize(const int x, const int y, const int w, const int 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; + if (m_parent_screen->m_multiplayer) + { + const int modelMaxHeight = (h - kart_name_h - player_name_h + - player_id_h)/2; + const int modelMaxWidth = w; + const int bestSize = std::min(modelMaxWidth, modelMaxHeight); + model_x = x + w/2 - (int)(bestSize/2); + model_y = y + player_name_h + player_id_h; + model_w = (int)(bestSize); + model_h = bestSize; + + m_kart_stats_w = model_w; + m_kart_stats_h = model_h; + m_kart_stats_x = x + w/2 - (int)(bestSize/2); + m_kart_stats_y = model_y + model_h; + + + } + else + { + 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/4 - (int)(bestSize/2); + model_y = modelY + modelMaxHeight/2 - bestSize/2; + model_w = (int)(bestSize); + model_h = bestSize; + + m_kart_stats_w = w/2; + m_kart_stats_h = h; + m_kart_stats_x = x + w/2; + m_kart_stats_y = y; + } kart_name_x = x; kart_name_y = y + h - kart_name_h; @@ -850,8 +912,8 @@ void KartHoverListener::onSelectionChanged(DynamicRibbonWidget* theWidget, } m_parent->updateKartWidgetModel(playerID, selectionID, selectionText); - m_parent->m_kart_widgets[playerID].setKartInternalName(selectionID); + m_parent->updateKartStats(playerID, selectionID); m_parent->validateKartChoices(); } // onSelectionChanged @@ -1454,6 +1516,23 @@ void KartSelectionScreen::playerConfirm(const int playerID) // ---------------------------------------------------------------------------- +void KartSelectionScreen::updateKartStats(uint8_t widget_id, + const std::string& selection) +{ + KartStatsWidget* w = m_kart_widgets[widget_id].m_kart_stats; + assert(w != NULL); + + const KartProperties *kp = + kart_properties_manager->getKart(selection); + if (kp != NULL) + { + w->setValue(KartStatsWidget::SKILL_MASS, (int)(kp->getMass()/5)); + w->setValue(KartStatsWidget::SKILL_SPEED, (int)((kp->getAbsMaxSpeed()-20)*9)); + w->setValue(KartStatsWidget::SKILL_POWER, (int)(kp->getAvgPower())); + w->update(0); + } +} + void KartSelectionScreen::updateKartWidgetModel(uint8_t widget_id, const std::string& selection, const irr::core::stringw& selectionText) diff --git a/src/states_screens/kart_selection.hpp b/src/states_screens/kart_selection.hpp index 7e3e8fa26..0c0ddf0f0 100644 --- a/src/states_screens/kart_selection.hpp +++ b/src/states_screens/kart_selection.hpp @@ -24,7 +24,9 @@ #include "guiengine/widgets/label_widget.hpp" #include "guiengine/widgets/model_view_widget.hpp" #include "guiengine/widgets/spinner_widget.hpp" +#include "guiengine/widgets/progress_bar_widget.hpp" #include "states_screens/state_manager.hpp" +#include "guiengine/widgets/kart_stats_widget.hpp" #include @@ -109,6 +111,10 @@ protected: void setKartsFromCurrentGroup(); virtual void playerConfirm(const int playerID); + + void updateKartStats(uint8_t widget_id, + const std::string& selection); + /** updates model of a kart widget, to have the good selection when the user validates */ void updateKartWidgetModel(uint8_t widget_id, const std::string& selection, @@ -236,6 +242,7 @@ class PlayerKartWidget : public GUIEngine::Widget, 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_kart_stats_x, m_kart_stats_y, m_kart_stats_w, m_kart_stats_h; /** A reserved ID for this widget if any, -1 otherwise. (If no ID is * reserved, widget will not be in the regular tabbing order */ @@ -267,6 +274,7 @@ public: /** Sub-widgets created by this widget */ PlayerNameSpinner* m_player_ident_spinner; + GUIEngine::KartStatsWidget* m_kart_stats; GUIEngine::ModelViewWidget* m_model_view; GUIEngine::LabelWidget* m_kart_name; diff --git a/src/states_screens/network_kart_selection.cpp b/src/states_screens/network_kart_selection.cpp index 66575978e..10dd6a750 100644 --- a/src/states_screens/network_kart_selection.cpp +++ b/src/states_screens/network_kart_selection.cpp @@ -146,6 +146,7 @@ void NetworkKartSelectionScreen::playerSelected(uint8_t race_id, std::string kar assert(widget_id>=0 && widget_id < m_kart_widgets.size()); KartSelectionScreen::updateKartWidgetModel(widget_id, kart_name, irr::core::stringw(kart_name.c_str())); + KartSelectionScreen::updateKartStats(widget_id, kart_name); m_kart_widgets[widget_id].setKartInternalName(kart_name); m_kart_widgets[widget_id].markAsReady(); // mark player ready } diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index 0018cc5ed..b808ce6df 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -97,13 +97,22 @@ const core::vector3df& TrackObjectPresentationSceneNode::getScale() const void TrackObjectPresentationSceneNode::move(const core::vector3df& xyz, const core::vector3df& hpr, - const core::vector3df& scale) + const core::vector3df& scale) { if (m_node == NULL) return; - m_node->setPosition(xyz); + if (m_node->getParent() != NULL) + { + scene::ISceneNode* parent = m_node->getParent(); + m_node->setPosition((xyz - parent->getAbsolutePosition()) / parent->getScale()); + } + else + { + m_node->setPosition(xyz); + } m_node->setRotation(hpr); m_node->setScale(scale); + m_node->updateAbsolutePosition(); } void TrackObjectPresentationSceneNode::setEnable(bool enabled) diff --git a/tools/batch.py b/tools/batch.py new file mode 100644 index 000000000..5cb78e0be --- /dev/null +++ b/tools/batch.py @@ -0,0 +1,103 @@ +from matplotlib import pyplot +from os import listdir + + +def is_numeric(x): + try: + float(x) + except ValueError: + return False + return True + + +avg_lap_time = {} +avg_pos = {} +avg_speed = {} +avg_top = {} +total_rescued = {} + +tests = len(listdir('../../batch'))-1 +for file in listdir('../../batch'): + if (file == '.DS_Store'): + continue + f = open('../../batch/'+file,'r') + + + ''' + name_index = file.find('.') + kart_name = str(file[:name_index]) + first = file.find('.',name_index+1) + track_name = file[name_index+1:first] + second = file.find('.',first+1) + run = int(file[first+1:second]) + ''' + track_name = "snowmountain" + kart_names = ["gnu", "sara", "tux", "elephpant"] + + if track_name == "snowmountain": + contents = f.readlines() + ''' + contents = contents[2:contents.index("[debug ] profile: \n")-1] + content = [s for s in contents if kart_name in s] + data = [float(x) for x in content[0].split() if is_numeric(x)] + if kart_name not in avg_lap_time: + avg_lap_time[kart_name] = [] + avg_pos[kart_name] = [] + avg_speed[kart_name] = [] + avg_top[kart_name] = [] + total_rescued[kart_name] = [] + + avg_lap_time[kart_name].append(data[2]/4) + avg_pos[kart_name].append(data[1]) + avg_speed[kart_name].append(data[3]) + avg_top[kart_name].append(data[4]) + total_rescued[kart_name].append(data[7]) + ''' + + contents = contents[2:6] #TODO check if all is in here + for kart in kart_names: + content = [s for s in contents if kart in s] + data = [float(x) for x in content[0].split() if is_numeric(x)] + if kart not in avg_lap_time: + avg_lap_time[kart] = [] + avg_pos[kart] = [] + avg_speed[kart] = [] + avg_top[kart] = [] + total_rescued[kart] = [] + + avg_lap_time[kart].append(data[2]/4) + avg_pos[kart].append(data[1]) + avg_speed[kart].append(data[3]) + avg_top[kart].append(data[4]) + total_rescued[kart].append(data[7]) + +tests = len(avg_lap_time["gnu"]) +print total_rescued + + +for kart in kart_names: + print "rescues for ", kart , ": ", sum(total_rescued[kart])/tests + print "avg_lap_time for " , kart , ": " , sum(avg_lap_time[kart])/tests + print "avg_pos for " , kart , ": " , sum(avg_pos[kart])/tests + print "avg_speed for " , kart , ": " , sum(avg_speed[kart])/tests + print "avg_top for " , kart , ": " , sum(avg_top[kart])/tests + + +pyplot.subplot(2,2,1) +pyplot.plot(list(xrange(tests)),avg_pos["gnu"], "b-") +pyplot.xlabel("tests") +pyplot.ylabel("gnu") +pyplot.subplot(2,2,2) +pyplot.plot(list(xrange(tests)),avg_pos["sara"], "r-") +pyplot.xlabel("tests") +pyplot.ylabel("sara") +pyplot.subplot(2,2,3) +pyplot.plot(list(xrange(tests)),avg_pos["elephpant"], "y-") +pyplot.xlabel("tests") +pyplot.ylabel("elephpant") +pyplot.subplot(2,2,4) +pyplot.plot(list(xrange(tests)),avg_pos["tux"], "g-") +pyplot.xlabel("tests") +pyplot.ylabel("tux") + +pyplot.show() diff --git a/tools/test.sh b/tools/test.sh new file mode 100755 index 000000000..d46ab8117 --- /dev/null +++ b/tools/test.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +mkdir -p ../../batch +#tracks='snowmountain city lighthouse olivermath hacienda startrack farm zengarden' +#karts='gnu tux sara elephpant' +laps=4 + +#for track in $tracks; do + #for kart in $karts; do + for run in {901..1500}; do + for lap in $laps; do + ./../cmake_build/bin/supertuxkart.app/Contents/MacOS/supertuxkart -R --mode=3 --numkarts=4 --track=snowmountain --with-profile --profile-laps=4 --kart=gnu --ai=sara,tux,elephpant --no-graphics > /dev/null + #./cmake_build/bin/supertuxkart.app/Contents/MacOS/supertuxkart -R --mode=3 --numkarts=4 --track=$track --with-profile --profile-laps=$lap --kart=$kart --ai=beastie,beastie,beastie --no-graphics > /dev/null + #grep "profile" ~/Library/Application\ Support/SuperTuxKart/stdout.log > ../batch/$kart.$track.$run.txt + grep "profile" ~/Library/Application\ Support/SuperTuxKart/stdout.log > ../../batch/faceoff.$run.txt + done + done +# done +#done \ No newline at end of file