// $Id$ // // SuperTuxKart - a fun racing game with go-kart // Copyright (C) 2004-2006 Ingo Ruhnke // // 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 "karts/kart_properties_manager.hpp" #include #include #include #include #include #include "challenges/unlock_manager.hpp" #include "config/stk_config.hpp" #include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/engine.hpp" #include "io/file_manager.hpp" #include "karts/kart_properties.hpp" #include "utils/string_utils.hpp" KartPropertiesManager *kart_properties_manager=0; std::vector KartPropertiesManager::m_kart_search_path; /** Constructor, only clears internal data structures. */ KartPropertiesManager::KartPropertiesManager() { m_all_groups.clear(); } // KartPropertiesManager //----------------------------------------------------------------------------- /** Destructor. Removes all allocated data. */ KartPropertiesManager::~KartPropertiesManager() { } // ~KartPropertiesManager //----------------------------------------------------------------------------- /** Adds a directory from which karts are loaded. The kart manager checks if * either this directory itself contains a kart, and if any subdirectory * contains a kart. * \param dir The directory to add. */ void KartPropertiesManager::addKartSearchDir(const std::string &s) { m_kart_search_path.push_back(s); } // addKartSearchDir //----------------------------------------------------------------------------- void KartPropertiesManager::unloadAllKarts() { m_karts_properties.clearAndDeleteAll(); m_selected_karts.clear(); m_kart_available.clear(); m_groups_2_indices.clear(); m_all_groups.clear(); m_kart_search_path.clear(); } // unloadAllKarts //----------------------------------------------------------------------------- /** Reloads all karts, i.e. reloads the meshes and textures. This is used * when changing the screen resolution. */ void KartPropertiesManager::reLoadAllKarts() { m_karts_properties.clearAndDeleteAll(); m_selected_karts.clear(); m_kart_available.clear(); m_groups_2_indices.clear(); m_all_groups.clear(); loadAllKarts(false); } // reLoadAllKarts //----------------------------------------------------------------------------- /** Remove a kart from the kart manager. * \param id The kart id (i.e. name of the directory) to remove. */ void KartPropertiesManager::removeKart(const std::string &ident) { // Remove the kart properties from the vector of all kart properties int index = getKartId(ident); const KartProperties *kp = getKart(ident); // must be done before remove m_karts_properties.remove(index); m_all_kart_dirs.erase(m_all_kart_dirs.begin()+index); m_kart_available.erase(m_kart_available.begin()+index); // Remove the just removed kart from the 'group-name to kart property // index' mapping. If a group is now empty (i.e. the removed kart was // the only member of this group), remove the group const std::vector &groups = kp->getGroups(); for (unsigned int i=0; i ::iterator it; it = std::find(m_groups_2_indices[groups[i]].begin(), m_groups_2_indices[groups[i]].end(), index); // Since we are iterating over all groups the kart belongs to, // there must be an entry found assert(it!=m_groups_2_indices[groups[i]].end()); m_groups_2_indices[groups[i]].erase(it); // Check if the last kart of a group was removed if(m_groups_2_indices[groups[i]].size()==0) { m_groups_2_indices.erase(groups[i]); std::vector::iterator its; its = std::find(m_all_groups.begin(), m_all_groups.end(), groups[i]); assert(its!=m_all_groups.end()); m_all_groups.erase(its); } // if m_groups_2_indices[groups[i]].size()==0) } // for i in all groups the kart belongs to // Adjust the indices of all kart properties in the 'group name to // kart property index' mapping: all kart properties with an index // greater than index were moved one position further to the beginning std::map >::iterator it_gr; for(it_gr=m_groups_2_indices.begin(); it_gr != m_groups_2_indices.end(); it_gr++) { for(unsigned int i=0; i<(*it_gr).second.size(); i++) { if( (*it_gr).second[i]>index) (*it_gr).second[i]--; } } delete kp; // Only used for networking only, and it is safe to just clear it. // If a networking game is started it will be initialised properly. m_selected_karts.clear(); } // removeKart //----------------------------------------------------------------------------- /** Loads all kart properties and models. */ void KartPropertiesManager::loadAllKarts(bool loading_icon) { m_all_kart_dirs.clear(); std::vector::const_iterator dir; for(dir = m_kart_search_path.begin(); dir!=m_kart_search_path.end(); dir++) { // First check if there is a kart in the current directory // ------------------------------------------------------- if(loadKart(*dir)) continue; // If not, check each subdir of this directory. // -------------------------------------------- std::set result; file_manager->listFiles(result, *dir, /*is_full_path*/ true); for(std::set::const_iterator subdir=result.begin(); subdir!=result.end(); subdir++) { const bool loaded = loadKart(*dir+"/"+*subdir); if (loaded && loading_icon) { GUIEngine::addLoadingIcon(irr_driver->getTexture( m_karts_properties[m_karts_properties.size()-1] .getAbsoluteIconFile() ) ); } } // for all files in the currently handled directory } // for i } // loadAllKarts //----------------------------------------------------------------------------- /** Loads a single kart and (if not disabled) the oorresponding 3d model. * \param filename Full path to the kart config file. */ bool KartPropertiesManager::loadKart(const std::string &dir) { std::string config_filename=dir+"/kart.xml"; FILE *f=fopen(config_filename.c_str(), "r"); if(!f) return false; fclose(f); KartProperties* kart_properties; try { kart_properties = new KartProperties(config_filename); } catch (std::runtime_error& err) { std::cerr << "Giving up loading '" << config_filename.c_str() << "' : " << err.what() << std::endl; return false; } // If the version of the kart file is not supported, // ignore this .kart file if (kart_properties->getVersion() < stk_config->m_min_kart_version || kart_properties->getVersion() > stk_config->m_max_kart_version) { fprintf(stderr, "[KartPropertiesManager] Warning: kart '%s' is not " "supported by this binary, ignored.\n", kart_properties->getIdent().c_str()); delete kart_properties; return false; } m_karts_properties.push_back(kart_properties); m_kart_available.push_back(true); const std::vector& groups=kart_properties->getGroups(); for(unsigned int g=0; ggetIdent() == ident) return kp; } return NULL; } // getKart //----------------------------------------------------------------------------- const KartProperties* KartPropertiesManager::getKartById(int i) const { if (i < 0 || i >= int(m_karts_properties.size())) return NULL; return m_karts_properties.get(i); } // getKartById //----------------------------------------------------------------------------- /** Returns a list of all available kart identifiers. */ std::vector KartPropertiesManager::getAllAvailableKarts() const { std::vector all; for (int i=0; i karts) { for (int i=0; i groups = m_karts_properties[i].getGroups(); if (std::find(groups.begin(), groups.end(), group) == groups.end()) continue; if (count == n) return i; count = count + 1; } return -1; } // getKartByGroup //----------------------------------------------------------------------------- bool KartPropertiesManager::testAndSetKart(int kartid) { if(!kartAvailable(kartid)) return false; m_selected_karts.push_back(kartid); return true; } // kartAvailable //----------------------------------------------------------------------------- /** Returns true if a kart is available to be selected. A kart is available to * be selected if it is available on all clients (i.e. m_kart_available is * true), not yet selected, and not locked. */ bool KartPropertiesManager::kartAvailable(int kartid) { if(kartid<0 || kartid>=(int)m_kart_available.size()) return false; if(!m_kart_available[kartid]) return false; std::vector::iterator it; for (it = m_selected_karts.begin(); it < m_selected_karts.end(); it++) { if ( kartid == *it) return false; } const KartProperties *kartprop = getKartById(kartid); if(unlock_manager->isLocked(kartprop->getIdent())) return false; return true; } // kartAvailable //----------------------------------------------------------------------------- /** Sets a kart to be selected by specifying the identifier (name) of the kart. * \param kart_name Name of the kart. */ void KartPropertiesManager::selectKartName(const std::string &kart_name) { int kart_id = getKartId(kart_name); selectKart(kart_id); } // selectKartName //----------------------------------------------------------------------------- /** Returns a vector with the indices of all karts in the specified group. * \param g The name of the group for which the kart indicies should be * determined * \return A vector of indices with the karts in the given group. */ const std::vector KartPropertiesManager::getKartsInGroup( const std::string& g) { if (g == ALL_KART_GROUPS_ID) { std::vector out; for (int n=0; n *ai_list) { // First: set up flags (based on global kart // index) for which karts are already used // ----------------------------------------- std::vector used; used.resize(getNumberOfKarts(), false); std::vector random_kart_queue; for (unsigned int i=0; isize(); i++) { try { int id=getKartId((*ai_list)[i]); used[id] = true; } catch (std::runtime_error &ex) { (void)ex; std::cerr << "[KartPropertiesManager] getRandomKartList : WARNING, " "can't find kart '" << (*ai_list)[i] << "'\n"; } } do { // if we have no karts left in our queue, re-fill it if (count > 0 && random_kart_queue.size() == 0) { random_kart_queue.clear(); std::vector karts_in_group = getKartsInGroup(UserConfigParams::m_last_used_kart_group); assert(karts_in_group.size() > 0); // first try not to use a kart already used by a player for (unsigned int i=0; iisLocked(kp.getIdent()) ) { random_kart_queue.push_back(kp.getIdent()); } } // if we really need to, reuse the same kart as the player if (random_kart_queue.size() == 0) { for (unsigned int i=0; i 0); std::random_shuffle(random_kart_queue.begin(), random_kart_queue.end() ); } while (count > 0 && random_kart_queue.size() > 0) { ai_list->push_back(random_kart_queue.back()); random_kart_queue.pop_back(); count --; } } while (count > 0); // There should always be enough karts assert(count==0); } // getRandomKartList /* EOF */