1 // SuperTuxKart - a fun racing game with go-kart
2 // Copyright (C) 2010-2015 Joerg Henrichs
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 3
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 #include "modes/world_with_rank.hpp"
19
20 #include "karts/abstract_kart.hpp"
21 #include "karts/controller/spare_tire_ai.hpp"
22 #include "karts/kart_properties.hpp"
23 #include "race/history.hpp"
24 #include "tracks/graph.hpp"
25 #include "tracks/track.hpp"
26 #include "tracks/track_sector.hpp"
27 #include "utils/log.hpp"
28
29 #include <iostream>
30
31 //-----------------------------------------------------------------------------
~WorldWithRank()32 WorldWithRank::~WorldWithRank()
33 {
34 for (unsigned int i = 0; i < m_kart_track_sector.size(); i++)
35 {
36 delete m_kart_track_sector[i];
37 }
38 m_kart_track_sector.clear();
39 } // ~WorldWithRank
40
41 //-----------------------------------------------------------------------------
init()42 void WorldWithRank::init()
43 {
44 World::init();
45
46 m_display_rank = true;
47
48 m_position_index.resize(m_karts.size());
49 #ifdef DEBUG
50 m_position_used.resize(m_karts.size());
51 m_position_setting_initialised = false;
52 #endif
53 stk_config->getAllScores(&m_score_for_position, getNumKarts());
54
55 Track *track = Track::getCurrentTrack();
56 // Don't init track sector if navmesh is not found in arena
57 if ((track->isArena() || track->isSoccer()) && !track->hasNavMesh())
58 return;
59
60 for (unsigned int i = 0; i < m_karts.size(); i++)
61 m_kart_track_sector.push_back(new TrackSector());
62
63 } // init
64
65 //-----------------------------------------------------------------------------
reset(bool restart)66 void WorldWithRank::reset(bool restart)
67 {
68 World::reset(restart);
69 for (unsigned int i = 0; i < m_kart_track_sector.size(); i++)
70 {
71 getTrackSector(i)->reset();
72 getTrackSector(i)->update(m_karts[i]->getXYZ());
73 }
74 } // reset
75
76 //-----------------------------------------------------------------------------
77 /** Returns the kart with a given position.
78 * \param p The position of the kart, 1<=p<=num_karts).
79 */
getKartAtPosition(unsigned int p) const80 AbstractKart* WorldWithRank::getKartAtPosition(unsigned int p) const
81 {
82 if(p<1 || p>m_position_index.size())
83 return NULL;
84
85 return m_karts[m_position_index[p-1]].get();
86 } // getKartAtPosition
87
88 //-----------------------------------------------------------------------------
89 /** This function must be called before starting to set all kart positions
90 * again. It's mainly used to add some debug support, i.e. detect if the
91 * same position is set in different karts.
92 */
beginSetKartPositions()93 void WorldWithRank::beginSetKartPositions()
94 {
95 #ifdef DEBUG
96 assert(!m_position_setting_initialised);
97 m_position_setting_initialised = true;
98
99 for(unsigned int i=0; i<m_position_used.size(); i++)
100 m_position_used[i] = false;
101 #endif
102 } // beginSetKartPositions
103
104 //-----------------------------------------------------------------------------
105 /** Sets the position of a kart. This will be saved in this object to allow
106 * quick lookup of which kart is on a given position, but also in the
107 * kart objects.
108 * \param kart_id The index of the kart to set the position for.
109 * \param position The position of the kart (1<=position<=num karts).
110 * \return false if this position was already set, i.e. an inconsistency in
111 * kart positions has occurred. This is used in debug mode only to
112 * allow the calling function to print debug information.
113 */
setKartPosition(unsigned int kart_id,unsigned int position)114 bool WorldWithRank::setKartPosition(unsigned int kart_id,
115 unsigned int position)
116 {
117 m_position_index[position-1] = kart_id;
118 m_karts[kart_id]->setPosition(position);
119 #ifdef DEBUG
120 assert(m_position_setting_initialised);
121 if(m_position_used[position-1])
122 {
123 Log::error("[WorldWithRank]", "== TWO KARTS ARE BEING GIVEN THE SAME POSITION!! ==");
124 for (unsigned int j=0; j < m_position_index.size(); j++)
125 {
126 if (!m_position_used[j])
127 {
128 Log::warn("WorldWithRank]", "No kart is yet set at position %u", j+1);
129 }
130 else
131 {
132 Log::warn("WorldWithRank]", "Kart %u is at position %u",
133 m_position_index[j], j);
134 }
135 }
136 Log::warn("WorldWithRank]", "Kart %u is being given position %u,"
137 "but this position is already taken",
138 kart_id, position);
139 return false;
140 }
141 m_position_used[position-1] = true;
142 #endif
143 return true;
144 } // setKartPosition
145
146 //-----------------------------------------------------------------------------
147 /** Called once the last position was set. Note that we should not test
148 * if all positions were set, since e.g. for eliminated and finished karts
149 * the position won't be set anymore.
150 */
endSetKartPositions()151 void WorldWithRank::endSetKartPositions()
152 {
153 #ifdef DEBUG
154 assert(m_position_setting_initialised);
155 m_position_setting_initialised = false;
156 #endif
157 } // endSetKartPositions
158
159 //-----------------------------------------------------------------------------
160 /** Determines the rescue position for a kart. The rescue position is the
161 * start position which is has the biggest accumulated distance to all other
162 * karts, and which has no other kart very close. The latter avoids dropping
163 * a kart on top of another kart. This is the method used
164 * \param kart The kart that is going to be rescued.
165 * \returns The index of the start position to which the rescued kart
166 * should be moved to.
167 */
168
getRescuePositionIndex(AbstractKart * kart)169 unsigned int WorldWithRank::getRescuePositionIndex(AbstractKart *kart)
170 {
171 const int start_spots_amount =
172 Track::getCurrentTrack()->getNumberOfStartPositions();
173 assert(start_spots_amount > 0);
174
175 float largest_accumulated_distance_found = -1;
176 int furthest_id_found = -1;
177
178 for(int n=0; n<start_spots_amount; n++)
179 {
180 const btTransform &s = getStartTransform(n);
181 const Vec3 &v=s.getOrigin();
182 float accumulated_distance = .0f;
183 bool spawn_point_clear = true;
184
185 for(unsigned int k=0; k<getCurrentNumKarts(); k++)
186 {
187 if(kart->getWorldKartId()==k) continue;
188 float abs_distance2 = (getKart(k)->getXYZ()-v).length2();
189 const float CLEAR_SPAWN_RANGE2 = 5*5;
190 if( abs_distance2 < CLEAR_SPAWN_RANGE2)
191 {
192 spawn_point_clear = false;
193 break;
194 }
195 accumulated_distance += sqrt(abs_distance2);
196 }
197
198 if(accumulated_distance > largest_accumulated_distance_found &&
199 spawn_point_clear)
200 {
201 furthest_id_found = n;
202 largest_accumulated_distance_found = accumulated_distance;
203 }
204 }
205
206 assert(furthest_id_found != -1);
207 return furthest_id_found;
208 } // getRescuePositionIndex
209
210 //-----------------------------------------------------------------------------
211 /** Returns the number of points for a kart at a specified position.
212 * \param p Position (starting with 1).
213 */
getScoreForPosition(int p)214 int WorldWithRank::getScoreForPosition(int p)
215 {
216 assert(p-1 >= 0);
217 assert(p - 1 <(int) m_score_for_position.size());
218 return m_score_for_position[p - 1];
219 } // getScoreForPosition
220
221 //-----------------------------------------------------------------------------
222 /** Returns true if the kart is on a valid graph quad.
223 * \param kart_index Index of the kart.
224 */
isOnRoad(unsigned int kart_index) const225 bool WorldWithRank::isOnRoad(unsigned int kart_index) const
226 {
227 return getTrackSector(kart_index)->isOnRoad();
228 } // isOnRoad
229
230 //-----------------------------------------------------------------------------
231 /** Gets the sector a kart is on. This function returns UNKNOWN_SECTOR if the
232 * kart_id is larger than the current kart sector. This is necessary in the
233 * case that a collision with the track happens during resetAllKarts: at this
234 * time m_kart_track_sector is not initialised (and has size 0), so it would
235 * trigger this assert. While this normally does not happen, it is useful for
236 * track designers that STK does not crash.
237 * \param kart Kart for which to return the sector.
238 */
getSectorForKart(const AbstractKart * kart) const239 int WorldWithRank::getSectorForKart(const AbstractKart *kart) const
240 {
241 if (kart->getWorldKartId() >= m_kart_track_sector.size())
242 return Graph::UNKNOWN_SECTOR;
243 return getTrackSector(kart->getWorldKartId())->getCurrentGraphNode();
244 } // getSectorForKart
245
246 //-----------------------------------------------------------------------------
247 /** Localize each kart on the graph using its center xyz.
248 */
updateSectorForKarts()249 void WorldWithRank::updateSectorForKarts()
250 {
251 if (isRaceOver()) return;
252
253 const unsigned int n = getNumKarts();
254 assert(n == m_kart_track_sector.size());
255 for (unsigned int i = 0; i < n; i++)
256 {
257 SpareTireAI* sta =
258 dynamic_cast<SpareTireAI*>(m_karts[i]->getController());
259 if (!m_karts[i]->isEliminated() || (sta && sta->isMoving()))
260 getTrackSector(i)->update(m_karts[i]->getXYZ());
261 }
262 } // updateSectorForKarts
263