diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp index 4ee7e1303..71923cae6 100644 --- a/src/config/stk_config.cpp +++ b/src/config/stk_config.cpp @@ -69,10 +69,10 @@ void STKConfig::load(const std::string &filename) catch(std::exception& err) { - fprintf(stderr, "Error while parsing KartProperties '%s':\n", - filename.c_str()); - fprintf(stderr, "%s", err.what()); + fprintf(stderr, "FATAL ERROR while reading StkConfig '%s':\n", filename.c_str()); + fprintf(stderr, " %s", err.what()); fprintf(stderr, "\n"); + exit(1); } delete root; diff --git a/src/config/user_config.cpp b/src/config/user_config.cpp index 543b3d779..19c87e6ab 100644 --- a/src/config/user_config.cpp +++ b/src/config/user_config.cpp @@ -423,7 +423,7 @@ void UserConfig::addDefaultPlayer() class GuestPlayerProfile : public PlayerProfile { public: - GuestPlayerProfile() : PlayerProfile(_("Guest")) + GuestPlayerProfile() : PlayerProfile(L"Guest") { m_is_guest_account = true; } diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index 9e9bc2854..953348fe5 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -204,6 +204,9 @@ public: float& operator=(const FloatUserConfigParam& v) { m_value = (float)v; return m_value; } }; +const int ANIMS_NONE = 0; +const int ANIMS_PLAYERS_ONLY = 1; +const int ANIMS_ALL = 2; /** * Using X-macros for setting-possible values is not very pretty, but it's a no-maintenance case : @@ -276,8 +279,10 @@ namespace UserConfigParams PARAM_PREFIX BoolUserConfigParam m_weather_effects PARAM_DEFAULT( BoolUserConfigParam(true, "weather_gfx", &m_video_group) ); - PARAM_PREFIX BoolUserConfigParam m_show_steering_animations - PARAM_DEFAULT( BoolUserConfigParam(true, "steering_animations", &m_video_group, "Display steering animations in race") ); + PARAM_PREFIX IntUserConfigParam m_show_steering_animations + PARAM_DEFAULT( IntUserConfigParam(ANIMS_ALL, "steering_animations", &m_video_group, + "Whether to display kart animations (0=disabled for all; " + "1=disabled for humans, disabled for AIs; 2=enabled for all") ); PARAM_PREFIX BoolUserConfigParam m_display_fps PARAM_DEFAULT( BoolUserConfigParam(false, "show_fps", &m_video_group, "Display frame per seconds") ); @@ -326,6 +331,7 @@ namespace UserConfigParams PARAM_DEFAULT( IntUserConfigParam(2305, "server_port", "Information about last server used") ); // ---- Graphic Quality + // FIXME: those are probably not needed... PARAM_PREFIX GroupUserConfigParam m_graphics_quality PARAM_DEFAULT( GroupUserConfigParam("GFX", "Graphics Quality Settings") ); @@ -334,7 +340,7 @@ namespace UserConfigParams "Whether anisotropic filtering is allowed to be used (true or false)") ); PARAM_PREFIX BoolUserConfigParam m_trilinear PARAM_DEFAULT( BoolUserConfigParam(true, "trilinear", &m_graphics_quality, - "Whether trilinear filtering is allowed to be used (true or false)") ); + "Whether trilinear filtering is allowed to be used (true or false)") ); // ---- Misc diff --git a/src/io/file_manager.cpp b/src/io/file_manager.cpp index f793311b2..ce9795ba4 100644 --- a/src/io/file_manager.cpp +++ b/src/io/file_manager.cpp @@ -231,11 +231,16 @@ io::IXMLReader *FileManager::createXMLReader(const std::string &filename) */ XMLNode *FileManager::createXMLTree(const std::string &filename) { - io::IXMLReader *xml_reader = createXMLReader(filename); - if(!xml_reader) return NULL; - XMLNode* node = new XMLNode(xml_reader); - xml_reader->drop(); - return node; + try + { + XMLNode* node = new XMLNode(filename); + return node; + } + catch (std::runtime_error& e) + { + fprintf(stderr, "[FileManager::createXMLTree] %s\n", e.what()); + return NULL; + } } // getXMLTree //----------------------------------------------------------------------------- diff --git a/src/io/xml_node.cpp b/src/io/xml_node.cpp index 72084972b..6b6202986 100644 --- a/src/io/xml_node.cpp +++ b/src/io/xml_node.cpp @@ -22,8 +22,12 @@ #include "utils/string_utils.hpp" #include "utils/vec3.hpp" +#include + XMLNode::XMLNode(io::IXMLReader *xml) { + m_file_name = "[unknown]"; + while(xml->getNodeType()!=io::EXN_ELEMENT && xml->read()); readXML(xml); } // XMLNode @@ -34,7 +38,15 @@ XMLNode::XMLNode(io::IXMLReader *xml) */ XMLNode::XMLNode(const std::string &filename) { + m_file_name = filename; + io::IXMLReader *xml = file_manager->createXMLReader(filename); + + if (xml == NULL) + { + throw std::runtime_error("Cannot find file "+filename); + } + bool is_first_element = true; while(xml->read()) { @@ -98,7 +110,9 @@ void XMLNode::readXML(io::IXMLReader *xml) switch (xml->getNodeType()) { case io::EXN_ELEMENT: - m_nodes.push_back(new XMLNode(xml)); + XMLNode* n = new XMLNode(xml); + n->m_file_name = m_file_name; + m_nodes.push_back(n); break; case io::EXN_ELEMENT_END: // End of this element found. @@ -255,9 +269,14 @@ int XMLNode::get(const std::string &attribute, int *value) const { std::string s; if(!get(attribute, &s)) return 0; - // FIXME: don't use "atoi", if the number in the attribute is not an int we want an error message, - // not silently return 0... easy to get bitten by this - *value = atoi(s.c_str()); + + if (!StringUtils::parseString(s, value)) + { + fprintf(stderr, "[XMLNode] WARNING: Expected int but found '%s' for attribute '%s' of node '%s' in file %s\n", + s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str()); + return 0; + } + return 1; } // get(int) @@ -266,7 +285,14 @@ int XMLNode::get(const std::string &attribute, unsigned int *value) const { std::string s; if(!get(attribute, &s)) return 0; - *value = atoi(s.c_str()); + + if (!StringUtils::parseString(s, value)) + { + fprintf(stderr, "[XMLNode] WARNING: Expected uint but found '%s' for attribute '%s' of node '%s' in file %s\n", + s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str()); + return 0; + } + return 1; } // get(unsigned int) @@ -275,7 +301,14 @@ int XMLNode::get(const std::string &attribute, float *value) const { std::string s; if(!get(attribute, &s)) return 0; - *value = (float)atof(s.c_str()); + + if (!StringUtils::parseString(s, value)) + { + fprintf(stderr, "[XMLNode] WARNING: Expected float but found '%s' for attribute '%s' of node '%s' in file %s\n", + s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str()); + return 0; + } + return 1; } // get(int) @@ -323,9 +356,19 @@ int XMLNode::get(const std::string &attribute, std::vector v = StringUtils::split(s,' '); value->clear(); - for(unsigned int i=0; ipush_back((float)atof(v[i].c_str())); + float curr; + if (!StringUtils::parseString(v[i], &curr)) + { + fprintf(stderr, "[XMLNode] WARNING: Expected float but found '%s' for attribute '%s' of node '%s' in file %s\n", + v[i].c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str()); + return 0; + } + + value->push_back(curr); } return value->size(); } // get(vector) @@ -344,9 +387,19 @@ int XMLNode::get(const std::string &attribute, std::vector *value) const std::vector v = StringUtils::split(s,' '); value->clear(); - for(unsigned int i=0; ipush_back(atoi(v[i].c_str())); + int val; + if (!StringUtils::parseString(v[i], &val)) + { + fprintf(stderr, "[XMLNode] WARNING: Expected int but found '%s' for attribute '%s' of node '%s'\n", + v[i].c_str(), attribute.c_str(), m_name.c_str()); + return 0; + } + + value->push_back(val); } return value->size(); } // get(vector) diff --git a/src/io/xml_node.hpp b/src/io/xml_node.hpp index f949752f6..f05aa1076 100644 --- a/src/io/xml_node.hpp +++ b/src/io/xml_node.hpp @@ -43,10 +43,17 @@ private: std::map m_attributes; /** List of all sub nodes. */ std::vector m_nodes; + void readXML(io::IXMLReader *xml); + + std::string m_file_name; + public: XMLNode(io::IXMLReader *xml); + + /** \throw runtime_error if the file is not found */ XMLNode(const std::string &filename); + ~XMLNode(); const std::string &getName() const {return m_name; } const XMLNode *getNode(const std::string &name) const; diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index d20a6410a..645c29a34 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -71,9 +71,10 @@ Kart::Kart (const std::string& ident, int position, #if defined(WIN32) && !defined(__CYGWIN__) # pragma warning(1:4355) #endif -{ - m_kart_properties = kart_properties_manager->getKart(ident); +{ + m_kart_properties = kart_properties_manager->getKart(ident); assert(m_kart_properties != NULL); + // We have to take a copy of the kart model, since otherwise // the animations will be mixed up (i.e. different instances of // the same model will set different animation frames). @@ -110,6 +111,8 @@ Kart::Kart (const std::string& ident, int position, m_speed = 0.0f; m_wheel_rotation = 0; + m_kart_model->setKart(this); + // Create SFXBase for each custom sound (TODO: add back when properly done) /* for (int n = 0; n < SFXManager::NUM_CUSTOMS; n++) diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index c98f72255..3fcd083d2 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -24,6 +24,7 @@ #include "graphics/irr_driver.hpp" #include "graphics/mesh_tools.hpp" #include "io/xml_node.hpp" +#include "karts/kart.hpp" #include "utils/constants.hpp" float KartModel::UNDEFINED = -99.9f; @@ -55,7 +56,8 @@ float KartModel::UNDEFINED = -99.9f; KartModel::KartModel(bool is_master) { m_is_master = is_master; - + m_kart = NULL; + for(unsigned int i=0; i<4; i++) { m_wheel_graphics_position[i] = Vec3(UNDEFINED); @@ -188,7 +190,21 @@ KartModel* KartModel::makeCopy() void KartModel::attachModel(scene::ISceneNode **node) { assert(!m_is_master); - if(UserConfigParams::m_show_steering_animations) + + bool animations = true; + + const int anims = UserConfigParams::m_show_steering_animations; + if (anims == ANIMS_NONE) + { + animations = false; + } + else if (anims == ANIMS_PLAYERS_ONLY && m_kart != NULL && m_kart->getController() != NULL && + !m_kart->getController()->isPlayerController()) + { + animations = false; + } + + if (animations) { *node = irr_driver->addAnimatedMesh(m_mesh); m_animated_node = static_cast(*node); @@ -202,6 +218,7 @@ void KartModel::attachModel(scene::ISceneNode **node) int straight_frame = m_animation_frame[AF_STRAIGHT]>=0 ? m_animation_frame[AF_STRAIGHT] : 0; + printf("straight_frame = %i\n", straight_frame); *node = irr_driver->addMesh(m_mesh->getMesh(straight_frame)); } #ifdef DEBUG @@ -239,7 +256,10 @@ bool KartModel::loadModels(const KartProperties &kart_properties) } else { - if (!UserConfigParams::m_show_steering_animations) + const int anims = UserConfigParams::m_show_steering_animations; + if (anims == ANIMS_NONE || + (anims == ANIMS_PLAYERS_ONLY && m_kart != NULL && m_kart->getController() != NULL && + !m_kart->getController()->isPlayerController())) { m_mesh->setHardwareMappingHint(scene::EHM_STATIC); } @@ -352,8 +372,11 @@ void KartModel::setDefaultPhysicsPosition(const Vec3 ¢er_shift, */ void KartModel::setAnimation(AnimationFrameType type) { - if(!UserConfigParams::m_show_steering_animations) return; - + const int anims = UserConfigParams::m_show_steering_animations; + if (anims == ANIMS_NONE) return; + if (m_kart != NULL && anims == ANIMS_PLAYERS_ONLY&& m_kart->getController() != NULL && + !m_kart->getController()->isPlayerController()) return; + m_current_animation = type; if(m_current_animation==AF_DEFAULT) { @@ -472,7 +495,10 @@ void KartModel::update(float rotation, float steer, const float suspension[4]) if(m_animation_frame[AF_LEFT]<0) return; // no animations defined - if(!UserConfigParams::m_show_steering_animations) return; + const int anims = UserConfigParams::m_show_steering_animations; + if (anims == ANIMS_NONE) return; + if (m_kart != NULL && anims == ANIMS_PLAYERS_ONLY && m_kart->getController() != NULL && + !m_kart->getController()->isPlayerController()) return; // Update animation if necessary // ----------------------------- diff --git a/src/karts/kart_model.hpp b/src/karts/kart_model.hpp index a3999a793..7f39195ae 100644 --- a/src/karts/kart_model.hpp +++ b/src/karts/kart_model.hpp @@ -28,6 +28,7 @@ using namespace irr; #include "utils/no_copy.hpp" #include "utils/vec3.hpp" +class Kart; class KartProperties; class XMLNode; @@ -130,6 +131,8 @@ private: void OnAnimationEnd(scene::IAnimatedMeshSceneNode *node); + Kart* m_kart; + public: KartModel(bool is_master); ~KartModel(); @@ -175,5 +178,8 @@ public: /** Enables- or disables the end animation. */ void setAnimation(AnimationFrameType type); + + /** Sets the kart this model is currently used for */ + void setKart(Kart* k) { m_kart = k; } }; // KartModel #endif diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index 0feb27bbf..4788d2a54 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -416,11 +416,14 @@ void KartProperties::getAllData(const XMLNode * root) plunger_node->get("in-face-time", &v); if(v.size()!=3) { - printf("Invalid plunger in-face-time specification."); + fprintf(stderr, "[KartProperties] ERROR: Invalid plunger in-face-time specification."); + } + else + { + m_plunger_in_face_duration[0] = v[0]; + m_plunger_in_face_duration[1] = v[1]; + m_plunger_in_face_duration[2] = v[2]; } - m_plunger_in_face_duration[0] = v[0]; - m_plunger_in_face_duration[1] = v[1]; - m_plunger_in_face_duration[2] = v[2]; } if(const XMLNode *zipper_node= root->getNode("zipper")) diff --git a/src/main.cpp b/src/main.cpp index 9e6154a93..857a73013 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -242,7 +242,7 @@ void cmdLineHelp (char* invocation) " (Default: 0, OpenGL: 1, Direct3D9: 2, \n" " Direct3D8: 3, Software: 4, \n" " Burning's Software: 5, Null device: 6).\n" - " --animations=n Play karts' animations (Enable: 1, Disable: 0).\n" + " --animations=n Play karts' animations (Enable for All : 2, Enable for humans only: 1, Disable for all: 0).\n" " --gfx=n Play other graphical effects like impact stars dance,\n" " water animations or explosions (Enable: 1, Disable: 0).\n" " --weather=n Show weather effects like rain or snow (0 or 1 as --gfx).\n" @@ -482,14 +482,7 @@ int handleCmdLine(int argc, char **argv) } else if ( sscanf(argv[i], "--animations=%d", &n) ) { - if (n) - { - UserConfigParams::m_show_steering_animations = true; - } - else - { - UserConfigParams::m_show_steering_animations = false; - } + UserConfigParams::m_show_steering_animations = n; } else if( (!strcmp(argv[i], "--kart") && i+1setController(controller); + return new_kart; } // createKart diff --git a/src/states_screens/options_screen_video.cpp b/src/states_screens/options_screen_video.cpp index 9274a7e0c..9fe967bb3 100644 --- a/src/states_screens/options_screen_video.cpp +++ b/src/states_screens/options_screen_video.cpp @@ -43,7 +43,7 @@ DEFINE_SCREEN_SINGLETON( OptionsScreenVideo ); // Look-up table for GFX levels const bool GFX [] = {false, true, true, true}; -const bool GFX_ANIM_KARTS[] = {false, false, true, true}; +const int GFX_ANIM_KARTS[] = {0, 0, 2, 2 }; // TODO: use new limited anims mode const bool GFX_WEATHER [] = {false, false, false, true}; const int GFX_LEVEL_AMOUNT = 4; diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index 8dbf53972..7c1007cd6 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -318,6 +318,26 @@ namespace StringUtils std::string s(chars); return insertValues(s, v1); } + + template + bool parseString(const char* input, T* output) + { + std::istringstream conv(input); + conv >> *output; + + // check reading worked correctly and everything was read + if (conv.fail() || !conv.eof()) + { + return false; + } + return true; + } + + template + bool parseString(const std::string& input, T* output) + { + return parseString(input.c_str(), output); + } } // namespace StringUtils