// // SuperTuxKart - a fun racing game with go-kart // Copyright (C) 2006-2015 Joerg Henrichs // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 3 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "config/stk_config.hpp" #include #include #include #include "audio/music_information.hpp" #include "io/file_manager.hpp" #include "io/xml_node.hpp" #include "items/item.hpp" #include "karts/kart_properties.hpp" #include "utils/log.hpp" STKConfig* stk_config=0; float STKConfig::UNDEFINED = -99.9f; //----------------------------------------------------------------------------- /** Constructor, which only initialises the object. The actual work is done * by calling load(). */ STKConfig::STKConfig() { m_has_been_loaded = false; m_title_music = NULL; m_default_kart_properties = new KartProperties(); } // STKConfig //----------------------------------------------------------------------------- STKConfig::~STKConfig() { if(m_title_music) delete m_title_music; 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 //----------------------------------------------------------------------------- /** Loads the stk configuration file. After loading it checks if all necessary * values are actually defined, otherwise an error message is printed and STK * is aborted. * /param filename Name of the configuration file to load. */ void STKConfig::load(const std::string &filename) { // Avoid loading the default config file if a user-specific // config file has already been loaded. if(m_has_been_loaded) return; m_has_been_loaded = true; init_defaults(); XMLNode *root = 0; try { root = new XMLNode(filename); if(!root || root->getName()!="config") { if(root) delete root; std::ostringstream msg; msg << "Couldn't load config '" << filename << "': no config node."; throw std::runtime_error(msg.str()); } getAllData(root); } catch(std::exception& err) { Log::error("StkConfig", "FATAL ERROR while reading '%s':", filename.c_str()); Log::fatal("StkConfig", " %s", err.what()); } delete root; // Check that all necessary values are indeed set // ----------------------------------------------- #define CHECK_NEG( a,strA) if(a<=UNDEFINED) { \ Log::fatal("StkConfig", "Missing default value for '%s' in '%s'.", \ strA,filename.c_str()); \ } if(m_score_increase.size()==0) { Log::fatal("StkConfig", "Not or not enough scores defined in stk_config"); } if(m_leader_intervals.size()==0) { Log::fatal("StkConfig", "No follow leader interval(s) defined in stk_config"); } if(m_switch_items.size()!=Item::ITEM_LAST-Item::ITEM_FIRST+1) { Log::fatal("StkConfig", "Wrong number of item switches defined in stk_config"); } if (m_positional_smoothing.size() == 0) { Log::fatal("StkConfig", "No positional smoothing defined in stk_config."); } if (m_rotational_smoothing.size() == 0) { Log::fatal("StkConfig", "No rotationalsmoothing defined in stk_config."); } if (m_client_port == 0 || m_server_port == 0 || m_server_discovery_port == 0 || m_client_port == m_server_port || m_client_port == m_server_discovery_port || m_server_port == m_server_discovery_port) { Log::fatal("StkConfig", "Invalid default port values."); } CHECK_NEG(m_max_karts, "" ); CHECK_NEG(m_max_kart_version, "" ); CHECK_NEG(m_min_track_version, "min-track-version" ); CHECK_NEG(m_max_track_version, "max-track-version" ); CHECK_NEG(m_min_server_version, "min-server-version" ); CHECK_NEG(m_max_server_version, "max-server-version" ); CHECK_NEG(m_skid_fadeout_time, "skid-fadeout-time" ); CHECK_NEG(m_near_ground, "near-ground" ); CHECK_NEG(m_delay_finish_time, "delay-finish-time" ); CHECK_NEG(m_music_credit_time, "music-credit-time" ); CHECK_NEG(m_leader_time_per_kart, "leader time-per-kart" ); CHECK_NEG(m_penalty_ticks, "penalty-time" ); CHECK_NEG(m_max_display_news, "max-display-news" ); CHECK_NEG(m_replay_max_frames, "replay max-frames" ); CHECK_NEG(m_replay_delta_steering, "replay delta-steering" ); CHECK_NEG(m_replay_delta_speed, "replay delta-speed " ); CHECK_NEG(m_replay_dt, "replay delta-t" ); CHECK_NEG(m_minimap_size, "minimap size" ); CHECK_NEG(m_minimap_ai_icon, "minimap ai_icon" ); CHECK_NEG(m_minimap_player_icon, "minimap player_icon" ); CHECK_NEG(m_smooth_angle_limit, "physics smooth-angle-limit" ); CHECK_NEG(m_default_track_friction, "physics default-track-friction"); CHECK_NEG(m_physics_fps, "physics fps" ); CHECK_NEG(m_network_state_frequeny, "network state-frequency" ); CHECK_NEG(m_default_moveable_friction, "physics default-moveable-friction"); // Square distance to make distance checks cheaper (no sqrt) m_default_kart_properties->checkAllSet(filename); } // load // ----------------------------------------------------------------------------- /** Init all values with invalid defaults, which are tested later. This * guarantees that all parameters will indeed be initialised, and helps * finding typos. */ void STKConfig::init_defaults() { m_bomb_time = m_bomb_time_increase = m_explosion_impulse_objects = m_music_credit_time = m_delay_finish_time = m_skid_fadeout_time = m_near_ground = m_smooth_angle_limit = m_default_track_friction = m_default_moveable_friction = UNDEFINED; m_item_switch_ticks = -100; m_penalty_ticks = -100; m_physics_fps = -100; m_bubblegum_counter = -100; m_shield_restrict_weapons = false; m_max_karts = -100; m_max_skidmarks = -100; m_min_kart_version = -100; m_max_kart_version = -100; m_min_track_version = -100; m_max_track_version = -100; m_min_server_version = -100; m_max_server_version = -100; m_max_display_news = -100; m_replay_max_frames = -100; m_replay_delta_steering = -100; m_replay_delta_speed = -100; m_replay_dt = -100; m_minimap_size = -100; m_minimap_ai_icon = -100; m_minimap_player_icon = -100; m_network_state_frequeny = -100; m_title_music = NULL; m_smooth_normals = false; m_same_powerup_mode = POWERUP_MODE_ONLY_IF_SAME; m_ai_acceleration = 1.0f; m_disable_steer_while_unskid = false; m_camera_follow_skid = false; m_cutscene_fov = 0.61f; m_max_skinning_bones = 1024; m_tc_quality = 16; m_server_discovery_port = 2757; m_client_port = 2758; m_server_port = 2759; m_score_increase.clear(); m_leader_intervals.clear(); m_switch_items.clear(); m_normal_ttf.clear(); m_digit_ttf.clear(); } // init_defaults //----------------------------------------------------------------------------- /** Extracts the actual information from a xml file. * \param xml Pointer to the xml data structure. */ void STKConfig::getAllData(const XMLNode * root) { // Get the values which are not part of the default KartProperties // --------------------------------------------------------------- if(const XMLNode *kart_node = root->getNode("kart-version")) { kart_node->get("min", &m_min_kart_version); kart_node->get("max", &m_max_kart_version); } if(const XMLNode *node = root->getNode("track-version")) { node->get("min", &m_min_track_version); node->get("max", &m_max_track_version); } if(const XMLNode *node = root->getNode("server-version")) { node->get("min", &m_min_server_version); node->get("max", &m_max_server_version); } if(const XMLNode *kart_node = root->getNode("karts")) kart_node->get("max-number", &m_max_karts); if(const XMLNode *gp_node = root->getNode("grand-prix")) { for(unsigned int i=0; igetNumNodes(); i++) { const XMLNode *pn=gp_node->getNode(i); int points=-1; pn->get("points", &points); if(points<0) { Log::error("StkConfig", "Incorrect GP point specification:"); Log::fatal("StkConfig", "points: %d", points); } m_score_increase.push_back(points); } if (m_max_karts > int(gp_node->getNumNodes())) { Log::error("StkConfig", "Not enough grand-prix ranking nodes:"); m_score_increase.resize(m_max_karts, 0); } } if(const XMLNode *leader_node= root->getNode("follow-the-leader")) { leader_node->get("intervals", &m_leader_intervals ); leader_node->get("time-per-kart", &m_leader_time_per_kart); } if (const XMLNode *physics_node= root->getNode("physics")) { physics_node->get("smooth-normals", &m_smooth_normals ); physics_node->get("smooth-angle-limit", &m_smooth_angle_limit ); physics_node->get("default-track-friction", &m_default_track_friction); physics_node->get("default-moveable-friction", &m_default_moveable_friction); physics_node->get("fps", &m_physics_fps ); } if (const XMLNode *startup_node= root->getNode("startup")) { float f; startup_node->get("penalty", &f); m_penalty_ticks = time2Ticks(f); } if (const XMLNode *news_node= root->getNode("news")) { news_node->get("max-display", &m_max_display_news); } if (const XMLNode *steer_node= root->getNode("steer")) { steer_node->get("disable-while-unskid", &m_disable_steer_while_unskid); steer_node->get("camera-follow-skid", &m_camera_follow_skid ); } if (const XMLNode *camera = root->getNode("camera")) { camera->get("fov-1", &m_camera_fov[0]); camera->get("fov-2", &m_camera_fov[1]); camera->get("fov-3", &m_camera_fov[2]); camera->get("fov-4", &m_camera_fov[3]); for (unsigned int i = 4; i < MAX_PLAYER_COUNT; i++) { camera->get("fov-4", &m_camera_fov[i]); } camera->get("cutscene-fov", &m_cutscene_fov); } if (const XMLNode *music_node = root->getNode("music")) { std::string title_music; music_node->get("title", &title_music); assert(title_music.size() > 0); title_music = file_manager->getAsset(FileManager::MUSIC, title_music); m_title_music = MusicInformation::create(title_music); if(!m_title_music) Log::error("StkConfig", "Cannot load title music : %s", title_music.c_str()); } if(const XMLNode *skidmarks_node = root->getNode("skid-marks")) { skidmarks_node->get("max-number", &m_max_skidmarks ); skidmarks_node->get("fadeout-time", &m_skid_fadeout_time); } if(const XMLNode *near_ground_node = root->getNode("near-ground")) near_ground_node->get("distance", &m_near_ground); if(const XMLNode *delay_finish_node= root->getNode("delay-finish")) delay_finish_node->get("time", &m_delay_finish_time); if(const XMLNode *credits_node= root->getNode("credits")) credits_node->get("music", &m_music_credit_time); if(const XMLNode *bomb_node= root->getNode("bomb")) { bomb_node->get("time", &m_bomb_time); bomb_node->get("time-increase", &m_bomb_time_increase); } if(const XMLNode *powerup_node= root->getNode("powerup")) { std::string s; powerup_node->get("collect-mode", &s); if(s=="same") m_same_powerup_mode = POWERUP_MODE_SAME; else if(s=="new") m_same_powerup_mode = POWERUP_MODE_NEW; else if(s=="only-if-same") m_same_powerup_mode = POWERUP_MODE_ONLY_IF_SAME; else { Log::warn("StkConfig", "Invalid item mode '%s' - ignored.", s.c_str()); } } if(const XMLNode *switch_node= root->getNode("switch")) { switch_node->get("items", &m_switch_items ); float f; if( switch_node->get("time", &f) ) m_item_switch_ticks = stk_config->time2Ticks(f); } if(const XMLNode *bubblegum_node= root->getNode("bubblegum")) { bubblegum_node->get("disappear-counter", &m_bubblegum_counter ); bubblegum_node->get("restrict-weapons", &m_shield_restrict_weapons); } if(const XMLNode *explosion_node= root->getNode("explosion")) { explosion_node->get("impulse-objects", &m_explosion_impulse_objects); } if(const XMLNode *ai_node = root->getNode("ai")) { ai_node->get("acceleration", &m_ai_acceleration); } if (const XMLNode *networking_node = root->getNode("networking")) { networking_node->get("state-frequency", &m_network_state_frequeny); networking_node->get("positional-smoothing", &m_positional_smoothing ); networking_node->get("rotational-smoothing", &m_rotational_smoothing ); } if(const XMLNode *replay_node = root->getNode("replay")) { replay_node->get("delta-steering", &m_replay_delta_steering); replay_node->get("delta-speed", &m_replay_delta_speed ); replay_node->get("delta-t", &m_replay_dt ); replay_node->get("max-frames", &m_replay_max_frames ); } if(const XMLNode *replay_node = root->getNode("minimap")) { replay_node->get("size", &m_minimap_size ); replay_node->get("ai-icon", &m_minimap_ai_icon ); replay_node->get("player-icon", &m_minimap_player_icon ); } if (const XMLNode *fonts_list = root->getNode("fonts-list")) { fonts_list->get("normal-ttf", &m_normal_ttf); fonts_list->get("digit-ttf", &m_digit_ttf ); } if (const XMLNode *skinning = root->getNode("skinning")) { skinning->get("max-bones", &m_max_skinning_bones); } if (const XMLNode *tc = root->getNode("texture-compression")) { tc->get("quality", &m_tc_quality); } if (const XMLNode *tc = root->getNode("network")) { unsigned server_discovery_port = 0; unsigned client_port = 0; unsigned server_port = 0; tc->get("server-discovery-port", &server_discovery_port); tc->get("client-port", &client_port); tc->get("server-port", &server_port); m_server_discovery_port = (uint16_t)server_discovery_port; m_client_port = (uint16_t)client_port; m_server_port = (uint16_t)server_port; } // Get the default KartProperties // ------------------------------ const XMLNode *node = root -> getNode("general-kart-defaults"); if(!node) { std::ostringstream msg; msg << "Couldn't load general-kart-defaults: no node."; throw std::runtime_error(msg.str()); } m_default_kart_properties->getAllData(node); const XMLNode *child_node = node->getNode("kart-type"); for (unsigned int i = 0; i < child_node->getNumNodes(); ++i) { const XMLNode* type = child_node->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 // ---------------------------------------------------------------------------- /** Defines the points for each position for a race with a given number * of karts. * \param all_scores A vector which will be resized to take num_karts * elements and which on return contains the number of points * for each position. * \param num_karts Number of karts. */ void STKConfig::getAllScores(std::vector *all_scores, int num_karts) { std::vector sorted_score_increase; if (num_karts == 0) return; assert(num_karts <= m_max_karts); all_scores->resize(num_karts); sorted_score_increase.resize(num_karts+1); //sorting function is [begin, end[ //get increase data into sorted_score_increase for(int i=0; i=0; i--) { (*all_scores)[i] = (*all_scores)[i+1] + sorted_score_increase[num_karts-i]; } } // getAllScores