1 //
2 // SuperTuxKart - a fun racing game with go-kart
3 // Copyright (C) 2010-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 #include "karts/max_speed.hpp"
20
21 #include "config/stk_config.hpp"
22 #include "karts/abstract_kart.hpp"
23 #include "karts/kart_properties.hpp"
24 #include "network/network_string.hpp"
25 #include "physics/btKart.hpp"
26
27 #include <algorithm>
28 #include <assert.h>
29 #include <cstdlib>
30
31 /** This class handles maximum speed for karts. Several factors can influence
32 * the maximum speed a kart can drive, some will decrease the maximum speed,
33 * some will increase the maximum speed.
34 * Slowdowns are specified in fraction of the (kart specific) maximum speed
35 * of that kart. The following categories are defined:
36 * - terrain-specific slow downs
37 * - AI related slow down (low level AIs might drive slower than player)
38 * - end controller related AI (end controller drives slower)
39 * The largest slowdown of all those factors is applied to the maximum
40 * speed of the kart.
41 * Increase of maximum speed is given absolute, i.e. in m/s. The following
42 * circumstances can increase the maximum speed:
43 * - Use of a zipper
44 * - Use of sliptstream
45 * - Use of nitro
46 * The speed increases for all those are added after applying the maximum
47 * slowdown fraction.
48 * At the end the maximum is capped by a value specified in stk_config
49 * (to avoid issues with physics etc).
50 */
MaxSpeed(AbstractKart * kart)51 MaxSpeed::MaxSpeed(AbstractKart *kart)
52 {
53 m_kart = kart;
54 // Initialise m_add_engine_force since it might be queried before
55 // update() is called.
56 m_add_engine_force = 0;
57 // This can be used if command line option -N is used
58 m_current_max_speed = 0;
59 } // MaxSpeed
60
61 // ----------------------------------------------------------------------------
62 /** Reset to prepare for a restart. It just overwrites each entry with a
63 * newly constructed values, i.e. values that don't cause any slowdown
64 * or speedup.
65 */
reset()66 void MaxSpeed::reset()
67 {
68 m_current_max_speed = m_kart->getKartProperties()->getEngineMaxSpeed();
69 m_min_speed = -1.0f;
70
71 for(unsigned int i=MS_DECREASE_MIN; i<MS_DECREASE_MAX; i++)
72 {
73 SpeedDecrease sd;
74 m_speed_decrease[i] = sd;
75 }
76
77 // Then add the speed increase from each category
78 // ----------------------------------------------
79 for(unsigned int i=MS_INCREASE_MIN; i<MS_INCREASE_MAX; i++)
80 {
81 SpeedIncrease si;
82 m_speed_increase[i] = si;
83 }
84 } // reset
85
86 // ----------------------------------------------------------------------------
87 /** Sets an increased maximum speed for a category.
88 * \param category The category for which to set the higher maximum speed.
89 * \param add_speed How much speed (in m/s) is added to the maximum speed.
90 * \param duration How long the speed increase will last.
91 * \param fade_out_time How long the maximum speed will fade out linearly.
92 */
increaseMaxSpeed(unsigned int category,float add_speed,float engine_force,int duration,int fade_out_time)93 void MaxSpeed::increaseMaxSpeed(unsigned int category, float add_speed,
94 float engine_force, int duration,
95 int fade_out_time)
96 {
97 // Allow fade_out_time 0 if add_speed is set to 0.
98 assert(add_speed==0.0f || fade_out_time>0.01f);
99 assert(category>=MS_INCREASE_MIN && category <MS_INCREASE_MAX);
100
101 if (add_speed < 0.0f || engine_force < 0.0f)
102 {
103 Log::warn("MaxSpeed::increaseMaxSpeed",
104 "Negative add_speed %f or engine_force %f, ignored.",
105 add_speed, engine_force);
106 return;
107 }
108
109 int add_speed_i = (int)(add_speed * 1000.0f);
110 if (add_speed_i > 65535)
111 {
112 Log::warn("MaxSpeed::increaseMaxSpeed",
113 "%f add_speed too large.", add_speed);
114 add_speed_i = 65535;
115 }
116
117 int engine_force_i = (int)(engine_force * 10.0f);
118 if (engine_force_i > 65535)
119 {
120 Log::warn("MaxSpeed::increaseMaxSpeed",
121 "%f engine_force too large.", engine_force);
122 engine_force_i = 65535;
123 }
124
125 int16_t fade = 0;
126 if (fade_out_time > 32767)
127 {
128 Log::warn("MaxSpeed::increaseMaxSpeed",
129 "%d fade_out_time too large.", fade);
130 fade = (int16_t)32767;
131 }
132 else
133 fade = (int16_t)fade_out_time;
134
135 int16_t dur = 0;
136 if (duration > 32767)
137 {
138 Log::warn("MaxSpeed::increaseMaxSpeed",
139 "%d duration too large.", dur);
140 dur = (int16_t)32767;
141 }
142 else
143 dur = (int16_t)duration;
144
145 m_speed_increase[category].m_max_add_speed = (uint16_t)add_speed_i;
146 m_speed_increase[category].m_duration = dur;
147 m_speed_increase[category].m_fade_out_time = fade;
148 m_speed_increase[category].m_current_speedup = add_speed;
149 m_speed_increase[category].m_engine_force = (uint16_t)engine_force_i;
150 } // increaseMaxSpeed
151
152 // ----------------------------------------------------------------------------
153 /** This adjusts the top speed using increaseMaxSpeed, but additionally
154 * causes an instant speed boost, which can be smaller than add-max-speed.
155 * (e.g. a zipper can give an instant boost of 5 m/s, but over time would
156 * allow the speed to go up by 10 m/s). Note that bullet does not restrict
157 * speed (e.g. by simulating air resistance), so without capping the speed
158 * (which is done my this object) the speed would go arbitrary high over time
159 * \param category The category for which the speed is increased.
160 * \param add_max_speed Increase of the maximum allowed speed.
161 * \param speed_boost An instant speed increase for this kart.
162 * \param engine_force Additional engine force.
163 * \param duration Duration of the increased speed.
164 * \param fade_out_time How long the maximum speed will fade out linearly.
165 */
instantSpeedIncrease(unsigned int category,float add_max_speed,float speed_boost,float engine_force,int duration,int fade_out_time)166 void MaxSpeed::instantSpeedIncrease(unsigned int category,
167 float add_max_speed, float speed_boost,
168 float engine_force, int duration,
169 int fade_out_time)
170 {
171 increaseMaxSpeed(category, add_max_speed, engine_force, duration,
172 fade_out_time);
173 // This will result in all max speed settings updated, but no
174 // changes to any slow downs since dt=0
175 update(0);
176 float speed = std::min(m_kart->getSpeed()+ speed_boost,
177 getCurrentMaxSpeed() );
178
179 // If there is a min_speed defined, make sure that the kart is still
180 // fast enough (otherwise e.g. on easy difficulty even with zipper
181 // the speed might be too low for certain jumps).
182 if(speed < m_min_speed) speed = m_min_speed;
183
184 m_kart->getVehicle()->setMinSpeed(speed);
185
186 } // instantSpeedIncrease
187
188 // ----------------------------------------------------------------------------
189 /** Handles the update of speed increase objects. The m_duration variable
190 * contains the remaining time - as long as this variable is positive
191 * the maximum speed increase applies, while when it is between
192 * -m_fade_out_time and 0, the maximum speed will linearly decrease.
193 * \param dt Time step size.
194 */
update(int ticks)195 void MaxSpeed::SpeedIncrease::update(int ticks)
196 {
197 if (m_duration == std::numeric_limits<int16_t>::min())
198 {
199 m_current_speedup = 0;
200 m_max_add_speed = 0;
201 return;
202 }
203 m_duration -= ticks;
204 // End of increased max speed reached.
205 if(m_duration < -m_fade_out_time)
206 {
207 m_duration = std::numeric_limits<int16_t>::min();
208 m_current_speedup = 0;
209 m_max_add_speed = 0;
210 return;
211 }
212 // If we are still in main max speed increase time, do nothing
213 m_current_speedup = (float)m_max_add_speed / 1000.0f;
214 if (m_duration > 0)
215 return;
216
217 // Now we are in the fade out period: decrease time linearly
218 m_current_speedup -= std::abs(m_duration - ticks) *
219 ((float)m_max_add_speed / 1000.0f) / m_fade_out_time;
220 } // SpeedIncrease::update
221
222 // ----------------------------------------------------------------------------
saveState(BareNetworkString * buffer) const223 void MaxSpeed::SpeedIncrease::saveState(BareNetworkString *buffer) const
224 {
225 buffer->addUInt16(m_max_add_speed);
226 buffer->addUInt16(m_duration);
227 buffer->addUInt16(m_fade_out_time);
228 buffer->addUInt16(m_engine_force);
229 } // saveState
230
231 // ----------------------------------------------------------------------------
rewindTo(BareNetworkString * buffer,bool is_active)232 void MaxSpeed::SpeedIncrease::rewindTo(BareNetworkString *buffer,
233 bool is_active)
234 {
235 if(is_active)
236 {
237 m_max_add_speed = buffer->getUInt16();
238 m_duration = buffer->getUInt16();
239 m_fade_out_time = buffer->getUInt16();
240 m_engine_force = buffer->getUInt16();
241 }
242 else // make sure to disable this category
243 {
244 reset();
245 }
246 } // rewindTo
247
248 // ----------------------------------------------------------------------------
249 /** Defines a slowdown, which is in fraction of top speed.
250 * \param category The category for which the speed is increased.
251 * \param max_speed_fraction Fraction of top speed to allow only.
252 * \param fade_in_time How long till maximum speed is capped.
253 * \param duration How long the effect will lasts. The value of -1 (default)
254 * indicates that this effect stays active forever (i.e. till its
255 * value is changed to something else).
256 */
setSlowdown(unsigned int category,float max_speed_fraction,int fade_in_ticks,int duration)257 void MaxSpeed::setSlowdown(unsigned int category, float max_speed_fraction,
258 int fade_in_ticks, int duration)
259 {
260 assert(category>=MS_DECREASE_MIN && category <MS_DECREASE_MAX);
261 if (max_speed_fraction < 0.0f)
262 {
263 Log::warn("MaxSpeed::increaseMaxSpeed",
264 "Negative max_speed_fraction %f, ignored.",
265 max_speed_fraction);
266 return;
267 }
268
269 int max_speed_fraction_i = (int)(max_speed_fraction * 1000.0f);
270 if (max_speed_fraction_i > 65535)
271 {
272 Log::warn("MaxSpeed::increaseMaxSpeed",
273 "%f max_speed_fraction too large.", max_speed_fraction);
274 max_speed_fraction_i = 65535;
275 }
276
277 int16_t fade = 0;
278 if (fade_in_ticks > 32767)
279 {
280 Log::warn("MaxSpeed::setSlowdown",
281 "%d fade_in_ticks too large.", fade);
282 fade = (int16_t)32767;
283 }
284 else
285 fade = (int16_t)fade_in_ticks;
286
287 int16_t dur = 0;
288 if (duration > 32767)
289 {
290 Log::warn("MaxSpeed::setSlowdown",
291 "%d duration too large.", dur);
292 dur = (int16_t)32767;
293 }
294 else
295 dur = (int16_t)duration;
296
297 m_speed_decrease[category].m_fade_in_ticks = fade;
298 m_speed_decrease[category].m_duration = dur;
299 m_speed_decrease[category].m_max_speed_fraction =
300 (uint16_t)max_speed_fraction_i;
301 } // setSlowdown
302
303 // ----------------------------------------------------------------------------
304 /** Handles the speed increase for a certain category.
305 * \param dt Time step size.
306 */
update(int ticks)307 void MaxSpeed::SpeedDecrease::update(int ticks)
308 {
309 if(m_duration>-1)
310 {
311 // It's a timed slowdown
312 m_duration -= ticks;
313 if(m_duration<0)
314 {
315 m_duration = 0;
316 m_current_fraction = 1.0f;
317 m_max_speed_fraction = 1000;
318 return;
319 }
320 }
321
322 float diff = m_current_fraction - m_max_speed_fraction / 1000.0f;
323
324 if (diff > 0)
325 {
326 if (diff * m_fade_in_ticks > ticks)
327 m_current_fraction -= float(ticks) / float(m_fade_in_ticks);
328 else
329 m_current_fraction = m_max_speed_fraction / 1000.0f;
330 }
331 else
332 m_current_fraction = m_max_speed_fraction / 1000.0f;
333 } // SpeedDecrease::update
334
335 // ----------------------------------------------------------------------------
336 /** Saves the state of an (active) speed decrease category. It is not called
337 * if the speed decrease is not active.
338 * \param buffer Buffer which will store the state information.
339 */
saveState(BareNetworkString * buffer) const340 void MaxSpeed::SpeedDecrease::saveState(BareNetworkString *buffer) const
341 {
342 buffer->addUInt16(m_max_speed_fraction);
343 buffer->addFloat(m_current_fraction);
344 buffer->addUInt16(m_fade_in_ticks);
345 buffer->addUInt16(m_duration);
346 } // saveState
347
348 // ----------------------------------------------------------------------------
349 /** Restores a previously saved state for an active speed decrease category.
350 */
rewindTo(BareNetworkString * buffer,bool is_active)351 void MaxSpeed::SpeedDecrease::rewindTo(BareNetworkString *buffer,
352 bool is_active)
353 {
354 if(is_active)
355 {
356 m_max_speed_fraction = buffer->getUInt16();
357 m_current_fraction = buffer->getFloat();
358 m_fade_in_ticks = buffer->getUInt16();
359 m_duration = buffer->getUInt16();
360 }
361 else // make sure it is not active
362 {
363 reset();
364 }
365 } // rewindTo
366
367 // ----------------------------------------------------------------------------
368 /** Returns how much increased speed time is left over in the given category.
369 * \param category Which category to report on.
370 */
getSpeedIncreaseTicksLeft(unsigned int category)371 int MaxSpeed::getSpeedIncreaseTicksLeft(unsigned int category)
372 {
373 return m_speed_increase[category].getTimeLeft();
374 } // getSpeedIncreaseTimeLeft
375
376 // ----------------------------------------------------------------------------
377 /** Returns if increased speed is active in the given category.
378 * \param category Which category to report on.
379 */
isSpeedIncreaseActive(unsigned int category)380 int MaxSpeed::isSpeedIncreaseActive(unsigned int category)
381 {
382 return m_speed_increase[category].isActive();
383 } // isSpeedIncreaseActive
384
385 // ----------------------------------------------------------------------------
386 /** Returns if decreased speed is active in the given category.
387 * \param category Which category to report on.
388 */
isSpeedDecreaseActive(unsigned int category)389 int MaxSpeed::isSpeedDecreaseActive(unsigned int category)
390 {
391 return m_speed_decrease[category].isActive();
392 } // isSpeedDecreaseActive
393
394 // ----------------------------------------------------------------------------
395 /** Updates all speed increase and decrease objects, and determines the
396 * current maximum speed. Note that the function can be called with
397 * dt=0, in which case the maximum speed will be updated, but no
398 * change to any of the speed increase/decrease objects will be done.
399 * \param dt Time step size (dt=0 only updates the current maximum speed).
400 */
update(int ticks)401 void MaxSpeed::update(int ticks)
402 {
403
404 // First compute the minimum max-speed fraction, which
405 // determines the overall decrease of maximum speed.
406 // ---------------------------------------------------
407 float slowdown_factor = 1.0f;
408 for(unsigned int i=MS_DECREASE_MIN; i<MS_DECREASE_MAX; i++)
409 {
410 SpeedDecrease &slowdown = m_speed_decrease[i];
411 slowdown.update(ticks);
412 slowdown_factor = std::min(slowdown_factor,
413 slowdown.getSlowdownFraction());
414 }
415
416 m_add_engine_force = 0;
417 m_current_max_speed = m_kart->getKartProperties()->getEngineMaxSpeed();
418
419 // Then add the speed increase from each category
420 // ----------------------------------------------
421 for(unsigned int i=MS_INCREASE_MIN; i<MS_INCREASE_MAX; i++)
422 {
423 SpeedIncrease &speedup = m_speed_increase[i];
424 speedup.update(ticks);
425 m_current_max_speed += speedup.getSpeedIncrease();
426 m_add_engine_force += speedup.getEngineForce();
427 }
428 if (getSpeedIncreaseTicksLeft(MS_INCREASE_SKIDDING) > 0 &&
429 getSpeedIncreaseTicksLeft(MS_INCREASE_RED_SKIDDING) > 0)
430 {
431 SpeedIncrease &speedup = m_speed_increase[MS_INCREASE_SKIDDING];
432 m_current_max_speed -= speedup.getSpeedIncrease();
433 m_add_engine_force -= speedup.getEngineForce();
434 }
435
436 m_current_max_speed *= slowdown_factor;
437
438 // Then cap the current speed of the kart
439 // --------------------------------------
440 if(m_min_speed > 0 && m_kart->getSpeed() < m_min_speed)
441 {
442 m_kart->getVehicle()->setMinSpeed(m_min_speed);
443 }
444 else
445 m_kart->getVehicle()->setMinSpeed(0); // no additional acceleration
446
447 if (m_kart->isOnGround())
448 m_kart->getVehicle()->setMaxSpeed(m_current_max_speed);
449 else
450 m_kart->getVehicle()->setMaxSpeed(9999.9f);
451
452 } // update
453
454 // ----------------------------------------------------------------------------
455 /** Saves the speed data in a network string for rewind.
456 * \param buffer Pointer to the network string to store the data.
457 */
saveState(BareNetworkString * buffer) const458 void MaxSpeed::saveState(BareNetworkString *buffer) const
459 {
460 // Save the slowdown states
461 // ------------------------
462 // Get the bit pattern of all active slowdowns
463 uint8_t active_slowdown = 0;
464 for(unsigned int i=MS_DECREASE_MIN, b=1; i<MS_DECREASE_MAX; i++, b <<=1)
465 {
466 // Don't bother saving terrain, this will get updated automatically
467 // each frame.
468 if(i==MS_DECREASE_TERRAIN) continue;
469 if (m_speed_decrease[i].isActive())
470 active_slowdown |= b;
471 }
472 buffer->addUInt8(active_slowdown);
473
474 for(unsigned int i=MS_DECREASE_MIN, b=1; i<MS_DECREASE_MAX; i++, b <<= 1)
475 {
476 if (i == MS_DECREASE_TERRAIN)
477 {
478 // Handle in local state
479 continue;
480 }
481 else if (active_slowdown & b)
482 m_speed_decrease[i].saveState(buffer);
483 }
484
485 // Now save the speedup state
486 // --------------------------
487 // Get the bit pattern of all active speedups
488 uint8_t active_speedups = 0;
489 for(unsigned int i=MS_INCREASE_MIN, b=1; i<MS_INCREASE_MAX; i++, b <<= 1)
490 {
491 if(m_speed_increase[i].isActive())
492 active_speedups |= b;
493 }
494 buffer->addUInt8(active_speedups);
495 for(unsigned int i=MS_INCREASE_MIN, b=1; i<MS_INCREASE_MAX; i++, b <<= 1)
496 {
497 if(active_speedups & b)
498 m_speed_increase[i].saveState(buffer);
499 }
500
501 } // saveState
502
503 // ----------------------------------------------------------------------------
504 /** Restore a saved state.
505 * \param buffer Saved state.
506 */
rewindTo(BareNetworkString * buffer)507 void MaxSpeed::rewindTo(BareNetworkString *buffer)
508 {
509 // Restore the slowdown states
510 // ---------------------------
511 // Get the bit pattern of all active slowdowns
512 uint8_t active_slowdown = buffer->getUInt8();
513
514 for(unsigned int i=MS_DECREASE_MIN, b=1; i<MS_DECREASE_MAX; i++, b <<= 1)
515 {
516 if (i == MS_DECREASE_TERRAIN)
517 {
518 // Handle in local state
519 continue;
520 }
521 else
522 m_speed_decrease[i].rewindTo(buffer, (active_slowdown & b) == b);
523 }
524
525 // Restore the speedup state
526 // --------------------------
527 // Get the bit pattern of all active speedups
528 uint8_t active_speedups = buffer->getUInt8();
529 for(unsigned int i=MS_INCREASE_MIN, b=1; i<MS_INCREASE_MAX; i++, b <<= 1)
530 {
531 m_speed_increase[i].rewindTo(buffer, (active_speedups & b) == b);
532 }
533 // Make sure to update the physics
534 update(0);
535 } // rewindoTo
536
537