1 // 2 // SuperTuxKart - a fun racing game with go-kart 3 // Copyright (C) 2006-2015 Joerg Henrichs 4 // 5 // This program is free software; you can redistribute it and/or 6 // modify it under the terms of the GNU General Public License 7 // as published by the Free Software Foundation; either version 3 8 // of the License, or (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 #ifndef HEADER_POWERUPMANAGER_HPP 20 #define HEADER_POWERUPMANAGER_HPP 21 22 #include "utils/leak_check.hpp" 23 #include "utils/no_copy.hpp" 24 #include "utils/types.hpp" 25 26 #include "btBulletDynamicsCommon.h" 27 28 #include <atomic> 29 #include <map> 30 #include <string> 31 #include <vector> 32 33 class Material; 34 class XMLNode; 35 namespace irr 36 { 37 namespace scene { class IMesh; } 38 } 39 40 /** 41 * \ingroup items 42 */ 43 44 /** This class manages all powerups. It reads in powerup.xml to get the data, 45 * initialise the static member of some flyables (i.e. powerup.xml contains 46 * info about cakes, plunger etc which needs to be stored), and maintains 47 * the 'weights' (used in randomly chosing which item was collected) for all 48 * items depending on position. The latter is done so that as the first player 49 * you get less advantageous items (but no useless ones either), while as the 50 * last you get more useful ones. 51 * 52 * The weights distribution is described in the powerup.xml file in more 53 * detail. All weights are stored in the m_all_weights data structure, 54 * which maps the race mode (race, battle, ...) to a list of WeightsData 55 * instances. Each WeightsData instance stores the data for one specific 56 * number of karts. E.g. m_all_weights['race'] contains 5 WeightsData 57 * instances for 1, 5, 9, 14, and 20 karts. 58 * At race start a new instance of WeightsData is created in 59 * m_current_item_weights. It contains the interpolated values for the 60 * number of karts in the current race (e.g. if the race is with 6 karts 61 * if will use 3/4 the weights for 5 karts, and 1/4 the weights for 9 karts. 62 * Then m_current_item_weights will create a weight distribution for each 63 * possible rank in the race (1 to 6 in the example above). This is the 64 * interpolation of the values within one WeightsData. Atm there are also 65 * 5 entries in that list (though it does not have to be the same number 66 * as above - i.e. the 1, 5, 9, 14, 20 weights list). Similarly the actual 67 * distribution used for a kart with a specific rank is based on dividing 68 * the available ranks (so 6 karts --> 6 ranks). With the 5 specified values 69 * the first entry is used for rank 1, the last entry for rank 6, and ranks 70 * 2-5 will be interpolated based on an equal distance: in a race with 6 71 * karts for example, the 2nd weight list is used for rank 2.25, the 3nd 72 * for rank 3.5, the 4th for rank 4.75 (and the first and last for rank 1 73 * and 6). It does not matter that the ranks are non integer: the actual 74 * weights used for say rank 2, will then be interplated between the weights 75 * of rank 1 and 2.25 (e.g. 0.8*weights_for 2.25 + 0.2*weights_for 1). 76 */ 77 78 class PowerupManager : public NoCopy 79 { 80 public: 81 LEAK_CHECK(); 82 private: 83 // ------------------------------------------------------------------------ 84 /** This object stores all the weights for one particular number of 85 * karts. I.e. it has a list of all the weights within the number of karts. 86 */ 87 class WeightsData 88 { 89 private: 90 /** The number of karts for which this entry is to be used. */ 91 unsigned int m_num_karts; 92 93 /** Stores for each of the sections the weights from the XML file. */ 94 std::vector < std::vector<int> > m_weights_for_section; 95 96 /** This field is only populated for the WeightData class that 97 * is used during a race. It contains for each rank the summed 98 * weights for easy lookup during a race. */ 99 std::vector < std::vector<unsigned> > m_summed_weights_for_rank; 100 101 public: 102 // The friend declaration gives the PowerupManager access to the 103 // internals, which is ONLY used for testing!! 104 friend PowerupManager; WeightsData()105 WeightsData() { m_num_karts = 0; } 106 void reset(); 107 void readData(int num_karts, const XMLNode *node); 108 void interpolate(WeightsData *prev, WeightsData *next, int num_karts); 109 void convertRankToSection(int rank, int *prev, int *next, 110 float *weight); 111 void precomputeWeights(); 112 int getRandomItem(int rank, uint64_t random_number); 113 // -------------------------------------------------------------------- 114 /** Sets the number of karts. */ setNumKarts(int num_karts)115 void setNumKarts(int num_karts) { m_num_karts = num_karts; } 116 // -------------------------------------------------------------------- 117 /** Returns for how many karts this entry is meant for. */ getNumKarts() const118 int getNumKarts() const { return m_num_karts; } 119 }; // class WeightsData 120 // ------------------------------------------------------------------------ 121 122 /** The first key is the race type: race, battle, soccer etc. 123 * The key then contains a mapping from the kart numbers to the 124 * WeightsData object that stores all data for the give kart number. 125 */ 126 std::map<std::string, std::vector<WeightsData*> > m_all_weights; 127 128 public: 129 // The anvil and parachute must be at the end of the enum, and the 130 // zipper just before them (see Powerup::hitBonusBox). 131 enum PowerupType {POWERUP_NOTHING, 132 POWERUP_FIRST, 133 POWERUP_BUBBLEGUM = POWERUP_FIRST, 134 POWERUP_CAKE, 135 POWERUP_BOWLING, POWERUP_ZIPPER, POWERUP_PLUNGER, 136 POWERUP_SWITCH, POWERUP_SWATTER, POWERUP_RUBBERBALL, 137 POWERUP_PARACHUTE, 138 POWERUP_ANVIL, //powerup.cpp assumes these two come last 139 POWERUP_LAST=POWERUP_ANVIL, 140 POWERUP_MAX 141 }; 142 143 private: 144 145 /** The icon for each powerup. */ 146 Material* m_all_icons [POWERUP_MAX]; 147 148 /** The mesh for each model (if the powerup has a model), e.g. a switch 149 has none. */ 150 irr::scene::IMesh *m_all_meshes[POWERUP_MAX]; 151 152 /** The weight distribution to be used for the current race. */ 153 WeightsData m_current_item_weights; 154 155 PowerupType getPowerupType(const std::string &name) const; 156 157 /** Seed for random powerup, for local game it will use a random number, 158 * for network games it will use the start time from server. */ 159 std::atomic<uint64_t> m_random_seed; 160 161 public: 162 static void unitTesting(); 163 164 PowerupManager (); 165 ~PowerupManager (); 166 void loadPowerupsModels (); 167 void loadWeights(const XMLNode *node, const std::string &category); 168 void unloadPowerups (); 169 void computeWeightsForRace(int num_karts); 170 void loadPowerup (PowerupType type, const XMLNode &node); 171 PowerupManager::PowerupType 172 getRandomPowerup(unsigned int pos, unsigned int *n, 173 uint64_t random_number); 174 // ------------------------------------------------------------------------ 175 /** Returns the icon(material) for a powerup. */ getIcon(int type) const176 Material* getIcon(int type) const {return m_all_icons [type];} 177 // ------------------------------------------------------------------------ 178 /** Returns the mesh for a certain powerup. 179 * \param type Mesh type for which the model is returned. */ getMesh(int type) const180 irr::scene::IMesh *getMesh(int type) const {return m_all_meshes[type];} 181 // ------------------------------------------------------------------------ getRandomSeed() const182 uint64_t getRandomSeed() const { return m_random_seed.load(); } 183 // ------------------------------------------------------------------------ setRandomSeed(uint64_t seed)184 void setRandomSeed(uint64_t seed) { m_random_seed.store(seed); } 185 186 }; // class PowerupManager 187 188 extern PowerupManager* powerup_manager; 189 190 #endif 191