1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2004-2016 Steve Baker <sjbaker1@airmail.net>
4 //  Copyright (C) 2006-2016 SuperTuxKart-Team, Joerg Henrichs, Steve Baker
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 3
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 
20 #include "karts/kart.hpp"
21 
22 #include "audio/sfx_manager.hpp"
23 #include "audio/sfx_base.hpp"
24 #include "challenges/challenge_status.hpp"
25 #include "challenges/unlock_manager.hpp"
26 #include "config/player_manager.hpp"
27 #include "config/user_config.hpp"
28 #include "font/bold_face.hpp"
29 #include "font/font_manager.hpp"
30 #include "graphics/camera.hpp"
31 #include "graphics/central_settings.hpp"
32 #include "graphics/explosion.hpp"
33 #include "graphics/irr_driver.hpp"
34 #include "graphics/material.hpp"
35 #include "graphics/material_manager.hpp"
36 #include "graphics/particle_emitter.hpp"
37 #include "graphics/particle_kind_manager.hpp"
38 #include "graphics/shadow.hpp"
39 #include "graphics/skid_marks.hpp"
40 #include "graphics/slip_stream.hpp"
41 #include "graphics/stk_text_billboard.hpp"
42 #include "graphics/stars.hpp"
43 #include "guiengine/scalable_font.hpp"
44 #include "io/file_manager.hpp"
45 #include "items/attachment.hpp"
46 #include "items/item_manager.hpp"
47 #include "items/powerup.hpp"
48 #include "items/projectile_manager.hpp"
49 #include "karts/abstract_characteristic.hpp"
50 #include "karts/abstract_kart_animation.hpp"
51 #include "karts/cached_characteristic.hpp"
52 #include "karts/controller/local_player_controller.hpp"
53 #include "karts/controller/end_controller.hpp"
54 #include "karts/controller/spare_tire_ai.hpp"
55 #include "karts/explosion_animation.hpp"
56 #include "karts/kart_gfx.hpp"
57 #include "karts/kart_model.hpp"
58 #include "karts/kart_properties.hpp"
59 #include "karts/kart_properties_manager.hpp"
60 #include "karts/kart_rewinder.hpp"
61 #include "karts/max_speed.hpp"
62 #include "karts/rescue_animation.hpp"
63 #include "karts/skidding.hpp"
64 #include "main_loop.hpp"
65 #include "modes/capture_the_flag.hpp"
66 #include "modes/linear_world.hpp"
67 #include "modes/overworld.hpp"
68 #include "modes/soccer_world.hpp"
69 #include "network/compress_network_body.hpp"
70 #include "network/network_config.hpp"
71 #include "network/protocols/client_lobby.hpp"
72 #include "network/race_event_manager.hpp"
73 #include "network/rewind_info.hpp"
74 #include "network/rewind_manager.hpp"
75 #include "physics/btKart.hpp"
76 #include "physics/btKartRaycast.hpp"
77 #include "physics/physics.hpp"
78 #include "race/history.hpp"
79 #include "tracks/terrain_info.hpp"
80 #include "tracks/drive_graph.hpp"
81 #include "tracks/drive_node.hpp"
82 #include "tracks/track.hpp"
83 #include "tracks/track_manager.hpp"
84 #include "tracks/track_sector.hpp"
85 #include "utils/constants.hpp"
86 #include "utils/helpers.hpp"
87 #include "utils/log.hpp" //TODO: remove after debugging is done
88 #include "utils/profiler.hpp"
89 #include "utils/string_utils.hpp"
90 #include "utils/translation.hpp"
91 #include "utils/vs.hpp"
92 
93 #include <ICameraSceneNode.h>
94 #include <ISceneManager.h>
95 
96 #include <algorithm> // for min and max
97 #include <iostream>
98 #include <limits>
99 #include <cmath>
100 
101 
102 #if defined(WIN32) && !defined(__CYGWIN__)  && !defined(__MINGW32__)
103    // Disable warning for using 'this' in base member initializer list
104 #  pragma warning(disable:4355)
105 #endif
106 
107 /** The kart constructor.
108  *  \param ident  The identifier for the kart model to use.
109  *  \param position The position (or rank) for this kart (between 1 and
110  *         number of karts). This is used to determine the start position.
111  *  \param init_transform  The initial position and rotation for this kart.
112  */
Kart(const std::string & ident,unsigned int world_kart_id,int position,const btTransform & init_transform,HandicapLevel handicap,std::shared_ptr<RenderInfo> ri)113 Kart::Kart (const std::string& ident, unsigned int world_kart_id,
114             int position, const btTransform& init_transform,
115             HandicapLevel handicap, std::shared_ptr<RenderInfo> ri)
116      : AbstractKart(ident, world_kart_id, position, init_transform,
117              handicap, ri)
118 
119 #if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
120 #  pragma warning(1:4355)
121 #endif
122 {
123     m_max_speed            = new MaxSpeed(this);
124     m_terrain_info         = new TerrainInfo();
125     m_powerup              = new Powerup(this);
126     m_initial_position     = position;
127     m_race_result          = false;
128     m_wheel_box            = NULL;
129     m_collision_particles  = NULL;
130     m_controller           = NULL;
131     m_saved_controller     = NULL;
132     m_consumption_per_tick = stk_config->ticks2Time(1) *
133                              m_kart_properties->getNitroConsumption();
134     m_fire_clicked         = 0;
135     m_default_suspension_force = 0.0f;
136     m_boosted_ai           = false;
137     m_type                 = RaceManager::KT_AI;
138     m_flying               = false;
139 
140     m_xyz_history_size     = stk_config->time2Ticks(XYZ_HISTORY_TIME);
141 
142     Vec3 initial_position = getXYZ();
143     for (int i=0;i<m_xyz_history_size;i++)
144     {
145         m_previous_xyz.push_back(initial_position);
146         m_previous_xyz_times.push_back(0.0f);
147     }
148 
149     // Initialize custom sound vector (TODO: add back when properly done)
150     // m_custom_sounds.resize(SFXManager::NUM_CUSTOMS);
151 
152     // Set position and heading:
153     m_reset_transform         = init_transform;
154     m_last_factor_engine_sound = 0.0f;
155 
156     m_kart_model->setKart(this);
157 
158     // Create SFXBase for each custom sound (TODO: add back when properly done)
159     /*
160     for (int n = 0; n < SFXManager::NUM_CUSTOMS; n++)
161     {
162         int id = m_kart_properties->getCustomSfxId((SFXManager::CustomSFX)n);
163 
164         // If id == -1 the custom sound was not defined in the .irrkart config file
165         if (id != -1)
166         {
167             m_custom_sounds[n] = SFXManager::get()->newSFX(id);
168         }
169     }*/
170 
171     m_horn_sound = SFXManager::get()->getBuffer("horn");
172     m_crash_sounds[0] = SFXManager::get()->getBuffer("crash");
173     m_crash_sounds[1] = SFXManager::get()->getBuffer("crash2");
174     m_crash_sounds[2] = SFXManager::get()->getBuffer("crash3");
175     m_goo_sound = SFXManager::get()->getBuffer("goo");
176     m_boing_sound = SFXManager::get()->getBuffer("boing");
177 
178     m_engine_sound  = SFXManager::get()->createSoundSource(m_kart_properties->getEngineSfxType());
179 
180     for (int i = 0; i < EMITTER_COUNT; i++)
181         m_emitters[i] = SFXManager::get()->createSoundSource("crash");
182 
183     m_skid_sound    = SFXManager::get()->createSoundSource( "skid"  );
184     m_nitro_sound   = SFXManager::get()->createSoundSource( "nitro" );
185     m_terrain_sound          = NULL;
186     m_last_sound_material    = NULL;
187     m_previous_terrain_sound = NULL;
188 }   // Kart
189 
190 // -----------------------------------------------------------------------------
191 /** This is a second initialisation phase, necessary since in the constructor
192  *  virtual functions are not called for any superclasses.
193  *  \param type Type of the kart.
194 */
init(RaceManager::KartType type)195 void Kart::init(RaceManager::KartType type)
196 {
197     m_type = type;
198 
199     // In multiplayer mode, sounds are NOT positional
200     if (RaceManager::get()->getNumLocalPlayers() > 1)
201     {
202         float factor = 1.0f / RaceManager::get()->getNumberOfKarts();
203         // players have louder sounds than AIs
204         if (type == RaceManager::KT_PLAYER)
205             factor = std::min(1.0f, RaceManager::get()->getNumLocalPlayers()/2.0f);
206 
207         for (int i = 0; i < EMITTER_COUNT; i++)
208             m_emitters[i]->setVolume(factor);
209 
210         m_skid_sound->setVolume(factor);
211         m_nitro_sound->setVolume(factor);
212     }   // if getNumLocalPlayers > 1
213 
214     if(!m_engine_sound)
215     {
216         Log::error("Kart","Could not allocate a sfx object for the kart. Further errors may ensue!");
217     }
218 
219     loadData(type, UserConfigParams::m_animated_characters);
220     reset();
221 }   // init
222 
223 // ----------------------------------------------------------------------------
changeKart(const std::string & new_ident,HandicapLevel handicap,std::shared_ptr<RenderInfo> ri)224 void Kart::changeKart(const std::string& new_ident,
225                       HandicapLevel handicap,
226                       std::shared_ptr<RenderInfo> ri)
227 {
228     AbstractKart::changeKart(new_ident, handicap, ri);
229     m_kart_model->setKart(this);
230 
231     scene::ISceneNode* old_node = m_node;
232     loadData(m_type, UserConfigParams::m_animated_characters);
233     m_wheel_box = NULL;
234 
235     if (LocalPlayerController* lpc =
236         dynamic_cast<LocalPlayerController*>(getController()))
237         lpc->initParticleEmitter();
238 
239     if (old_node)
240         old_node->remove();
241 
242     // Reset 1 more time (add back the body)
243     reset();
244 
245     for (int i = 0; i < m_vehicle->getNumWheels(); i++)
246     {
247         btWheelInfo &wi = m_vehicle->getWheelInfo(i);
248         wi.m_raycastInfo.m_suspensionLength = m_default_suspension_force /
249             m_vehicle->getNumWheels();
250     }
251     m_graphical_y_offset = -m_default_suspension_force /
252         m_vehicle->getNumWheels() + m_kart_model->getLowestPoint();
253     m_kart_model->setDefaultSuspension();
254     startEngineSFX();
255 }   // changeKart
256 
257 // ----------------------------------------------------------------------------
258 /** The destructor frees the memory of this kart, but note that the actual kart
259  *  model is still stored in the kart_properties (m_kart_model variable), so
260  *  it is not reloaded).
261  */
~Kart()262 Kart::~Kart()
263 {
264     // Delete all custom sounds (TODO: add back when properly done)
265     /*
266     for (int n = 0; n < SFXManager::NUM_CUSTOMS; n++)
267     {
268         if (m_custom_sounds[n] != NULL)
269             SFXManager::get()->deleteSFX(m_custom_sounds[n]);
270     }*/
271 
272     m_engine_sound->deleteSFX();
273     m_skid_sound  ->deleteSFX();
274 
275     for (int i = 0; i < EMITTER_COUNT; i++)
276         m_emitters[i]->deleteSFX();
277 
278     m_nitro_sound ->deleteSFX();
279     if(m_terrain_sound)          m_terrain_sound->deleteSFX();
280     if(m_previous_terrain_sound) m_previous_terrain_sound->deleteSFX();
281     if(m_collision_particles)    delete m_collision_particles;
282 
283     if (m_wheel_box) m_wheel_box->remove();
284 
285     // Ghost karts don't have a body
286     if(m_body)
287     {
288         Physics::get()->removeKart(this);
289     }
290 
291     delete m_max_speed;
292     delete m_terrain_info;
293     delete m_powerup;
294 
295     if(m_controller)
296         delete m_controller;
297     if(m_saved_controller)
298         delete m_saved_controller;
299 }   // ~Kart
300 
301 //-----------------------------------------------------------------------------
302 /** Reset before a new race. It will remove all attachments, and
303  *  puts the kart back at its original start position.
304  */
reset()305 void Kart::reset()
306 {
307     if (m_flying && !isGhostKart())
308     {
309         m_flying = false;
310         stopFlying();
311     }
312 
313     m_network_finish_check_ticks = 0;
314     m_network_confirmed_finish_ticks = 0;
315     // Add karts back in case that they have been removed (i.e. in battle
316     // mode) - but only if they actually have a body (e.g. ghost karts
317     // don't have one).
318     if(m_body)
319     {
320         Physics::get()->removeKart(this);
321         Physics::get()->addKart(this);
322     }
323 
324     m_min_nitro_ticks = 0;
325     m_energy_to_min_ratio = 0;
326     m_consumption_per_tick = stk_config->ticks2Time(1) *
327                              m_kart_properties->getNitroConsumption();
328 
329     // Reset star effect in case that it is currently being shown.
330     if (m_stars_effect)
331         m_stars_effect->reset();
332     m_max_speed->reset();
333     m_powerup->reset();
334 
335     // Reset animations and wheels
336     m_kart_model->reset();
337 
338     // If the controller was replaced (e.g. replaced by end controller),
339     // restore the original controller.
340     if(m_saved_controller)
341     {
342         delete m_controller;
343         m_controller       = m_saved_controller;
344         m_saved_controller = NULL;
345     }
346     m_kart_model->setAnimation(KartModel::AF_DEFAULT);
347     m_attachment->reset();
348     m_kart_gfx->reset();
349     m_skidding->reset();
350 
351     m_weight = 0.0f;
352     updateWeight();
353 
354 #ifndef SERVER_ONLY
355     if (m_collision_particles)
356         m_collision_particles->setCreationRateAbsolute(0.0f);
357 #endif
358 
359     unsetSquash();
360 
361     m_last_used_powerup    = PowerupManager::POWERUP_NOTHING;
362     m_race_position        = m_initial_position;
363     m_finished_race        = false;
364     m_eliminated           = false;
365     m_finish_time          = 0.0f;
366     m_bubblegum_ticks      = 0;
367     m_bubblegum_torque_sign = true;
368     m_invulnerable_ticks   = 0;
369     m_min_nitro_ticks      = 0;
370     m_energy_to_min_ratio  = 0;
371     m_collected_energy     = 0;
372     m_bounce_back_ticks    = 0;
373     m_brake_ticks          = 0;
374     m_ticks_last_crash     = 0;
375     m_ticks_last_zipper    = 0;
376     m_speed                = 0.0f;
377     m_current_lean         = 0.0f;
378     m_falling_time         = 0.0f;
379     m_view_blocked_by_plunger = 0;
380     m_has_caught_nolok_bubblegum = false;
381     m_is_jumping           = false;
382     m_flying               = false;
383     m_startup_boost        = 0.0f;
384 
385     if (m_node)
386         m_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f));
387 
388     for (int i=0;i<m_xyz_history_size;i++)
389     {
390         m_previous_xyz[i] = getXYZ();
391         m_previous_xyz_times[i] = 0.0f;
392     }
393     m_time_previous_counter = 0.0f;
394 
395     // In case that the kart was in the air, in which case its
396     // linear damping is 0
397     if(m_body)
398         m_body->setDamping(m_kart_properties->getStabilityChassisLinearDamping(),
399                            m_kart_properties->getStabilityChassisAngularDamping());
400 
401     if(m_terrain_sound)
402     {
403         m_terrain_sound->deleteSFX();
404         m_terrain_sound = NULL;
405     }
406     if(m_previous_terrain_sound)
407     {
408         m_previous_terrain_sound->deleteSFX();
409         m_previous_terrain_sound = NULL;
410     }
411 
412     if(m_engine_sound)
413         m_engine_sound->stop();
414 
415     m_controls.reset();
416     m_slipstream->reset();
417 
418     if(m_vehicle)
419     {
420         for (unsigned int i = 0; i < 4; i++)
421         {
422             m_vehicle->getWheelInfo(i).m_steering = 0;
423         }
424 
425         m_vehicle->reset();
426     }
427 
428     setTrans(m_reset_transform);
429 
430     applyEngineForce (0.0f);
431 
432     AbstractKart::reset();
433 #ifndef SERVER_ONLY
434     if (m_skidmarks)
435     {
436         m_skidmarks->reset();
437     }
438 #endif
439 
440     Vec3 front(0, 0, getKartLength()*0.5f);
441     m_xyz_front = getTrans()(front);
442 
443     // Base on update() below, require if starting point of kart is not near
444     // 0, 0, 0 (like in battle arena)
445     m_terrain_info->update(getTrans().getBasis(),
446         getTrans().getOrigin() + getTrans().getBasis() * Vec3(0, 0.3f, 0));
447 
448     // Reset is also called when the kart is created, at which time
449     // m_controller is not yet defined, so this has to be tested here.
450     if(m_controller)
451         m_controller->reset();
452 
453     // 3 strikes mode can hide the wheels
454     scene::ISceneNode** wheels = getKartModel()->getWheelNodes();
455     if(wheels[0]) wheels[0]->setVisible(true);
456     if(wheels[1]) wheels[1]->setVisible(true);
457     if(wheels[2]) wheels[2]->setVisible(true);
458     if(wheels[3]) wheels[3]->setVisible(true);
459 
460 }   // reset
461 
462 // -----------------------------------------------------------------------------
setXYZ(const Vec3 & a)463 void Kart::setXYZ(const Vec3& a)
464 {
465     AbstractKart::setXYZ(a);
466     Vec3 front(0, 0, getKartLength()*0.5f);
467     m_xyz_front = getTrans()(front);
468 }    // setXYZ
469 
470 // -----------------------------------------------------------------------------
increaseMaxSpeed(unsigned int category,float add_speed,float engine_force,int duration,int fade_out_time)471 void Kart::increaseMaxSpeed(unsigned int category, float add_speed,
472                             float engine_force, int duration,
473                             int fade_out_time)
474 {
475     m_max_speed->increaseMaxSpeed(category, add_speed, engine_force,
476                                   duration, fade_out_time);
477 }   // increaseMaxSpeed
478 
479 // -----------------------------------------------------------------------------
instantSpeedIncrease(unsigned int category,float add_max_speed,float speed_boost,float engine_force,int duration,int fade_out_time)480 void Kart::instantSpeedIncrease(unsigned int category, float add_max_speed,
481                                float speed_boost, float engine_force,
482                                int duration, int fade_out_time)
483 {
484     m_max_speed->instantSpeedIncrease(category, add_max_speed, speed_boost,
485                                       engine_force, duration, fade_out_time);
486 }   // instantSpeedIncrease
487 
488 // -----------------------------------------------------------------------------
setSlowdown(unsigned int category,float max_speed_fraction,int fade_in_time)489 void Kart::setSlowdown(unsigned int category, float max_speed_fraction,
490                        int fade_in_time)
491 {
492     m_max_speed->setSlowdown(category, max_speed_fraction,  fade_in_time);
493 }   // setSlowdown
494 
495 // -----------------------------------------------------------------------------
getCurrentMaxSpeed() const496 float Kart::getCurrentMaxSpeed() const
497 {
498     return m_max_speed->getCurrentMaxSpeed();
499 }   // getCurrentMaxSpeed
500 // -----------------------------------------------------------------------------
getSpeedIncreaseTicksLeft(unsigned int category) const501 int Kart::getSpeedIncreaseTicksLeft(unsigned int category) const
502 {
503     return m_max_speed->getSpeedIncreaseTicksLeft(category);
504 }   // getSpeedIncreaseTimeLeft
505 
506 // -----------------------------------------------------------------------------
setBoostAI(bool boosted)507 void Kart::setBoostAI(bool boosted)
508 {
509     m_boosted_ai = boosted;
510 }   // setBoostAI
511 // -----------------------------------------------------------------------------
getBoostAI() const512 bool Kart::getBoostAI() const
513 {
514     return m_boosted_ai;
515 }   // getBoostAI
516 
517 // -----------------------------------------------------------------------------
518 /** Returns the current material the kart is on. */
getMaterial() const519 const Material *Kart::getMaterial() const
520 {
521     return m_terrain_info->getMaterial();
522 }   // getMaterial
523 
524 // -----------------------------------------------------------------------------
525 /** Returns the previous material the kart was one (which might be
526  *  the same as getMaterial() ). */
getLastMaterial() const527 const Material *Kart::getLastMaterial() const
528 {
529     return m_terrain_info->getLastMaterial();
530 }   // getLastMaterial
531 // -----------------------------------------------------------------------------
532 /** Returns the pitch of the terrain depending on the heading. */
getTerrainPitch(float heading) const533 float Kart::getTerrainPitch(float heading) const
534 {
535     return m_terrain_info->getTerrainPitch(heading);
536 }   // getTerrainPitch
537 
538 // -----------------------------------------------------------------------------
539 /** Returns the height of the terrain. we're currently above */
getHoT() const540 float Kart::getHoT() const
541 {
542     return m_terrain_info->getHoT();
543 }   // getHoT
544 
545 // ----------------------------------------------------------------------------
546 /** Sets the powerup this kart has collected.
547  *  \param t Type of the powerup.
548  *  \param n Number of powerups collected.
549  */
setPowerup(PowerupManager::PowerupType t,int n)550 void Kart::setPowerup(PowerupManager::PowerupType t, int n)
551 {
552     m_powerup->set(t, n);
553 }   // setPowerup
554 
555 // ----------------------------------------------------------------------------
556 /** Sets the powerup this kart has last used. Number is always 1.
557  *  \param t Type of the powerup.
558  */
setLastUsedPowerup(PowerupManager::PowerupType t)559 void Kart::setLastUsedPowerup(PowerupManager::PowerupType t)
560 {
561     m_last_used_powerup = t;
562 }   // setLastUsedPowerup
563 
564 // -----------------------------------------------------------------------------
getNumPowerup() const565 int Kart::getNumPowerup() const
566 {
567     return m_powerup->getNum();
568 }   // getNumPowerup
569 
570 // -----------------------------------------------------------------------------
571 /** Saves the old controller in m_saved_controller and stores a new
572  *  controller. The save controller is needed in case of a reset.
573  *  \param controller The new controller to use (atm it's always an
574  *         end controller).
575  */
setController(Controller * controller)576 void Kart::setController(Controller *controller)
577 {
578     assert(m_saved_controller==NULL);
579     m_saved_controller = m_controller;
580     m_controller       = controller;
581 }   // setController
582 
583 // -----------------------------------------------------------------------------
584 /** Sets the position in race this kart has .
585  *  The position in this race for this kart (1<=p<=n)
586  */
setPosition(int p)587 void Kart::setPosition(int p)
588 {
589     m_controller->setPosition(p);
590     m_race_position = p;
591 }   // setPosition
592 
593 // -----------------------------------------------------------------------------
594 /** Sets that the view is blocked by a plunger. The duration depends on
595  *  the difficulty, see KartPorperties getPlungerInFaceTime.
596  */
blockViewWithPlunger()597 void Kart::blockViewWithPlunger()
598 {
599     // Avoid that a plunger extends the plunger time
600     if(m_view_blocked_by_plunger<=0 && !isShielded())
601     {
602         m_view_blocked_by_plunger = (int16_t)
603             stk_config->time2Ticks(m_kart_properties->getPlungerInFaceTime());
604     }
605     if(isShielded())
606     {
607         decreaseShieldTime();
608     }
609 }   // blockViewWithPlunger
610 
611 // -----------------------------------------------------------------------------
612 /** Returns a transform that will align an object with the kart: the heading
613  *  and the pitch will be set appropriately. A custom pitch value can be
614  *  specified in order to overwrite the terrain pitch (which would be used
615  *  otherwise).
616  *  \param custom_pitch Pitch value to overwrite the terrain pitch. A value of
617  *         -1 indicates that the custom_pitch value should not be used, instead
618  *         the actual pitch of the terrain is to be used.
619  */
getAlignedTransform(const float custom_pitch)620 btTransform Kart::getAlignedTransform(const float custom_pitch)
621 {
622     btTransform trans = getTrans();
623     /*
624     float pitch = (custom_pitch == -1 ? getTerrainPitch(getHeading())
625                                       : custom_pitch);
626 
627     btMatrix3x3 m;
628     m.setEulerZYX(pitch, getHeading()+m_skidding->getVisualSkidRotation(),
629                   0.0f);
630     trans.setBasis(m);
631     */
632     btTransform trans2;
633     trans2.setIdentity();
634     trans2.setRotation(btQuaternion(m_skidding->getVisualSkidRotation(), 0, 0));
635     trans *= trans2;
636 
637     return trans;
638 }   // getAlignedTransform
639 
640 // ----------------------------------------------------------------------------
getTimeFullSteer(float steer) const641 float Kart::getTimeFullSteer(float steer) const
642 {
643     return m_kart_properties->getTurnTimeFullSteer().get(steer);
644 }   // getTimeFullSteer
645 
646 // ----------------------------------------------------------------------------
647 /** Creates the physical representation of this kart. Atm it uses the actual
648  *  extention of the kart model to determine the size of the collision body.
649  */
createPhysics()650 void Kart::createPhysics()
651 {
652     // First: Create the chassis of the kart
653     // -------------------------------------
654     const float kart_length = getKartLength();
655     const float kart_width  = getKartWidth();
656     float       kart_height = getKartHeight();
657 
658     // improve physics for tall karts
659     if (kart_height > kart_length*0.6f)
660     {
661         kart_height = kart_length*0.6f;
662     }
663 
664     const Vec3 &bevel = m_kart_properties->getBevelFactor();
665     Vec3 wheel_pos[4];
666 
667     Vec3 orig_factor(1, 1, 1 - bevel.getZ());
668     Vec3 bevel_factor(1.0f - bevel.getX(), 1.0f - bevel.getY(), 1.0f);
669     btConvexHullShape *hull = new btConvexHullShape();
670     for (int y = -1; y <= 1; y += 2)
671     {
672         for (int z = -1; z <= 1; z += 2)
673         {
674             for (int x = -1; x <= 1; x += 2)
675             {
676                 Vec3 p(x*kart_width  *0.5f,
677                        y*kart_height *0.5f,
678                        z*kart_length *0.5f);
679 
680                 hull->addPoint(p*orig_factor);
681                 // Only add bevelled point if bevel is defined (i.e.!=0)
682                 if(bevel.length2()>0)
683                     hull->addPoint(p*bevel_factor);
684                 if (y == -1)
685                 {
686                     int index = (x + 1) / 2 + 1 - z;  // get index of wheel
687                     float f = m_kart_properties->getPhysicalWheelPosition();
688                     // f < 0 indicates to use the old physics position, i.e.
689                     // to place the wheels outside of the chassis
690                     if(f<0)
691                     {
692                         // All wheel positions are relative to the center of
693                         // the collision shape.
694                         wheel_pos[index].setX(x*0.5f*kart_width);
695                         wheel_pos[index].setZ((0.5f*kart_length-0.25f)* z);
696                     }
697                     else
698                     {
699                         // Store the x/z position for the wheels as a weighted average
700                         // of the two bevelled points (y is set below).
701                         wheel_pos[index] = p*(orig_factor*(1.0f - f) + bevel_factor*f);
702                     }
703                     // The y position of the wheels (i.e. the points where
704                     // the suspension is attached to) is just at the
705                     // bottom of the kart (independent of collision shape).
706                     // That is half the kart height down.
707                     wheel_pos[index].setY(-0.5f*kart_height);
708                 }  // if y==-1
709             }   // for x
710         }   // for z
711     }   // for y
712 
713     // This especially enables proper drawing of the point cloud
714     hull->initializePolyhedralFeatures();
715 
716     btTransform shiftCenterOfGravity;
717     shiftCenterOfGravity.setIdentity();
718     // Shift center of gravity downwards, so that the kart
719     // won't topple over too easy.
720     shiftCenterOfGravity.setOrigin(m_kart_properties->getGravityCenterShift());
721     m_kart_chassis.reset(new btCompoundShape());
722     m_kart_chassis->addChildShape(shiftCenterOfGravity, hull);
723 
724     // Set mass and inertia
725     // --------------------
726     float mass = m_kart_properties->getMass();
727 
728     // Position the chassis
729     // --------------------
730     btTransform trans;
731     trans.setIdentity();
732     createBody(mass, trans, m_kart_chassis.get(),
733                m_kart_properties->getRestitution(0.0f));
734     std::vector<float> ang_fact = m_kart_properties->getStabilityAngularFactor();
735     // The angular factor (with X and Z values <1) helps to keep the kart
736     // upright, especially in case of a collision.
737     m_body->setAngularFactor(Vec3(ang_fact[0], ang_fact[1], ang_fact[2]));
738     m_body->setFriction(m_kart_properties->getFrictionKartFriction());
739     m_user_pointer.set(this);
740     m_body->setDamping(m_kart_properties->getStabilityChassisLinearDamping(),
741                        m_kart_properties->getStabilityChassisAngularDamping() );
742 
743     // Reset velocities
744     // ----------------
745     m_body->setLinearVelocity (btVector3(0.0f,0.0f,0.0f));
746     m_body->setAngularVelocity(btVector3(0.0f,0.0f,0.0f));
747 
748     // Create the actual vehicle
749     // -------------------------
750     m_vehicle_raycaster.reset(
751         new btKartRaycaster(Physics::get()->getPhysicsWorld(),
752                             stk_config->m_smooth_normals &&
753                             Track::getCurrentTrack()->smoothNormals()));
754     m_vehicle.reset(new btKart(m_body.get(), m_vehicle_raycaster.get(), this));
755 
756     // never deactivate the vehicle
757     m_body->setActivationState(DISABLE_DEACTIVATION);
758 
759     // Add wheels
760     // ----------
761     float suspension_rest = m_kart_properties->getSuspensionRest();
762 
763     btVector3 wheel_direction(0.0f, -1.0f, 0.0f);
764     btVector3 wheel_axle(-1.0f, 0.0f, 0.0f);
765 
766     btKart::btVehicleTuning tuning;
767     tuning.m_maxSuspensionTravel =
768         m_kart_properties->getSuspensionTravel();
769     tuning.m_maxSuspensionForce    =
770         m_kart_properties->getSuspensionMaxForce();
771 
772     const Vec3 &cs = m_kart_properties->getGravityCenterShift();
773     for(unsigned int i=0; i<4; i++)
774     {
775         bool is_front_wheel = i<2;
776         btWheelInfo& wheel = m_vehicle->addWheel(
777                             wheel_pos[i]+cs,
778                             wheel_direction, wheel_axle, suspension_rest,
779                             m_kart_model->getWheelGraphicsRadius(i),
780                             tuning, is_front_wheel);
781         wheel.m_suspensionStiffness      = m_kart_properties->getSuspensionStiffness();
782         wheel.m_wheelsDampingRelaxation  = m_kart_properties->getWheelsDampingRelaxation();
783         wheel.m_wheelsDampingCompression = m_kart_properties->getWheelsDampingCompression();
784         wheel.m_frictionSlip             = m_kart_properties->getFrictionSlip();
785         wheel.m_rollInfluence            = m_kart_properties->getStabilityRollInfluence();
786     }
787     // Body to be added in reset() which allows complete reset kart when
788     // restarting the race
789 
790 }   // createPhysics
791 
792 // ----------------------------------------------------------------------------
793 
flyUp()794 void Kart::flyUp()
795 {
796     m_flying = true;
797     Moveable::flyUp();
798 }   // flyUp
799 
800 // ----------------------------------------------------------------------------
flyDown()801 void Kart::flyDown()
802 {
803     if (isNearGround())
804     {
805         stopFlying();
806         m_flying = false;
807     }
808     else
809     {
810         Moveable::flyDown();
811     }
812 }   // flyDown
813 
814 // ----------------------------------------------------------------------------
815 /** Starts the engine sound effect. Called once the track intro phase is over.
816  */
startEngineSFX()817 void Kart::startEngineSFX()
818 {
819     if(!m_engine_sound)
820         return;
821 
822     // In multiplayer mode, sounds are NOT positional (because we have
823     // multiple listeners) so the engine sounds of all AIs is constantly
824     // heard. So reduce volume of all sounds.
825     if (RaceManager::get()->getNumLocalPlayers() > 1)
826     {
827         const int np = RaceManager::get()->getNumLocalPlayers();
828         const int nai = RaceManager::get()->getNumberOfKarts() - np;
829 
830         // player karts twice as loud as AIs toghether
831         const float players_volume = (np * 2.0f) / (np*2.0f + np);
832 
833         if (m_controller->isLocalPlayerController())
834             m_engine_sound->setVolume( players_volume / np );
835         else
836             m_engine_sound->setVolume( (1.0f - players_volume) / nai );
837     }
838 
839     m_engine_sound->setSpeed(0.6f);
840     m_engine_sound->setLoop(true);
841     m_engine_sound->play();
842 }   // startEngineSFX
843 
844 //-----------------------------------------------------------------------------
845 /** Returns true if the kart is 'resting', i.e. (nearly) not moving.
846  */
isInRest() const847 bool Kart::isInRest() const
848 {
849     return fabsf(m_body->getLinearVelocity ().y())<0.2f;
850 }  // isInRest
851 
852 //-----------------------------------------------------------------------------
853 /** Multiplies the velocity of the kart by a factor f (both linear
854  *  and angular). This is used by anvils, which suddenly slow down the kart
855  *  when they are attached.
856  */
adjustSpeed(float f)857 void Kart::adjustSpeed(float f)
858 {
859     m_body->setLinearVelocity(m_body->getLinearVelocity()*f);
860     m_body->setAngularVelocity(m_body->getAngularVelocity()*f);
861 }   // adjustSpeed
862 
863 //-----------------------------------------------------------------------------
864 /** This method is to be called every time the mass of the kart is updated,
865  *  which includes attaching an anvil to the kart (and detaching).
866  */
updateWeight()867 void Kart::updateWeight()
868 {
869     if (!m_body)
870         return;
871     float mass = m_kart_properties->getMass() + m_attachment->weightAdjust();
872     if (m_weight != mass)
873     {
874         m_weight = mass;
875         btVector3 inertia;
876         m_kart_chassis->calculateLocalInertia(mass, inertia);
877         m_body->setMassProps(mass, inertia);
878     }
879 }   // updateWeight
880 
881 // ------------------------------------------------------------------------
882 /** Returns the (maximum) speed for a given turn radius.
883  *  \param radius The radius for which the speed needs to be computed. */
getSpeedForTurnRadius(float radius) const884 float Kart::getSpeedForTurnRadius(float radius) const
885 {
886     InterpolationArray turn_angle_at_speed = m_kart_properties->getTurnRadius();
887     // Convert the turn radius into turn angle
888     for(int i = 0; i < (int)turn_angle_at_speed.size(); i++)
889         turn_angle_at_speed.setY(i, sinf( 1.0f / turn_angle_at_speed.getY(i)));
890 
891     float angle = sinf(1.0f / radius);
892     return turn_angle_at_speed.getReverse(angle);
893 }   // getSpeedForTurnRadius
894 
895 // ------------------------------------------------------------------------
896 /** Returns the maximum steering angle (depending on speed).
897     This is proportional to kart length because physics reverse this effect,
898     the results of this function should not be used to determine the
899     real raw steer angle. */
getMaxSteerAngle(float speed) const900 float Kart::getMaxSteerAngle(float speed) const
901 {
902     InterpolationArray turn_angle_at_speed = m_kart_properties->getTurnRadius();
903     // Convert the turn radius into turn angle
904     // We multiply by wheel base to keep turn radius identical
905     // across karts of different lengths sharing the same
906     // turn radius properties
907     for(int i = 0; i < (int)turn_angle_at_speed.size(); i++)
908         turn_angle_at_speed.setY(i, sinf( 1.0f / turn_angle_at_speed.getY(i))
909                                     * m_kart_properties->getWheelBase());
910 
911     return turn_angle_at_speed.get(speed);
912 }   // getMaxSteerAngle
913 
914 //-----------------------------------------------------------------------------
915 /** Sets that this kart has finished the race and finishing time. It also
916  *  notifies the race_manager about the race completion for this kart.
917  *  \param time The finishing time for this kart. It can either be the
918  *         actual time when the kart finished (in which case time() =
919  *         world->getTime()), or the estimated time in case that all
920  *         player kart have finished the race and all AI karts get
921  *         an estimated finish time set.
922  *  \param from_server In a network game, only the server can notify
923  *         about a kart finishing a race. This parameter is to distinguish
924  *         between a local detection (which is ignored on clients in a
925  *         network game), and a server notification.
926  */
finishedRace(float time,bool from_server)927 void Kart::finishedRace(float time, bool from_server)
928 {
929     // m_finished_race can be true if e.g. an AI kart was set to finish
930     // because the race was over (i.e. estimating the finish time). If
931     // this kart then crosses the finish line (with the end controller)
932     // it would trigger a race end again.
933     if (m_finished_race) return;
934 
935     const bool is_linear_race =
936         RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
937         RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL  ||
938         RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER;
939     if (NetworkConfig::get()->isNetworking() && !from_server)
940     {
941         if (NetworkConfig::get()->isServer())
942         {
943             RaceEventManager::get()->kartFinishedRace(this, time);
944         }   // isServer
945 
946         // Ignore local detection of a kart finishing a race in a
947         // network game.
948         else if (NetworkConfig::get()->isClient())
949         {
950             if (is_linear_race && m_saved_controller == NULL &&
951                 !RewindManager::get()->isRewinding())
952             {
953                 m_network_finish_check_ticks =
954                     World::getWorld()->getTicksSinceStart() +
955                     stk_config->time2Ticks(1.0f);
956                 EndController* ec = new EndController(this, m_controller);
957                 Controller* old_controller = m_controller;
958                 setController(ec);
959                 // Seamless endcontroller replay
960                 RewindManager::get()->addRewindInfoEventFunction(new
961                 RewindInfoEventFunction(
962                     World::getWorld()->getTicksSinceStart(),
963                     /*undo_function*/[old_controller, this]()
964                     {
965                         if (m_network_finish_check_ticks == -1)
966                             return;
967 
968                         m_controller = old_controller;
969                     },
970                     /*replay_function*/[ec, old_controller, this]()
971                     {
972                         if (m_network_finish_check_ticks == -1)
973                             return;
974 
975                         m_saved_controller = old_controller;
976                         ec->reset();
977                         m_controller = ec;
978                     }));
979             }
980             return;
981         }
982     }   // !from_server
983 
984     if (NetworkConfig::get()->isClient())
985     {
986         m_network_confirmed_finish_ticks =
987             World::getWorld()->getTicksSinceStart();
988     }
989 
990     m_finished_race = true;
991 
992     m_finish_time   = time;
993 
994     m_controller->finishedRace(time);
995     m_kart_model->finishedRace();
996     RaceManager::get()->kartFinishedRace(this, time);
997 
998     // If this is spare tire kart, end now
999     if (dynamic_cast<SpareTireAI*>(m_controller) != NULL) return;
1000 
1001     if (is_linear_race && m_controller->isPlayerController() && !m_eliminated)
1002     {
1003         RaceGUIBase* m = World::getWorld()->getRaceGUI();
1004         if (m)
1005         {
1006             bool won_the_race = false, too_slow = false;
1007             unsigned int win_position = 1;
1008 
1009             if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
1010                 win_position = 2;
1011 
1012             if (getPosition() == (int)win_position &&
1013                 World::getWorld()->getNumKarts() > win_position)
1014                 won_the_race = true;
1015 
1016             if (RaceManager::get()->hasTimeTarget() && m_finish_time > RaceManager::get()->getTimeTarget())
1017                 too_slow = true;
1018 
1019             m->addMessage((too_slow     ? _("You were too slow!") :
1020                            won_the_race ? _("You won the race!")  :
1021                                           _("You finished the race!")),
1022             this, 2.0f, video::SColor(255, 255, 255, 255), true, true, true);
1023         }
1024     }
1025 
1026     if (RaceManager::get()->isLinearRaceMode() || RaceManager::get()->isBattleMode() ||
1027         RaceManager::get()->isSoccerMode()     || RaceManager::get()->isEggHuntMode())
1028     {
1029         // Save for music handling in race result gui
1030         setRaceResult();
1031         if (!isGhostKart())
1032         {
1033             if (m_saved_controller == NULL)
1034             {
1035                 setController(new EndController(this, m_controller));
1036             }
1037             else
1038                 m_saved_controller->finishedRace(time);
1039         }
1040         // Skip animation if this kart is eliminated
1041         if (m_eliminated || isGhostKart()) return;
1042 
1043         m_kart_model->setAnimation(m_race_result ?
1044             KartModel::AF_WIN_START : KartModel::AF_LOSE_START);
1045     }
1046 }   // finishedRace
1047 
1048 //-----------------------------------------------------------------------------
setRaceResult()1049 void Kart::setRaceResult()
1050 {
1051     if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
1052         RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL)
1053     {
1054         if (m_controller->isLocalPlayerController()) // if player is on this computer
1055         {
1056             PlayerProfile *player = PlayerManager::getCurrentPlayer();
1057             const ChallengeStatus *challenge = player->getCurrentChallengeStatus();
1058             // In case of a GP challenge don't make the end animation depend
1059             // on if the challenge is fulfilled
1060             if (challenge && !challenge->getData()->isGrandPrix())
1061             {
1062                 if (challenge->getData()->isChallengeFulfilled())
1063                     m_race_result = true;
1064                 else
1065                     m_race_result = false;
1066             }
1067             else if (this->getPosition() <= 0.5f *
1068                 World::getWorld()->getCurrentNumKarts() ||
1069                 this->getPosition() == 1)
1070                 m_race_result = true;
1071             else
1072                 m_race_result = false;
1073         }
1074         else
1075         {
1076             if (this->getPosition() <= 0.5f *
1077                 World::getWorld()->getCurrentNumKarts() ||
1078                 this->getPosition() == 1)
1079                 m_race_result = true;
1080             else
1081                 m_race_result = false;
1082         }
1083     }
1084     else if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER ||
1085              RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES)
1086     {
1087         // the kart wins if it isn't eliminated
1088         m_race_result = !this->isEliminated();
1089     }
1090     else if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL)
1091     {
1092         FreeForAll* ffa = dynamic_cast<FreeForAll*>(World::getWorld());
1093         m_race_result = ffa->getKartFFAResult(getWorldKartId());
1094     }
1095     else if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG)
1096     {
1097         CaptureTheFlag* ctf = dynamic_cast<CaptureTheFlag*>(World::getWorld());
1098         m_race_result = ctf->getKartCTFResult(getWorldKartId());
1099     }
1100     else if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
1101     {
1102         SoccerWorld* sw = dynamic_cast<SoccerWorld*>(World::getWorld());
1103         m_race_result = sw->getKartSoccerResult(this->getWorldKartId());
1104     }
1105     else if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_EASTER_EGG)
1106     {
1107         // Easter egg mode only has one player, so always win
1108         m_race_result = true;
1109     }
1110     else
1111         Log::warn("Kart", "Unknown game mode given.");
1112 
1113 }   // setRaceResult
1114 
1115 //-----------------------------------------------------------------------------
1116 /** Called when an item is collected. It will either adjust the collected
1117  *  energy, or update the attachment or powerup for this kart.
1118  *  \param item_state The item that was hit.
1119  */
collectedItem(ItemState * item_state)1120 void Kart::collectedItem(ItemState *item_state)
1121 {
1122     float old_energy          = m_collected_energy;
1123     const Item::ItemType type = item_state->getType();
1124 
1125     switch (type)
1126     {
1127     case Item::ITEM_BANANA:
1128         m_attachment->hitBanana(item_state);
1129         break;
1130     case Item::ITEM_NITRO_SMALL:
1131         m_collected_energy += m_kart_properties->getNitroSmallContainer();
1132         break;
1133     case Item::ITEM_NITRO_BIG:
1134         m_collected_energy += m_kart_properties->getNitroBigContainer();
1135         break;
1136     case Item::ITEM_BONUS_BOX  :
1137         {
1138             m_powerup->hitBonusBox(*item_state);
1139             break;
1140         }
1141     case Item::ITEM_BUBBLEGUM:
1142         m_has_caught_nolok_bubblegum =
1143             (item_state->getPreviousOwner()&&
1144              item_state->getPreviousOwner()->getIdent() == "nolok");
1145 
1146         // slow down
1147         m_bubblegum_ticks = (int16_t)stk_config->time2Ticks(
1148             m_kart_properties->getBubblegumDuration());
1149         m_bubblegum_torque_sign =
1150             ((World::getWorld()->getTicksSinceStart() / 10) % 2 == 0) ?
1151             true : false;
1152         m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_BUBBLE,
1153             m_kart_properties->getBubblegumSpeedFraction() ,
1154             stk_config->time2Ticks(m_kart_properties->getBubblegumFadeInTime()),
1155             m_bubblegum_ticks);
1156         if (!RewindManager::get()->isRewinding())
1157             getNextEmitter()->play(getSmoothedXYZ(), m_goo_sound);
1158 
1159         // Play appropriate custom character sound
1160         playCustomSFX(SFXManager::CUSTOM_GOO);
1161         break;
1162     default        : break;
1163     }   // switch TYPE
1164 
1165     if ( m_collected_energy > m_kart_properties->getNitroMax())
1166         m_collected_energy = m_kart_properties->getNitroMax();
1167     m_controller->collectedItem(*item_state, old_energy);
1168 
1169 }   // collectedItem
1170 
1171 //-----------------------------------------------------------------------------
1172 /** Called the first time a kart accelerates after 'ready'. It searches
1173  *  through the startup times to find the appropriate slot, and returns the
1174  *  speed-boost from the corresponding entry.
1175  *  If the kart started too slow (i.e. slower than the longest time in the
1176  *  startup times list), it returns 0.
1177  */
getStartupBoostFromStartTicks(int ticks) const1178 float Kart::getStartupBoostFromStartTicks(int ticks) const
1179 {
1180     int ticks_since_ready = ticks - stk_config->time2Ticks(1.0f);
1181     if (ticks_since_ready < 0)
1182         return 0.0f;
1183     float t = stk_config->ticks2Time(ticks_since_ready);
1184     std::vector<float> startup_times = m_kart_properties->getStartupTime();
1185     for (unsigned int i = 0; i < startup_times.size(); i++)
1186     {
1187         if (t <= startup_times[i])
1188             return m_kart_properties->getStartupBoost()[i];
1189     }
1190     return 0.0f;
1191 }   // getStartupBoostFromStartTicks
1192 
1193 //-----------------------------------------------------------------------------
1194 /** Simulates gears by adjusting the force of the engine. It also takes the
1195  *  effect of the zipper into account.
1196  */
getActualWheelForce()1197 float Kart::getActualWheelForce()
1198 {
1199     float add_force = m_max_speed->getCurrentAdditionalEngineForce();
1200     assert(!std::isnan(add_force));
1201     const std::vector<float>& gear_ratio=m_kart_properties->getGearSwitchRatio();
1202     for(unsigned int i=0; i<gear_ratio.size(); i++)
1203     {
1204         if(m_speed <= m_kart_properties->getEngineMaxSpeed() * gear_ratio[i])
1205         {
1206             assert(!std::isnan(m_kart_properties->getEnginePower()));
1207             assert(!std::isnan(m_kart_properties->getGearPowerIncrease()[i]));
1208             return m_kart_properties->getEnginePower()
1209                  * m_kart_properties->getGearPowerIncrease()[i]
1210                  + add_force;
1211         }
1212     }
1213     assert(!std::isnan(m_kart_properties->getEnginePower()));
1214     return m_kart_properties->getEnginePower() + add_force * 2;
1215 
1216 }   // getActualWheelForce
1217 
1218 //-----------------------------------------------------------------------------
1219 /** The kart is on ground if all 4 wheels touch the ground, and if no special
1220  *  animation (rescue, explosion etc.) is happening).
1221  */
isOnGround() const1222 bool Kart::isOnGround() const
1223 {
1224     return ((int)m_vehicle->getNumWheelsOnGround() == m_vehicle->getNumWheels()
1225           && !getKartAnimation());
1226 }   // isOnGround
1227 
1228 //-----------------------------------------------------------------------------
1229 /** The kart is near the ground, but not necessarily on it (small jumps). This
1230  *  is used to determine when to stop flying.
1231 */
isNearGround() const1232 bool Kart::isNearGround() const
1233 {
1234     if((m_terrain_info->getHitPoint() - getXYZ()).length() ==Track::NOHIT)
1235         return false;
1236     else
1237         return ((getXYZ().getY() - m_terrain_info->getHoT())
1238                  < stk_config->m_near_ground);
1239 }   // isNearGround
1240 
1241 // ------------------------------------------------------------------------
1242 /** Enables a kart shield protection for a certain amount of time.
1243  */
setShieldTime(float t)1244 void Kart::setShieldTime(float t)
1245 {
1246     if(isShielded())
1247     {
1248         getAttachment()->setTicksLeft(stk_config->time2Ticks(t));
1249     }
1250 }   // setShieldTime
1251 
1252 // ------------------------------------------------------------------------
1253 /**
1254  * Returns true if the kart is protected by a shield.
1255  */
isShielded() const1256 bool Kart::isShielded() const
1257 {
1258     if(getAttachment() != NULL)
1259     {
1260         Attachment::AttachmentType type = getAttachment()->getType();
1261         return type == Attachment::ATTACH_BUBBLEGUM_SHIELD ||
1262                type == Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD;
1263     }
1264     else
1265     {
1266         return false;
1267     }
1268 }   // isShielded
1269 
1270 // ------------------------------------------------------------------------
1271 /**
1272  *Returns the remaining time the kart is protected by a shield.
1273  */
getShieldTime() const1274 float Kart::getShieldTime() const
1275 {
1276     if (isShielded())
1277         return stk_config->ticks2Time(getAttachment()->getTicksLeft());
1278     else
1279         return 0.0f;
1280 }   // getShieldTime
1281 
1282 // ------------------------------------------------------------------------
1283 /**
1284  * Decreases the kart's shield time.
1285  * \param t The time subtracted from the shield timer. If t == 0.0f, the
1286              default amout of time is subtracted.
1287  */
decreaseShieldTime()1288 void Kart::decreaseShieldTime()
1289 {
1290     if (isShielded())
1291     {
1292         getAttachment()->setTicksLeft(0);
1293     }
1294 }   // decreaseShieldTime
1295 
1296 //-----------------------------------------------------------------------------
1297 /** Shows the star effect for a certain time.
1298  *  \param t Time to show the star effect for.
1299  */
showStarEffect(float t)1300 void Kart::showStarEffect(float t)
1301 {
1302     if (m_stars_effect)
1303         m_stars_effect->showFor(t);
1304 }   // showStarEffect
1305 
1306 //-----------------------------------------------------------------------------
eliminate()1307 void Kart::eliminate()
1308 {
1309     if (!getKartAnimation())
1310     {
1311         Physics::get()->removeKart(this);
1312     }
1313     if (m_stars_effect)
1314     {
1315         m_stars_effect->reset();
1316         m_stars_effect->update(1);
1317     }
1318 
1319     if (m_attachment)
1320         m_attachment->clear();
1321 
1322     if (m_slipstream)
1323         m_slipstream->reset();
1324 
1325     m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_TERRAIN, 0);
1326     m_kart_gfx->setGFXInvisible();
1327 
1328     if (m_engine_sound)
1329         m_engine_sound->stop();
1330 
1331     m_eliminated = true;
1332 
1333 #ifndef SERVER_ONLY
1334     if (m_shadow)
1335         m_shadow->update(false);
1336 #endif
1337     if (m_node)
1338         m_node->setVisible(false);
1339 }   // eliminate
1340 
1341 //-----------------------------------------------------------------------------
1342 /** Updates the kart in each time step. It updates the physics setting,
1343  *  particle effects, camera position, etc.
1344  *  \param dt Time step size.
1345  */
update(int ticks)1346 void Kart::update(int ticks)
1347 {
1348     if (m_network_finish_check_ticks > 0 &&
1349         World::getWorld()->getTicksSinceStart() >
1350         m_network_finish_check_ticks &&
1351         !m_finished_race && m_saved_controller != NULL)
1352     {
1353         Log::warn("Kart", "Missing finish race from server.");
1354         m_network_finish_check_ticks = -1;
1355         delete m_controller;
1356         m_controller = m_saved_controller;
1357         m_saved_controller = NULL;
1358     }
1359 
1360     m_powerup->update(ticks);
1361 
1362     // Reset any instant speed increase in the bullet kart
1363     m_vehicle->resetMaxSpeed();
1364 
1365     if (m_bubblegum_ticks > 0)
1366         m_bubblegum_ticks -= ticks;
1367 
1368     // This is to avoid a rescue immediately after an explosion
1369     const bool has_animation_before = m_kart_animation != NULL;
1370     // A kart animation can change the xyz position. This needs to be done
1371     // before updating the graphical position (which is done in
1372     // Moveable::update() ), otherwise 'stuttering' can happen (caused by
1373     // graphical and physical position not being the same).
1374     if (has_animation_before)
1375     {
1376         m_kart_animation->update(ticks);
1377     }
1378     else if (NetworkConfig::get()->roundValuesNow())
1379         CompressNetworkBody::compress(m_body.get(), m_motion_state.get());
1380 
1381     float dt = stk_config->ticks2Time(ticks);
1382     if (!RewindManager::get()->isRewinding())
1383     {
1384         m_time_previous_counter += dt;
1385         while (m_time_previous_counter > stk_config->ticks2Time(1))
1386         {
1387             m_previous_xyz[0] = getXYZ();
1388             m_previous_xyz_times[0] = World::getWorld()->getTime();
1389             for (int i=m_xyz_history_size-1;i>0;i--)
1390             {
1391                 m_previous_xyz[i] = m_previous_xyz[i-1];
1392                 m_previous_xyz_times[i] = m_previous_xyz_times[i-1];
1393             }
1394             m_time_previous_counter -= stk_config->ticks2Time(1);
1395         }
1396     }
1397 
1398     // Update the position and other data taken from the physics (or
1399     // an animation which calls setXYZ(), which also updates the kart
1400     // physical position).
1401     Moveable::update(ticks);
1402 
1403     Vec3 front(0, 0, getKartLength()*0.5f);
1404     m_xyz_front = getTrans()(front);
1405 
1406     // Hover the kart above reset position before entering the game
1407     // Add invulnerability depends on kart
1408     if (m_live_join_util != 0 &&
1409         ((m_live_join_util > World::getWorld()->getTicksSinceStart() &&
1410         World::getWorld()->isActiveRacePhase()) ||
1411         World::getWorld()->isLiveJoinWorld()))
1412     {
1413         btRigidBody *body = getBody();
1414         body->clearForces();
1415         body->setLinearVelocity(Vec3(0.0f));
1416         body->setAngularVelocity(Vec3(0.0f));
1417         btTransform hovering = m_starting_transform;
1418         hovering.setOrigin(hovering.getOrigin() +
1419             m_starting_transform.getBasis().getColumn(1) * 3.0f);
1420         body->proceedToTransform(hovering);
1421         setTrans(hovering);
1422         float time = getKartProperties()->getExplosionInvulnerabilityTime();
1423         m_invulnerable_ticks = stk_config->time2Ticks(time);
1424     }
1425 
1426     // Update the locally maintained speed of the kart (m_speed), which
1427     // is used furthermore for engine power, camera distance etc
1428     updateSpeed();
1429     // Make the restitution depend on speed: this avoids collision issues,
1430     // otherwise a collision with high speed can see a kart being push
1431     // high up in the air (and out of control). So for higher speed we
1432     // reduce the restitution, meaning the karts will get less of a push
1433     // based on the collision speed.
1434     m_body->setRestitution(m_kart_properties->getRestitution(fabsf(m_speed)));
1435 
1436     m_controller->update(ticks);
1437 
1438 #ifndef SERVER_ONLY
1439 #undef DEBUG_CAMERA_SHAKE
1440 #ifdef DEBUG_CAMERA_SHAKE
1441     Log::verbose("camera", "%s t %f %d xyz %f %f %f v %f %f %f d3 %f d2 %f",
1442         getIdent().c_str(),
1443         World::getWorld()->getTime(), ticks,
1444         getXYZ().getX(), getXYZ().getY(), getXYZ().getZ(),
1445         getVelocity().getX(), getVelocity().getY(), getVelocity().getZ(),
1446         (Camera::getCamera(0)->getXYZ()-getXYZ()).length(),
1447         (Camera::getCamera(0)->getXYZ()-getXYZ()).length_2d()
1448         );
1449 #endif
1450 #endif
1451 
1452 #undef DEBUG_TO_COMPARE_KART_PHYSICS
1453 #ifdef DEBUG_TO_COMPARE_KART_PHYSICS
1454     // This information is useful when comparing kart physics, e.g. to
1455     // see top speed, acceleration (i.e. time to top speed) etc.
1456     Log::verbose("physics", "     %s t %f %d xyz(9-11) %f %f %f v(13-15) %f %f %f steerf(17) %f maxangle(19) %f speed(21) %f steering(23-24) %f %f clock %lf",
1457         getIdent().c_str(),
1458         World::getWorld()->getTime(), ticks,
1459         getXYZ().getX(), getXYZ().getY(), getXYZ().getZ(),
1460         getVelocity().getX(), getVelocity().getY(), getVelocity().getZ(),  //13,14,15
1461         m_skidding->getSteeringFraction(), //19
1462         getMaxSteerAngle(),  //20
1463         m_speed,  //21
1464         m_vehicle->getWheelInfo(0).m_steering,  //23
1465         m_vehicle->getWheelInfo(1).m_steering,  //24
1466         StkTime::getRealTime()
1467         );
1468 #endif
1469 
1470     // if its view is blocked by plunger, decrease remaining time
1471     if(m_view_blocked_by_plunger > 0)
1472     {
1473         m_view_blocked_by_plunger -= ticks;
1474         //unblock the view if kart just became shielded
1475         if(isShielded())
1476             m_view_blocked_by_plunger = 0;
1477     }
1478 
1479     // Decrease the remaining invulnerability time
1480     if(m_invulnerable_ticks>0)
1481         m_invulnerable_ticks -= ticks;
1482 
1483     if (!RewindManager::get()->isRewinding())
1484         m_slipstream->update(ticks);
1485     m_slipstream->updateSpeedIncrease();
1486 
1487     // TODO: hiker said this probably will be moved to btKart or so when updating bullet engine.
1488     // Neutralize any yaw change if the kart leaves the ground, so the kart falls more or less
1489     // straight after jumping, but still allowing some "boat shake" (roll and pitch).
1490     // Otherwise many non perfect jumps end in a total roll over or a serious change of
1491     // direction, sometimes 90 or even full U turn (real but less fun for a karting game).
1492     // As side effect steering becames a bit less responsive (any wheel on air), but not too bad.
1493     if(!isOnGround()) {
1494         btVector3 speed = m_body->getAngularVelocity();
1495         speed.setX(speed.getX() * 0.95f);
1496         speed.setY(speed.getY() * 0.25f); // or 0.0f for sharp neutralization of yaw
1497         speed.setZ(speed.getZ() * 0.95f);
1498         m_body->setAngularVelocity(speed);
1499 
1500         // When the kart is jumping, linear damping reduces the falling speed
1501         // of a kart so much that it can appear to be in slow motion. So
1502         // disable linear damping if a kart is in the air
1503         m_body->setDamping(0, m_kart_properties->getStabilityChassisAngularDamping());
1504     }
1505     else
1506     {
1507         m_body->setDamping(m_kart_properties->getStabilityChassisLinearDamping(),
1508                            m_kart_properties->getStabilityChassisAngularDamping());
1509     }
1510 
1511     // Used to prevent creating a rescue animation after an explosion animation got deleted
1512 
1513     m_attachment->update(ticks);
1514 
1515     // Make sure that the ray doesn't hit the kart. This is done by
1516     // resetting the collision filter group, so that this collision
1517     // object is ignored during raycasting.
1518     short int old_group = 0;
1519     if (m_body->getBroadphaseHandle())
1520     {
1521         old_group = m_body->getBroadphaseHandle()->m_collisionFilterGroup;
1522         m_body->getBroadphaseHandle()->m_collisionFilterGroup = 0;
1523     }
1524 
1525     // After the physics step was done, the position of the wheels (as stored
1526     // in wheelInfo) is actually outdated, since the chassis was moved
1527     // according to the force acting from the wheels. So the center of the
1528     // chassis is not at the center of the wheels anymore, it is somewhat
1529     // moved forward (depending on speed and fps). In very extreme cases
1530     // (see bug 2246) the center of the chassis can actually be ahead of the
1531     // front wheels. So if we do a raycast to detect the terrain from the
1532     // current chassis, that raycast might be ahead of the wheels - which
1533     // results in incorrect rescues (the wheels are still on the ground,
1534     // but the raycast happens ahead of the front wheels and are over
1535     // a rescue texture).
1536     // To avoid this problem, we do the raycast for terrain detection from
1537     // the center of the 4 wheel positions (in world coordinates).
1538 
1539     if (!has_animation_before)
1540     {
1541         Vec3 from(0.0f, 0.0f, 0.0f);
1542         for (unsigned int i = 0; i < 4; i++)
1543             from += m_vehicle->getWheelInfo(i).m_raycastInfo.m_hardPointWS;
1544 
1545         // Add a certain epsilon (0.3) to the height of the kart. This avoids
1546         // problems of the ray being cast from under the track (which happened
1547         // e.g. on tux tollway when jumping down from the ramp, when the chassis
1548         // partly tunnels through the track). While tunneling should not be
1549         // happening (since Z velocity is clamped), the epsilon is left in place
1550         // just to be on the safe side (it will not hit the chassis itself).
1551         from = from/4 + (getTrans().getBasis() * Vec3(0.0f, 0.3f, 0.0f));
1552 
1553         m_terrain_info->update(getTrans().getBasis(), from);
1554     }
1555     else
1556     {
1557         // Use kart transform directly as wheel info is not updated when
1558         // there is an animation
1559         m_terrain_info->update(getTrans().getBasis(),
1560             getXYZ() + getTrans().getBasis().getColumn(1) * 0.1f);
1561     }
1562 
1563     if (m_body->getBroadphaseHandle())
1564         m_body->getBroadphaseHandle()->m_collisionFilterGroup = old_group;
1565 
1566     // Check if a kart is (nearly) upside down and not moving much -->
1567     // automatic rescue
1568     // But only do this if auto-rescue is enabled (i.e. it will be disabled in
1569     // battle mode), and the material the kart is driving on does not have
1570     // gravity (which atm affects the roll angle).
1571 
1572     // To be used later
1573     float dist_to_sector = 0.0f;
1574     LinearWorld* lw = dynamic_cast<LinearWorld*>(World::getWorld());
1575     if (lw && DriveGraph::get())
1576     {
1577         const int sector =
1578             lw->getTrackSector(getWorldKartId())->getCurrentGraphNode();
1579         dist_to_sector = getXYZ().distance
1580             (DriveGraph::get()->getNode(sector)->getCenter());
1581 
1582         const Vec3& quad_normal = DriveGraph::get()->getNode(sector)
1583             ->getNormal();
1584         const btQuaternion& q = getTrans().getRotation();
1585         const float roll = quad_normal.angle
1586                ((Vec3(0, 1, 0).rotate(q.getAxis(), q.getAngle())));
1587 
1588         if (Track::getCurrentTrack()->isAutoRescueEnabled() &&
1589             (!m_terrain_info->getMaterial() ||
1590             !m_terrain_info->getMaterial()->hasGravity()) &&
1591             !has_animation_before && fabs(roll) > 60 * DEGREE_TO_RAD &&
1592             fabs(getSpeed()) < 3.0f)
1593         {
1594             RescueAnimation::create(this, /*is_auto_rescue*/true);
1595             m_last_factor_engine_sound = 0.0f;
1596         }
1597     }
1598 
1599     // Update physics from newly updated material
1600     PROFILER_PUSH_CPU_MARKER("Kart::updatePhysics", 0x60, 0x34, 0x7F);
1601     const Material* material = m_terrain_info->getMaterial();
1602 
1603     // First update the gravity of the kart, as updateSliding in updatePhysics
1604     // need the newly set gravity to test for sliding.
1605     if (!m_flying)
1606     {
1607         float g = Track::getCurrentTrack()->getGravity();
1608         Vec3 gravity(0.0f, -g, 0.0f);
1609         btRigidBody *body = getVehicle()->getRigidBody();
1610 
1611         // If the material should overwrite the gravity,
1612         if (material && material->hasGravity())
1613         {
1614             Vec3 normal = m_terrain_info->getNormal();
1615             gravity = normal * -g;
1616         }
1617 
1618         body->setGravity(gravity);
1619     }
1620     updatePhysics(ticks);
1621     PROFILER_POP_CPU_MARKER();
1622 
1623     if(!m_controls.getFire()) m_fire_clicked = 0;
1624 
1625     if(m_controls.getFire() && !m_fire_clicked && !m_kart_animation)
1626     {
1627         if (m_powerup->getType() != PowerupManager::POWERUP_NOTHING)
1628         {
1629             setLastUsedPowerup(m_powerup->getType());
1630         }
1631         // use() needs to be called even if there currently is no collecteable
1632         // since use() can test if something needs to be switched on/off.
1633         if (!World::getWorld()->isStartPhase())
1634             m_powerup->use();
1635         else
1636         {
1637             if(!getKartAnimation())
1638                 beep();
1639         }
1640         World::getWorld()->onFirePressed(getController());
1641         m_fire_clicked = 1;
1642     }
1643 
1644 #undef XX
1645 #ifdef XX
1646     Log::verbose("physicsafter", "%s t %f %d xyz(9-11) %f %f %f %f %f %f "
1647         "v(16-18) %f %f %f steerf(20) %f maxangle(22) %f speed(24) %f "
1648         "steering(26-27) %f %f clock(29) %lf skidstate(31) %d factor(33) %f "
1649         "maxspeed(35) %f engf(37) %f braketick(39) %d brakes(41) %d heading(43) %f "
1650         "bubticks(45) %d",
1651         getIdent().c_str(),
1652         World::getWorld()->getTime(), World::getWorld()->getTicksSinceStart(),
1653         getXYZ().getX(), getXYZ().getY(), getXYZ().getZ(),
1654         m_body->getWorldTransform().getOrigin().getX(),
1655         m_body->getWorldTransform().getOrigin().getY(),
1656         m_body->getWorldTransform().getOrigin().getZ(),
1657         getVelocity().getX(), getVelocity().getY(), getVelocity().getZ(),  //16-18
1658         m_skidding->getSteeringFraction(), //20
1659         getMaxSteerAngle(),  //22
1660         m_speed,  //24
1661         m_vehicle->getWheelInfo(0).m_steering,  //26
1662         m_vehicle->getWheelInfo(1).m_steering,  //27
1663         StkTime::getRealTime(),  //29
1664         m_skidding->getSkidState(), //31
1665         m_skidding->getSkidFactor(),    //33
1666         m_max_speed->getCurrentMaxSpeed(),
1667         m_max_speed->getCurrentAdditionalEngineForce(),  // 37
1668         m_brake_ticks, //39
1669         m_controls.getButtonsCompressed(),  //41
1670         getHeading(),  //43
1671         m_bubblegum_ticks // 45
1672     );
1673 #endif
1674 
1675     PROFILER_PUSH_CPU_MARKER("Kart::Update (material)", 0x60, 0x34, 0x7F);
1676     if (!material)   // kart falling off the track
1677     {
1678         // let kart fall a bit before rescuing
1679         const Vec3 *min, *max;
1680         Track::getCurrentTrack()->getAABB(&min, &max);
1681 
1682         if((min->getY() - getXYZ().getY() > 17 || dist_to_sector > 25) && !m_flying &&
1683            !has_animation_before)
1684         {
1685             RescueAnimation::create(this);
1686             m_last_factor_engine_sound = 0.0f;
1687         }
1688     }
1689     else
1690     {
1691         if (!has_animation_before && material->isDriveReset() && isOnGround())
1692         {
1693             RescueAnimation::create(this);
1694             m_last_factor_engine_sound = 0.0f;
1695         }
1696         else if(material->isZipper()     && isOnGround())
1697         {
1698             handleZipper(material);
1699             showZipperFire();
1700         }
1701         else
1702         {
1703             m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_TERRAIN,
1704                                      material->getMaxSpeedFraction(),
1705                                      material->getSlowDownTicks()    );
1706 #ifdef DEBUG
1707             if(UserConfigParams::m_material_debug)
1708             {
1709                 Log::info("Kart","World %d %s\tfraction %f\ttime %d.",
1710                        World::getWorld()->getTicksSinceStart(),
1711                        material->getTexFname().c_str(),
1712                        material->getMaxSpeedFraction(),
1713                        material->getSlowDownTicks()       );
1714             }
1715 #endif
1716         }
1717     }   // if there is material
1718     PROFILER_POP_CPU_MARKER();
1719 
1720     Track::getCurrentTrack()->getItemManager()->checkItemHit(this);
1721 
1722     const bool emergency = has_animation_before;
1723 
1724     if (emergency)
1725     {
1726         m_view_blocked_by_plunger = 0;
1727         if (m_flying)
1728         {
1729             stopFlying();
1730             m_flying = false;
1731         }
1732     }
1733 
1734     if (RewindManager::get()->isRewinding())
1735         return;
1736     // Remove the shadow if the kart is not on the ground (if a kart
1737     // is rescued isOnGround might still be true, since the kart rigid
1738     // body was removed from the physics, but still retain the old
1739     // values for the raycasts).
1740     if (!isOnGround() && !has_animation_before)
1741     {
1742         const Material *m      = getMaterial();
1743         const Material *last_m = getLastMaterial();
1744 
1745         // A jump starts only the kart isn't already jumping, is on a new
1746         // (or no) texture.
1747         if (!m_is_jumping && last_m && last_m != m &&
1748             m_kart_model->getAnimation() == KartModel::AF_DEFAULT)
1749         {
1750             float v = getVelocity().getY();
1751             float force = Track::getCurrentTrack()->getGravity();
1752             // Velocity / force is the time it takes to reach the peak
1753             // of the jump (i.e. when vertical speed becomes 0). Assuming
1754             // that jump start height and end height are the same, it will
1755             // take the same time again to reach the bottom
1756             float t = 2.0f * v/force;
1757 
1758             // Jump if either the jump is estimated to be long enough, or
1759             // the texture has the jump property set.
1760             if (t > m_kart_properties->getJumpAnimationTime() ||
1761                 last_m->isJumpTexture())
1762             {
1763                 m_kart_model->setAnimation(KartModel::AF_JUMP_START);
1764             }
1765 
1766             m_is_jumping = true;
1767         }
1768     }
1769     else if (m_is_jumping)
1770     {
1771         // Kart touched ground again
1772         m_is_jumping = false;
1773         m_kart_model->setAnimation(KartModel::AF_DEFAULT);
1774 
1775         if (!GUIEngine::isNoGraphics() && !has_animation_before)
1776         {
1777             HitEffect *effect =  new Explosion(getXYZ(), "jump",
1778                                               "jump_explosion.xml");
1779             ProjectileManager::get()->addHitEffect(effect);
1780         }
1781     }
1782 
1783 }   // update
1784 
1785 //-----------------------------------------------------------------------------
1786 /** Updates the local speed based on the current physical velocity. The value
1787  *  is smoothed exponentially to avoid camera stuttering (camera distance
1788  *  is dependent on speed)
1789  */
updateSpeed()1790 void Kart::updateSpeed()
1791 {
1792     // Compute the speed of the kart. Smooth it with previous speed to make
1793     // the camera smoother (because of capping the speed in m_max_speed
1794     // the speed value jitters when approaching maximum speed. This results
1795     // in the distance between kart and camera to jitter as well (typically
1796     // only in the order of centimetres though). Smoothing the speed value
1797     // gets rid of this jitter, and also r
1798     m_speed = getVehicle()->getRigidBody()->getLinearVelocity().length();
1799 
1800     // calculate direction of m_speed
1801     const btTransform& chassisTrans = getVehicle()->getChassisWorldTransform();
1802     btVector3 forwardW(
1803         chassisTrans.getBasis()[0][2],
1804         chassisTrans.getBasis()[1][2],
1805         chassisTrans.getBasis()[2][2]);
1806 
1807     // In theory <0 should be sufficient, but floating point errors can cause
1808     // flipping from +eps to -eps and back, resulting in animation flickering
1809     // if the kart has backpedal animations.
1810     if (forwardW.dot(getVehicle()->getRigidBody()->getLinearVelocity())
1811         < btScalar(-0.01f))
1812     {
1813         m_speed = -m_speed;
1814     }
1815 
1816     // At low velocity, forces on kart push it back and forth so we ignore this
1817     // - quick'n'dirty workaround for bug 1776883
1818     if (fabsf(m_speed) < 0.2f                                   ||
1819         dynamic_cast<RescueAnimation*>   ( getKartAnimation() ) ||
1820         dynamic_cast<ExplosionAnimation*>( getKartAnimation() )    )
1821     {
1822         m_speed          = 0;
1823     }
1824 }   // updateSpeed
1825 
1826 //-----------------------------------------------------------------------------
1827 /** Show fire to go with a zipper.
1828  */
showZipperFire()1829 void Kart::showZipperFire()
1830 {
1831     m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_ZIPPER, 800.0f);
1832 }
1833 
1834 //-----------------------------------------------------------------------------
1835 /** Squashes this kart: it will scale the kart in up direction, and causes
1836  *  a slowdown while this kart is squashed.
1837  *  Returns true if the squash is successful, false otherwise.
1838  *  \param time How long the kart will be squashed. A value of 0 will reset
1839  *         the kart to be unsquashed.
1840  *  \param slowdown Reduction of max speed.
1841  */
setSquash(float time,float slowdown)1842 bool Kart::setSquash(float time, float slowdown)
1843 {
1844     if (isInvulnerable() || getKartAnimation()) return false;
1845 
1846     if (isShielded())
1847     {
1848         decreaseShieldTime();
1849         return false;
1850     }
1851 
1852     if(m_attachment->getType()==Attachment::ATTACH_BOMB && time>0)
1853     {
1854         ExplosionAnimation::create(this);
1855         return true;
1856     }
1857 
1858     m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_SQUASH, slowdown,
1859                              stk_config->time2Ticks(0.1f),
1860                              stk_config->time2Ticks(time));
1861     return true;
1862 }   // setSquash
1863 
1864 //-----------------------------------------------------------------------------
setSquashGraphics()1865 void Kart::setSquashGraphics()
1866 {
1867 #ifndef SERVER_ONLY
1868     if (isGhostKart() || GUIEngine::isNoGraphics()) return;
1869 
1870     m_node->setScale(core::vector3df(1.0f, 0.5f, 1.0f));
1871     if (m_vehicle->getNumWheels() > 0)
1872     {
1873         if (!m_wheel_box)
1874         {
1875             m_wheel_box = irr_driver->getSceneManager()
1876                 ->addDummyTransformationSceneNode(m_node);
1877         }
1878         scene::ISceneNode **wheels = m_kart_model->getWheelNodes();
1879         for (int i = 0; i < 4 && i < m_vehicle->getNumWheels(); i++)
1880         {
1881             if (wheels[i])
1882                 wheels[i]->setParent(m_wheel_box);
1883         }
1884         m_wheel_box->getRelativeTransformationMatrix()
1885             .setScale(core::vector3df(1.0f, 2.0f, 1.0f));
1886     }
1887 #endif
1888 }   // setSquashGraphics
1889 
1890 //-----------------------------------------------------------------------------
unsetSquash()1891 void Kart::unsetSquash()
1892 {
1893 #ifndef SERVER_ONLY
1894     if (isGhostKart() || GUIEngine::isNoGraphics()) return;
1895 
1896     m_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f));
1897     if (m_vehicle && m_vehicle->getNumWheels() > 0)
1898     {
1899         scene::ISceneNode** wheels = m_kart_model->getWheelNodes();
1900         scene::ISceneNode* node = m_kart_model->getAnimatedNode() ?
1901                                   m_kart_model->getAnimatedNode() : m_node;
1902 
1903         for (int i = 0; i < 4 && i < m_vehicle->getNumWheels(); i++)
1904         {
1905             if (wheels[i])
1906             {
1907                 wheels[i]->setParent(node);
1908             }
1909         }
1910     }
1911 #endif
1912 }   // unsetSquash
1913 
1914 //-----------------------------------------------------------------------------
1915 /** Returns if the kart is currently being squashed
1916   */
isSquashed() const1917 bool Kart::isSquashed() const
1918 {
1919     return
1920         m_max_speed->isSpeedDecreaseActive(MaxSpeed::MS_DECREASE_SQUASH) == 1;
1921 }   // setSquash
1922 
1923 //-----------------------------------------------------------------------------
1924 /** Plays any terrain specific sound effect.
1925  */
handleMaterialSFX()1926 void Kart::handleMaterialSFX()
1927 {
1928     // If a terrain specific sfx is already being played, when a new
1929     // terrain is entered, an old sfx should be finished (once, not
1930     // looped anymore of course). The m_terrain_sound is then copied
1931     // to a m_previous_terrain_sound, for which looping is disabled.
1932     // In case that three sfx needed to be played (i.e. a previous is
1933     // playing, a current is playing, and a new terrain with sfx is
1934     // entered), the oldest (previous) sfx is stopped and deleted.
1935 
1936     // FIXME: if there are already two sfx playing, don't add another
1937     // one. This should reduce the performance impact when driving
1938     // on the bridge in Cocoa.
1939     const Material* material =
1940         isOnGround() ? m_terrain_info->getMaterial() : NULL;
1941 
1942     // We can not use getLastMaterial() since, since the last material might
1943     // be updated several times during the physics updates, not indicating
1944     // that we have reached a new material with regards to the sound effect.
1945     // So we separately save the material last used for a sound effect and
1946     // then use this for comparison.
1947     if(m_last_sound_material!=material)
1948     {
1949         // First stop any previously playing terrain sound
1950         // and remove it, so that m_previous_terrain_sound
1951         // can be used again.
1952         if(m_previous_terrain_sound)
1953         {
1954             m_previous_terrain_sound->deleteSFX();
1955         }
1956 
1957         // Disable looping for the current terrain sound, and
1958         // make it the previous terrain sound.
1959         if (m_terrain_sound) m_terrain_sound->setLoop(false);
1960         m_previous_terrain_sound = m_terrain_sound;
1961 
1962         const std::string &sound_name = material ? material->getSFXName() : "";
1963 
1964         // In multiplayer mode sounds are NOT positional, because we have
1965         // multiple listeners. This would make the sounds of all AIs be
1966         // audible at all times. So silence AI karts.
1967         if (!sound_name.empty() && (RaceManager::get()->getNumPlayers()==1 ||
1968                                     m_controller->isLocalPlayerController() ) )
1969         {
1970             m_terrain_sound = SFXManager::get()->createSoundSource(sound_name);
1971             m_terrain_sound->play();
1972             m_terrain_sound->setLoop(true);
1973         }
1974         else
1975         {
1976             m_terrain_sound = NULL;
1977         }
1978     }
1979 
1980     // Check if a previous terrain sound (now not looped anymore)
1981     // is finished and can be deleted.
1982     if(m_previous_terrain_sound &&
1983         m_previous_terrain_sound->getStatus()==SFXBase::SFX_STOPPED)
1984     {
1985         // We don't modify the position of m_previous_terrain_sound
1986         // anymore, so that it keeps on playing at the place where the
1987         // kart left the material.
1988         m_previous_terrain_sound->deleteSFX();
1989         m_previous_terrain_sound = NULL;
1990     }
1991 
1992     bool m_schedule_pause = m_flying ||
1993                         dynamic_cast<RescueAnimation*>(getKartAnimation()) ||
1994                         dynamic_cast<ExplosionAnimation*>(getKartAnimation());
1995 
1996     // terrain sound is not necessarily a looping sound so check its status before
1997     // setting its speed, to avoid 'ressuscitating' sounds that had already stopped
1998     if(m_terrain_sound &&
1999         (m_terrain_sound->getStatus()==SFXBase::SFX_PLAYING ||
2000          m_terrain_sound->getStatus()==SFXBase::SFX_PAUSED)    )
2001     {
2002         m_terrain_sound->setPosition(getSmoothedXYZ());
2003         if(material)
2004             material->setSFXSpeed(m_terrain_sound, m_speed, m_schedule_pause);
2005     }
2006 
2007     m_last_sound_material = material;
2008 }   // handleMaterialSFX
2009 
2010 //-----------------------------------------------------------------------------
2011 /** Handles material specific GFX, mostly particle effects. Particle
2012  *  effects can be triggered by two different situations: either
2013  *  because a kart drives on top of a terrain with a special effect,
2014  *  or because the kart is driving or falling under a surface (e.g.
2015  *  water), and the terrain effect is coming from that surface. Those
2016  *  effects are exclusive - you either get the effect from the terrain
2017  *  you are driving on, or the effect from a surface the kart is
2018  *  (partially) under. The surface effect is triggered, if either the
2019  *  kart is falling, or if the surface the kart is driving on has
2020  *  the 'isBelowSurface' property set. This function is called once
2021  *  per rendered frame from updateGraphics().
2022  *  \param dt Time step size.
2023  */
handleMaterialGFX(float dt)2024 void Kart::handleMaterialGFX(float dt)
2025 {
2026     const Material *material = getMaterial();
2027 
2028     // First test: give the terrain effect, if the kart is
2029     // on top of a surface (i.e. not falling), actually touching
2030     // something with the wheels, and the material has not the
2031     // below surface property set.
2032     if (material && isOnGround() && !material->isBelowSurface() &&
2033         !getKartAnimation()      && UserConfigParams::m_particles_effects > 1)
2034     {
2035 
2036         // Get the appropriate particle data depending on
2037         // wether the kart is skidding or driving.
2038         const ParticleKind* pk =
2039             material->getParticlesWhen(m_skidding->isSkidding()
2040                                                     ? Material::EMIT_ON_SKID
2041                                                     : Material::EMIT_ON_DRIVE);
2042         if(!pk)
2043         {
2044             // Disable potentially running particle effects
2045             m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_TERRAIN, 0);
2046             return;  // no particle effect, return
2047         }
2048         m_kart_gfx->updateTerrain(pk);
2049         return;
2050     }
2051 
2052     // Now the kart is either falling, or driving on a terrain which
2053     // has the 'below surface' flag set. Detect if there is a surface
2054     // on top of the kart.
2055     // --------------------------------------------------------------
2056     if (m_controller->isLocalPlayerController() && !hasFinishedRace())
2057     {
2058         bool falling = material && material->hasFallingEffect() && !m_flying;
2059         if (falling)
2060         {
2061             m_falling_time -= dt;
2062             if (m_falling_time < 0)
2063                 m_falling_time = 0;
2064         }
2065         else
2066             m_falling_time = 0.35f;
2067 
2068         for(unsigned int i=0; i<Camera::getNumCameras(); i++)
2069         {
2070             Camera *camera = Camera::getCamera(i);
2071             if(camera->getKart()!=this) continue;
2072 
2073             if (falling && m_falling_time <= 0)
2074             {
2075                 camera->setMode(Camera::CM_FALLING);
2076             }
2077             else if (camera->getMode() != Camera::CM_NORMAL &&
2078                      camera->getMode() != Camera::CM_REVERSE)
2079             {
2080                 camera->setMode(Camera::CM_NORMAL);
2081             }
2082         }   // for i in all cameras for this kart
2083     }   // camera != final camera
2084 
2085     if (UserConfigParams::m_particles_effects < 2)
2086         return;
2087 
2088     // Use the middle of the contact points of the two rear wheels
2089     // as the point from which to cast the ray upwards
2090     const btWheelInfo::RaycastInfo &ri2 =
2091         getVehicle()->getWheelInfo(2).m_raycastInfo;
2092     const btWheelInfo::RaycastInfo &ri3 =
2093         getVehicle()->getWheelInfo(3).m_raycastInfo;
2094     Vec3 from = (ri2.m_contactPointWS + ri3.m_contactPointWS)*0.5f;
2095     Vec3 xyz;
2096     const Material *surface_material;
2097     if(!m_terrain_info->getSurfaceInfo(from, &xyz, &surface_material))
2098     {
2099         m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_TERRAIN, 0);
2100         return;
2101     }
2102     const ParticleKind *pk =
2103         surface_material->getParticlesWhen(Material::EMIT_ON_DRIVE);
2104 
2105     if(!pk || m_flying || dynamic_cast<RescueAnimation*>(getKartAnimation()))
2106         return;
2107 
2108     // Now the kart is under a surface, and there is a surface effect
2109     // --------------------------------------------------------------
2110     m_kart_gfx->setParticleKind(KartGFX::KGFX_TERRAIN, pk);
2111     m_kart_gfx->setXYZ(KartGFX::KGFX_TERRAIN, xyz);
2112 
2113     const float distance = xyz.distance2(from);
2114     float ratio;
2115     if      (distance < 2.0f) ratio = 1.0f;
2116     else if (distance < 4.0f) ratio = (4.0f-distance)*0.5f;
2117     else                      ratio = -1.0f;  // No more particles
2118     m_kart_gfx->setCreationRateRelative(KartGFX::KGFX_TERRAIN, ratio);
2119 
2120     // Play special sound effects for this terrain
2121     // -------------------------------------------
2122     const std::string &s = surface_material->getSFXName();
2123     if (s != "" && !dynamic_cast<RescueAnimation*>(getKartAnimation())&&
2124         (m_terrain_sound == NULL ||
2125          m_terrain_sound->getStatus() == SFXBase::SFX_STOPPED))
2126     {
2127         if (m_previous_terrain_sound) m_previous_terrain_sound->deleteSFX();
2128         m_previous_terrain_sound = m_terrain_sound;
2129         if(m_previous_terrain_sound)
2130             m_previous_terrain_sound->setLoop(false);
2131 
2132         m_terrain_sound = SFXManager::get()->createSoundSource(s);
2133         m_terrain_sound->play();
2134         m_terrain_sound->setLoop(false);
2135     }
2136 
2137 }   // handleMaterialGFX
2138 
2139 //-----------------------------------------------------------------------------
2140 /** Sets zipper time, and apply one time additional speed boost. It can be
2141  *  used with a specific material, in which case the zipper parmaters are
2142  *  taken from this material (parameters that are <0 will be using the
2143  *  kart-specific values from kart-properties.
2144  *  \param material If not NULL, will be used to determine the zipper
2145  *                  parameters, otherwise the defaults from kart properties
2146  *                  will be used.
2147  * \param play_sound If true this will cause a sfx to be played even if the
2148  *                  terrain hasn't changed. It is used by the zipper powerup.
2149  */
handleZipper(const Material * material,bool play_sound)2150 void Kart::handleZipper(const Material *material, bool play_sound)
2151 {
2152     /** The additional speed allowed on top of the kart-specific maximum kart
2153      *  speed. */
2154     float max_speed_increase;
2155 
2156     /**Time the zipper stays activated. */
2157     float duration;
2158     /** A one time additional speed gain - the kart will instantly add this
2159      *  amount of speed to its current speed. */
2160     float speed_gain;
2161     /** Time it takes for the zipper advantage to fade out. */
2162     float fade_out_time;
2163     /** Additional engine force. */
2164     float engine_force;
2165 
2166     if(material)
2167     {
2168         material->getZipperParameter(&max_speed_increase, &duration,
2169                                      &speed_gain, &fade_out_time, &engine_force);
2170         if(max_speed_increase<0)
2171             max_speed_increase = m_kart_properties->getZipperMaxSpeedIncrease();
2172         if(duration<0)
2173             duration           = m_kart_properties->getZipperDuration();
2174         if(speed_gain<0)
2175             speed_gain         = m_kart_properties->getZipperSpeedGain();
2176         if(fade_out_time<0)
2177             fade_out_time      = m_kart_properties->getZipperFadeOutTime();
2178         if(engine_force<0)
2179             engine_force       = m_kart_properties->getZipperForce();
2180     }
2181     else
2182     {
2183         max_speed_increase = m_kart_properties->getZipperMaxSpeedIncrease();
2184         duration           = m_kart_properties->getZipperDuration();
2185         speed_gain         = m_kart_properties->getZipperSpeedGain();
2186         fade_out_time      = m_kart_properties->getZipperFadeOutTime();
2187         engine_force       = m_kart_properties->getZipperForce();
2188     }
2189     // Ignore a zipper that's activated while braking
2190     if(m_controls.getBrake() || m_speed<0) return;
2191 
2192     m_max_speed->instantSpeedIncrease(MaxSpeed::MS_INCREASE_ZIPPER,
2193                                      max_speed_increase, speed_gain,
2194                                      engine_force,
2195                                      stk_config->time2Ticks(duration),
2196                                      stk_config->time2Ticks(fade_out_time));
2197     // Play custom character sound (weee!)
2198     int zipper_ticks = World::getWorld()->getTicksSinceStart();
2199     if (zipper_ticks > m_ticks_last_zipper)
2200     {
2201         m_ticks_last_zipper = zipper_ticks;
2202         playCustomSFX(SFXManager::CUSTOM_ZIPPER);
2203         m_controller->handleZipper(play_sound);
2204     }
2205 
2206 }   // handleZipper
2207 
2208 // -----------------------------------------------------------------------------
2209 /** Updates the current nitro status.
2210  *  \param ticks Number of physics time steps - should be 1.
2211  */
updateNitro(int ticks)2212 void Kart::updateNitro(int ticks)
2213 {
2214     if (m_collected_energy == 0)
2215         m_min_nitro_ticks = 0;
2216 
2217     if (m_controls.getNitro() && m_min_nitro_ticks <= 0 && m_collected_energy > 0)
2218     {
2219         m_min_nitro_ticks = m_kart_properties->getNitroMinConsumptionTicks();
2220         float min_consumption = m_min_nitro_ticks * m_consumption_per_tick;
2221         m_energy_to_min_ratio = std::min<float>(1, m_collected_energy/min_consumption);
2222     }
2223     if (m_min_nitro_ticks > 0)
2224     {
2225         m_min_nitro_ticks -= ticks;
2226 
2227         // when pressing the key, don't allow the min time to go under zero.
2228         // If it went under zero, it would be reset
2229         // As the time deduction happens before, it can be an arbitrarily
2230         // small number > 0. Smaller means more responsive controls.
2231         if (m_controls.getNitro() && m_min_nitro_ticks <= 0)
2232             m_min_nitro_ticks = 1;
2233     }
2234 
2235     bool rewinding = RewindManager::get()->isRewinding();
2236     bool increase_speed = (m_min_nitro_ticks > 0 && isOnGround());
2237     if (!increase_speed && m_min_nitro_ticks <= 0)
2238     {
2239         if (m_nitro_sound->getStatus() == SFXBase::SFX_PLAYING && !rewinding)
2240             m_nitro_sound->stop();
2241         return;
2242     }
2243 
2244 
2245     m_collected_energy -= m_consumption_per_tick*ticks;
2246     if (m_collected_energy < 0)
2247     {
2248         if(m_nitro_sound->getStatus() == SFXBase::SFX_PLAYING && !rewinding)
2249             m_nitro_sound->stop();
2250         m_collected_energy = 0;
2251         return;
2252     }
2253 
2254     if (increase_speed)
2255     {
2256         if(m_nitro_sound->getStatus() != SFXBase::SFX_PLAYING && !rewinding)
2257             m_nitro_sound->play();
2258 
2259         m_max_speed->increaseMaxSpeed(MaxSpeed::MS_INCREASE_NITRO,
2260             m_kart_properties->getNitroMaxSpeedIncrease(),
2261             m_kart_properties->getNitroEngineForce(),
2262             stk_config->time2Ticks(m_kart_properties->getNitroDuration()*m_energy_to_min_ratio),
2263             stk_config->time2Ticks(m_kart_properties->getNitroFadeOutTime()));
2264     }
2265     else
2266     {
2267         if(m_nitro_sound->getStatus() == SFXBase::SFX_PLAYING && !rewinding)
2268             m_nitro_sound->stop();
2269     }
2270 }   // updateNitro
2271 
2272 // -----------------------------------------------------------------------------
2273 /** Activates a slipstream effect */
setSlipstreamEffect(float f)2274 void Kart::setSlipstreamEffect(float f)
2275 {
2276     m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_ZIPPER, f);
2277 }   // setSlipstreamEffect
2278 
2279 // -----------------------------------------------------------------------------
2280 /** Called when the kart crashes against another kart.
2281  *  \param k The kart that was hit.
2282  *  \param update_attachments If true the attachment of this kart and the
2283  *          other kart hit will be updated (e.g. bombs will be moved)
2284  */
crashed(AbstractKart * k,bool update_attachments)2285 void Kart::crashed(AbstractKart *k, bool update_attachments)
2286 {
2287     if(update_attachments)
2288     {
2289         assert(k);
2290         getAttachment()->handleCollisionWithKart(k);
2291     }
2292     m_controller->crashed(k);
2293     playCrashSFX(NULL, k);
2294 }   // crashed(Kart, update_attachments
2295 
2296 // -----------------------------------------------------------------------------
2297 /** Kart hits the track with a given material.
2298  *  \param m Material hit, can be NULL if no specific material exists.
2299  *  \param normal The normal of the hit (used to push a kart back, which avoids
2300  *         that karts sometimes can get stuck).
2301  */
crashed(const Material * m,const Vec3 & normal)2302 void Kart::crashed(const Material *m, const Vec3 &normal)
2303 {
2304     if (m && !(m->getCollisionReaction() == Material::RESCUE))
2305         playCrashSFX(m, NULL);
2306 #ifdef DEBUG
2307     // Simple debug output for people playing without sound.
2308     // This makes it easier to see if a kart hit the track (esp.
2309     // after a jump).
2310     // FIXME: This should be removed once the physics are fixed.
2311     if(UserConfigParams::m_physics_debug)
2312     {
2313         // Add a counter to make it easier to see if a new line of
2314         // output was added.
2315         static int counter=0;
2316         Log::info("Kart","Kart %s hit track: %d material %s.",
2317                getIdent().c_str(), counter++,
2318                m ? m->getTexFname().c_str() : "None");
2319     }
2320 #endif
2321 
2322     const LinearWorld *lw = dynamic_cast<LinearWorld*>(World::getWorld());
2323     if(m_kart_properties->getTerrainImpulseType()
2324                              ==KartProperties::IMPULSE_NORMAL &&
2325         m_vehicle->getCentralImpulseTicks()<=0                     )
2326     {
2327         // Restrict impule to plane defined by gravity (i.e. X/Z plane).
2328         // This avoids the problem that karts can be pushed up, e.g. above
2329         // a fence.
2330         btVector3 gravity = m_body->getGravity();
2331         gravity.normalize();
2332         Vec3 impulse =  normal - gravity* btDot(normal, gravity);
2333         if(impulse.getX() || impulse.getZ())
2334             impulse.normalize();
2335         else
2336             impulse = Vec3(0, 0, -1); // Arbitrary
2337         // Impulse depends of kart speed - and speed can be negative
2338         // If the speed is too low, karts can still get stuck into a wall
2339         // so make sure there is always enough impulse to avoid this
2340         float abs_speed = fabsf(getSpeed());
2341         impulse *= ( abs_speed<10 ? 10.0f : sqrt(abs_speed) )
2342                  * m_kart_properties->getCollisionTerrainImpulse();
2343         m_bounce_back_ticks = 0;
2344         impulse = Vec3(0, 0, 0);
2345         //m_vehicle->setTimedCentralImpulse(0.1f, impulse);
2346         m_vehicle->setTimedCentralImpulse(0, impulse);
2347     }
2348     // If there is a quad graph, push the kart towards the previous
2349     // graph node center (we have to use the previous point since the
2350     // kart might have only now reached the new quad, meaning the kart
2351     // would be pushed forward).
2352     else if(m_kart_properties->getTerrainImpulseType()
2353                                  ==KartProperties::IMPULSE_TO_DRIVELINE &&
2354             lw && m_vehicle->getCentralImpulseTicks()<=0 &&
2355             Track::getCurrentTrack()->isPushBackEnabled())
2356     {
2357         int sector = lw->getSectorForKart(this);
2358         if(sector!=Graph::UNKNOWN_SECTOR)
2359         {
2360             // Use the first predecessor node, which is the most
2361             // natural one (i.e. the one on the main driveline).
2362             const DriveNode* dn = DriveGraph::get()->getNode(
2363                 DriveGraph::get()->getNode(sector)->getPredecessor(0));
2364             Vec3 impulse = dn->getCenter() - getXYZ();
2365             impulse.setY(0);
2366             if(impulse.getX() || impulse.getZ())
2367                 impulse.normalize();
2368             else
2369                 impulse = Vec3(0, 0, -1); // Arbitrary
2370             impulse *= m_kart_properties->getCollisionTerrainImpulse();
2371             m_bounce_back_ticks = (uint8_t)stk_config->time2Ticks(0.2f);
2372             m_vehicle->setTimedCentralImpulse(
2373                 (uint16_t)stk_config->time2Ticks(0.1f), impulse);
2374         }
2375 
2376     }
2377     /** If a kart is crashing against the track, the collision is often
2378      *  reported more than once, resulting in a machine gun effect, and too
2379      *  long disabling of the engine. Therefore, this reaction is disabled
2380      *  for 0.5 seconds after a crash.
2381      */
2382     if(m && m->getCollisionReaction() != Material::NORMAL &&
2383         !getKartAnimation())
2384     {
2385 #ifndef SERVER_ONLY
2386         std::string particles = m->getCrashResetParticles();
2387         if (!GUIEngine::isNoGraphics() &&
2388             particles.size() > 0 && UserConfigParams::m_particles_effects > 0)
2389         {
2390             ParticleKind* kind =
2391                 ParticleKindManager::get()->getParticles(particles);
2392             if (kind != NULL)
2393             {
2394                 if (m_collision_particles == NULL)
2395                 {
2396                     Vec3 position(-getKartWidth()*0.35f, 0.06f,
2397                                   getKartLength()*0.5f);
2398                     m_collision_particles  =
2399                         new ParticleEmitter(kind, position, getNode());
2400                 }
2401                 else
2402                 {
2403                     m_collision_particles->setParticleType(kind);
2404                 }
2405             }
2406             else
2407             {
2408                 Log::error("Kart","Unknown particles kind <%s> in material "
2409                                 "crash-reset properties\n", particles.c_str());
2410             }
2411         }
2412 #endif
2413         if (m->getCollisionReaction() == Material::RESCUE)
2414         {
2415             RescueAnimation::create(this);
2416             m_last_factor_engine_sound = 0.0f;
2417         }
2418         else if (m->getCollisionReaction() == Material::PUSH_BACK)
2419         {
2420             // This variable is set to 0.2 in case of a kart-terrain collision
2421             if (m_bounce_back_ticks <= (uint8_t)stk_config->time2Ticks(0.2f))
2422             {
2423                 btVector3 push = m_body->getLinearVelocity().normalized();
2424                 push[1] = 0.1f;
2425                 m_body->applyCentralImpulse( -4000.0f*push );
2426                 m_bounce_back_ticks = (uint8_t)stk_config->time2Ticks(2.0f);
2427             }   // if m_bounce_back_ticks <= 0.2f
2428         }   // if (m->getCollisionReaction() == Material::PUSH_BACK)
2429     }   // if(m && m->getCollisionReaction() != Material::NORMAL &&
2430         //   !getKartAnimation())
2431     m_controller->crashed(m);
2432 }   // crashed(Material)
2433 
2434 // -----------------------------------------------------------------------------
2435 /** Common code used when a kart or a material was hit.
2436  * @param m The material collided into, or NULL if none
2437  * @param k The kart collided into, or NULL if none
2438  */
playCrashSFX(const Material * m,AbstractKart * k)2439 void Kart::playCrashSFX(const Material* m, AbstractKart *k)
2440 {
2441     int ticks_since_start = World::getWorld()->getTicksSinceStart();
2442     if(ticks_since_start-m_ticks_last_crash < 60) return;
2443 
2444     m_ticks_last_crash = ticks_since_start;
2445     // After a collision disable the engine for a short time so that karts
2446     // can 'bounce back' a bit (without this the engine force will prevent
2447     // karts from bouncing back, they will instead stuck towards the obstable).
2448     if(m_bounce_back_ticks == 0)
2449     {
2450         if (getVelocity().length()> 0.555f)
2451         {
2452             const float speed_for_max_volume = 15; //The speed at which the sound plays at maximum volume
2453             const float max_volume = 1; //The maximum volume a sound is played at
2454             const float min_volume = 0.2f; //The minimum volume a sound is played at
2455 
2456             float volume; //The volume the crash sound will be played at
2457 
2458             if (k == NULL) //Collision with wall
2459             {
2460                 volume = sqrt( abs(m_speed / speed_for_max_volume));
2461             }
2462             else
2463             {
2464                 const Vec3 ThisKartVelocity = getVelocity();
2465                 const Vec3 OtherKartVelocity = k->getVelocity();
2466                 const Vec3 VelocityDifference = ThisKartVelocity - OtherKartVelocity;
2467                 const float LengthOfDifference = VelocityDifference.length();
2468 
2469                 volume = sqrt( abs(LengthOfDifference / speed_for_max_volume));
2470             }
2471 
2472             if (volume > max_volume) { volume = max_volume; }
2473             else if (volume < min_volume) { volume = min_volume; }
2474 
2475             SFXBase* crash_sound_emitter = getNextEmitter();
2476             crash_sound_emitter->setVolume(volume);
2477 
2478             // In case that the sfx is longer than 0.5 seconds, only play it if
2479             // it's not already playing.
2480             if (isShielded() || (k != NULL && k->isShielded()))
2481             {
2482                 crash_sound_emitter->play(getSmoothedXYZ(), m_boing_sound);
2483             }
2484             else
2485             {
2486                 int idx = rand() % CRASH_SOUND_COUNT;
2487 
2488                 SFXBuffer* buffer = m_crash_sounds[idx];
2489                 crash_sound_emitter->play(getSmoothedXYZ(), buffer);
2490             }
2491         }    // if lin_vel > 0.555
2492     }   // if m_bounce_back_ticks == 0
2493 }   // playCrashSFX
2494 
2495 // -----------------------------------------------------------------------------
2496 /** Plays a beep sfx.
2497  */
beep()2498 void Kart::beep()
2499 {
2500     // If the custom horn can't play (isn't defined) then play the default one
2501     if (!playCustomSFX(SFXManager::CUSTOM_HORN) &&
2502         !RewindManager::get()->isRewinding())
2503     {
2504         getNextEmitter()->play(getSmoothedXYZ(), m_horn_sound);
2505     }
2506 
2507 } // beep
2508 
2509 // -----------------------------------------------------------------------------
2510 /*
2511     playCustomSFX()
2512 
2513     This function will play a particular character voice for this kart.  It
2514     returns whether or not a character voice sample exists for the particular
2515     event.  If there is no voice sample, a default can be played instead.
2516 
2517     Use entries from the CustomSFX enumeration as a parameter (see
2518     SFXManager::get().hpp).  eg. playCustomSFX(SFXManager::CUSTOM_CRASH)
2519 
2520     Obviously we don't want a certain character voicing multiple phrases
2521     simultaneously.  It just sounds bad.  There are two ways of avoiding this:
2522 
2523     1.  If there is already a voice sample playing for the character
2524         don't play another until it is finished.
2525 
2526     2.  If there is already a voice sample playing for the character
2527         stop the sample, and play the new one.
2528 
2529     Currently we're doing #2.
2530 
2531     rforder
2532 
2533 */
2534 
playCustomSFX(unsigned int type)2535 bool Kart::playCustomSFX(unsigned int type)
2536 {
2537     // (TODO: add back when properly done)
2538     return false;
2539 
2540     /*
2541     bool ret = false;
2542 
2543     // Stop all other character voices for this kart before playing a new one
2544     // we don't want overlapping phrases coming from the same kart
2545     for (unsigned int n = 0; n < SFXManager::NUM_CUSTOMS; n++)
2546     {
2547         if (m_custom_sounds[n] != NULL)
2548         {
2549             // If the sound we're trying to play is already playing
2550             // don't stop it, we'll just let it finish.
2551             if (type != n) m_custom_sounds[n]->stop();
2552         }
2553     }
2554 
2555     if (type < SFXManager::NUM_CUSTOMS)
2556     {
2557         if (m_custom_sounds[type] != NULL)
2558         {
2559             ret = true;
2560             //printf("Kart SFX: playing %s for %s.\n",
2561             //    SFXManager::get()->getCustomTagName(type),
2562             //    m_kart_properties->getIdent().c_str());
2563             // If it's already playing, let it finish
2564             if (m_custom_sounds[type]->getStatus() != SFXManager::SFX_PLAYING)
2565             {
2566                 m_custom_sounds[type]->play();
2567             }
2568         }
2569     }
2570     return ret;
2571      */
2572 }
2573 // ----------------------------------------------------------------------------
2574 /** Updates the physics for this kart: computing the driving force, set
2575  *  steering, handles skidding, terrain impact on kart, ...
2576  *  \param ticks Number if physics time steps - should be 1.
2577  */
updatePhysics(int ticks)2578 void Kart::updatePhysics(int ticks)
2579 {
2580     if (m_controls.getAccel() > 0.0f &&
2581         World::getWorld()->getTicksSinceStart() == 1)
2582     {
2583         if (m_startup_boost > 0.0f)
2584         {
2585             m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_ZIPPER,
2586                 100.0f * m_startup_boost);
2587             m_max_speed->instantSpeedIncrease(MaxSpeed::MS_INCREASE_ZIPPER,
2588                 0.9f * m_startup_boost, m_startup_boost,
2589                 /*engine_force*/200.0f,
2590                 /*duration*/stk_config->time2Ticks(5.0f),
2591                 /*fade_out_time*/stk_config->time2Ticks(5.0f));
2592         }
2593     }
2594     if (m_bounce_back_ticks > 0)
2595         m_bounce_back_ticks -= ticks;
2596 
2597     updateEnginePowerAndBrakes(ticks);
2598 
2599     // apply flying physics if relevant
2600     if (m_flying)
2601         updateFlying();
2602 
2603     m_skidding->update(ticks, isOnGround(), m_controls.getSteer(),
2604                        m_controls.getSkidControl());
2605     if( ( m_skidding->getSkidState() == Skidding::SKID_ACCUMULATE_LEFT ||
2606           m_skidding->getSkidState() == Skidding::SKID_ACCUMULATE_RIGHT  ) &&
2607        !m_skidding->isJumping()                                              )
2608     {
2609         if(m_skid_sound->getStatus()!=SFXBase::SFX_PLAYING && !isWheeless())
2610             m_skid_sound->play(getSmoothedXYZ());
2611     }
2612     else if(m_skid_sound->getStatus()==SFXBase::SFX_PLAYING)
2613     {
2614         m_skid_sound->stop();
2615     }
2616 
2617     float steering = getMaxSteerAngle() * m_skidding->getSteeringFraction();
2618     m_vehicle->setSteeringValue(steering, 0);
2619     m_vehicle->setSteeringValue(steering, 1);
2620 
2621     updateSliding();
2622 
2623     // Cap speed if necessary
2624     const Material *m = getMaterial();
2625 
2626     float min_speed =  m && m->isZipper() ? m->getZipperMinSpeed() : -1.0f;
2627     m_max_speed->setMinSpeed(min_speed);
2628     m_max_speed->update(ticks);
2629 
2630 #ifdef XX
2631     Log::info("Kart","angVel %f %f %f heading %f suspension %f %f %f %f"
2632        ,m_body->getAngularVelocity().getX()
2633        ,m_body->getAngularVelocity().getY()
2634        ,m_body->getAngularVelocity().getZ()
2635        ,getHeading()
2636        ,m_vehicle->getWheelInfo(0).m_raycastInfo.m_suspensionLength
2637        ,m_vehicle->getWheelInfo(1).m_raycastInfo.m_suspensionLength
2638        ,m_vehicle->getWheelInfo(2).m_raycastInfo.m_suspensionLength
2639        ,m_vehicle->getWheelInfo(3).m_raycastInfo.m_suspensionLength
2640        );
2641 #endif
2642 
2643 }   // updatephysics
2644 
2645 //-----------------------------------------------------------------------------
2646 /** Adjust the engine sound effect depending on the speed of the kart. This
2647  *  is called during updateGraphics, i.e. once per rendered frame only.
2648  *  \param dt Time step size.
2649  */
updateEngineSFX(float dt)2650 void Kart::updateEngineSFX(float dt)
2651 {
2652     // Only update SFX during the last substep (otherwise too many SFX commands
2653     // in one frame), and if sfx are enabled
2654     if(!m_engine_sound || !SFXManager::get()->sfxAllowed()  )
2655         return;
2656 
2657     // when going faster, use higher pitch for engine
2658     if(isOnGround())
2659     {
2660         float max_speed = m_kart_properties->getEngineMaxSpeed();
2661 
2662         // Engine noise is based half in total speed, half in fake gears:
2663         // With a sawtooth graph like /|/|/| we get 3 even spaced gears,
2664         // ignoring the gear settings from stk_config, but providing a
2665         // good enough brrrBRRRbrrrBRRR sound effect. Speed factor makes
2666         // it a "staired sawtooth", so more acoustically rich.
2667         float f = max_speed > 0 ? m_speed/max_speed : 1.0f;
2668         // Speed at this stage is not yet capped, reduce the amount beyond 1
2669         if (f> 1.0f) f = 1.0f + (1.0f-1.0f/f);
2670 
2671         float fc = f;
2672         if (fc>1.0f) fc = 1.0f;
2673         float gears = 3.0f * fmod(fc, 0.333334f);
2674         assert(!std::isnan(f));
2675         m_last_factor_engine_sound = (0.9f*f + gears) * 0.35f;
2676         m_engine_sound->setSpeedPosition(0.6f + m_last_factor_engine_sound, getSmoothedXYZ());
2677     }
2678     else
2679       {
2680         // When flying, reduce progressively the sound engine (since we can't accelerate)
2681         m_last_factor_engine_sound *= (1.0f-0.1f*dt);
2682         m_engine_sound->setSpeedPosition(0.6f + m_last_factor_engine_sound, getSmoothedXYZ());
2683         if (m_speed < 0.1f) m_last_factor_engine_sound = 0.0f;
2684       }
2685 }   // updateEngineSFX
2686 
2687 
2688 
2689 //-----------------------------------------------------------------------------
2690 /** Reduces the engine power according to speed
2691  *
2692  *  TODO : find where the physics already apply a linear force decrease
2693  *  TODO : While this work fine, it should ideally be in physics
2694  *         However, the function use some kart properties and parachute
2695  *         effect needs to be applied, so keep both working if moving
2696  *  \param engine_power : the engine power on which to apply the decrease
2697  */
applyAirFriction(float engine_power)2698 float Kart::applyAirFriction(float engine_power)
2699 {
2700     //The physics already do that a certain amount of engine force is needed to keep going
2701     //at a given speed (~39,33 engine force = 1 speed for a mass of 350)
2702     //But it's either too slow to accelerate to a target speed or makes it
2703     //too easy to accelerate farther.
2704     //Instead of making increasing gears have enormous power gaps, apply friction
2705 
2706     float mass_factor = m_kart_properties->getMass()/350.0f;
2707     float compense_linear_slowdown = 39.33f*fabsf(getSpeed())*mass_factor;
2708 
2709     engine_power += compense_linear_slowdown;
2710 
2711     // The result will always be a positive number
2712     float friction_intensity = fabsf(getSpeed());
2713 
2714     // Not a pure quadratic evolution as it would be too brutal
2715     friction_intensity *= sqrt(friction_intensity)*5;
2716 
2717     // Apply parachute physics
2718     // Currently, all karts have the same base friction
2719     // If this is changed, a compensation needs to be added here
2720     if(m_attachment->getType()==Attachment::ATTACH_PARACHUTE)
2721         friction_intensity *= m_kart_properties->getParachuteFriction();
2722 
2723     if (friction_intensity < 0.0f) friction_intensity = 0.0f;
2724 
2725     // We subtract the friction from the engine power
2726     // 1)This is the logical behavior
2727     // 2)That way, engine boosts remain useful at high speed
2728     // 3)It helps heavier karts, who have an higher engine power
2729 
2730     engine_power-=friction_intensity;
2731 
2732     return engine_power;
2733 } //applyAirFriction
2734 
2735 //-----------------------------------------------------------------------------
2736 /** Sets the engine power. It considers the engine specs, items that influence
2737  *  the available power, and braking/steering.
2738  */
updateEnginePowerAndBrakes(int ticks)2739 void Kart::updateEnginePowerAndBrakes(int ticks)
2740 {
2741     updateWeight();
2742     updateNitro(ticks);
2743     float engine_power = getActualWheelForce();
2744 
2745     // apply nitro boost if relevant
2746     if(getSpeedIncreaseTicksLeft(MaxSpeed::MS_INCREASE_NITRO) > 0)
2747     {
2748         engine_power*= m_kart_properties->getNitroEngineMult();
2749     }
2750 
2751     // apply bubblegum physics if relevant
2752     if (m_bubblegum_ticks > 0)
2753     {
2754         engine_power = 0.0f;
2755         m_body->applyTorque(btVector3(0.0,
2756             m_kart_properties->getBubblegumTorque() *
2757             (m_bubblegum_torque_sign ? 1.0f : -1.0f), 0.0));
2758     }
2759 
2760     if(m_controls.getAccel())   // accelerating
2761     {
2762         // For a short time after a collision disable the engine,
2763         // so that the karts can bounce back a bit from the obstacle.
2764         if (m_bounce_back_ticks > 0)
2765             engine_power = 0.0f;
2766         // let a player going backwards accelerate quickly (e.g. if a player
2767         // hits a wall, he needs to be able to start again quickly after
2768         // going backwards)
2769         else if(m_speed < 0.0f)
2770             engine_power *= 5.0f;
2771 
2772         // Lose some traction when skidding, to balance the advantage
2773         if (m_controls.getSkidControl() &&
2774             m_kart_properties->getSkidVisualTime() == 0)
2775             engine_power *= 0.5f;
2776 
2777         // This also applies parachute physics if relevant
2778         engine_power = applyAirFriction(engine_power);
2779 
2780         applyEngineForce(engine_power*m_controls.getAccel());
2781 
2782         // Either all or no brake is set, so test only one to avoid
2783         // resetting all brakes most of the time.
2784         if(m_vehicle->getWheelInfo(0).m_brake &&
2785             !World::getWorld()->isStartPhase())
2786             m_vehicle->setAllBrakes(0);
2787         m_brake_ticks = 0;
2788     }
2789     else // not accelerating
2790     {
2791         //The engine power is still guaranteed >= 0 at this point
2792         float braking_power = engine_power;
2793 
2794         // This also applies parachute physics if relevant
2795         engine_power = applyAirFriction(engine_power);
2796 
2797         if(m_controls.getBrake())
2798         {   // check if the player is currently only slowing down
2799             // or moving backwards
2800             if(m_speed > 0.0f)
2801             {   // Still going forward while braking
2802                 applyEngineForce(engine_power-braking_power*3);
2803                 m_brake_ticks += ticks;
2804                 // Apply the brakes - include the time dependent brake increase
2805                 float f = 1.0f + stk_config->ticks2Time(m_brake_ticks)
2806                                * m_kart_properties->getEngineBrakeTimeIncrease();
2807                 m_vehicle->setAllBrakes(m_kart_properties->getEngineBrakeFactor() * f);
2808             }
2809             else   // m_speed < 0
2810             {
2811                 m_vehicle->setAllBrakes(0);
2812                 // going backward, apply reverse gear ratio (unless he goes
2813                 // too fast backwards)
2814                 if ( -m_speed <  m_max_speed->getCurrentMaxSpeed()
2815                                  *m_kart_properties->getEngineMaxSpeedReverseRatio())
2816                 {
2817                     // The backwards acceleration is artificially increased to
2818                     // allow players to get "unstuck" quicker if they hit e.g.
2819                     // a wall.
2820                     applyEngineForce(engine_power-braking_power*3);
2821                 }
2822                 else  // -m_speed >= max speed on this terrain
2823                 {
2824                     applyEngineForce(0.0f);
2825                 }
2826 
2827             }   // m_speed <00
2828         }
2829         else   // no braking and no acceleration
2830         {
2831             m_brake_ticks = 0;
2832             // lift the foot from throttle, let friction slow it down
2833             assert(!std::isnan(m_controls.getAccel()));
2834             assert(!std::isnan(engine_power));
2835 
2836             // If not giving power (forward or reverse gear), and speed is low
2837             // we are "parking" the kart, so in battle mode we can ambush people
2838             if (std::abs(m_speed) < 5.0f)
2839             {
2840                 // Engine must be 0, otherwise braking is not used at all
2841                 applyEngineForce(0);
2842                 m_vehicle->setAllBrakes(20.0f);
2843             }
2844             else
2845             {
2846                 // This ensure that parachute and air friction are applied
2847                 // and that the kart gracefully slows down
2848                 applyEngineForce(engine_power-braking_power);
2849                 m_vehicle->setAllBrakes(0);
2850             }
2851         }   // no braking and no acceleration
2852     }   // not accelerating
2853 }   // updateEnginePowerAndBrakes
2854 
2855 // ----------------------------------------------------------------------------
2856 /** Handles sliding, i.e. the kart sliding off terrain that is too steep.
2857  *  Dynamically determine friction so that the kart looses its traction
2858  *  when trying to drive on too steep surfaces. Below angles of 0.25 rad,
2859  *  you have full traction; above 0.5 rad angles you have absolutely none;
2860  *  inbetween  there is a linear change in friction. This is done for each
2861  *  wheel individually (since otherwise karts were still able with enough
2862  *  speed to drive on walls - one wheel 'on a wall' would not tilt the
2863  *  kart chassis enough to trigger sliding, but since that wheel had still
2864  *  full friction, give the kart an upwards velocity).
2865  */
updateSliding()2866 void Kart::updateSliding()
2867 {
2868     // Allow the sliding to be disabled per material (for so called
2869     // high adhesion material), which is useful for e.g. banked curves.
2870     // We don't have per-wheel material, so the test for special material
2871     // with high adhesion is done per kart (not per wheel).
2872     const Material * material = getMaterial();
2873     if (material && material->highTireAdhesion())
2874     {
2875         for (int i = 0; i < m_vehicle->getNumWheels(); i++)
2876         {
2877             btWheelInfo &wheel = m_vehicle->getWheelInfo(i);
2878             wheel.m_frictionSlip = m_kart_properties->getFrictionSlip();
2879         }
2880         m_vehicle->setSliding(false);
2881 
2882     }
2883 
2884     // Now test for each wheel if it should be sliding
2885     // -----------------------------------------------
2886     bool enable_sliding = false;
2887 
2888     // We need the 'up' vector, which can be affected by material
2889     // with gravity. So use the body's gravity to determine up:
2890     Vec3 up = -m_body->getGravity();
2891     up.normalize();
2892     for (int i = 0; i < m_vehicle->getNumWheels(); i++)
2893     {
2894         const btWheelInfo &wheel = m_vehicle->getWheelInfo(i);
2895         if (!wheel.m_raycastInfo.m_isInContact) continue;
2896 
2897         const btVector3 &norm = m_vehicle->getWheelInfo(i).m_raycastInfo.m_contactNormalWS;
2898         float distanceFromUp = norm.dot(up);
2899         float friction;
2900         if (distanceFromUp < 0.85f)
2901         {
2902             friction = 0.0f;
2903             enable_sliding = true;
2904         }
2905         else if (distanceFromUp > 0.9f)
2906         {
2907             friction = 1.0f;
2908         }
2909         else
2910         {
2911             friction = (distanceFromUp - 0.85f) / 0.5f;
2912             enable_sliding = true;
2913         }
2914         m_vehicle->getWheelInfo(i).m_frictionSlip = friction * m_kart_properties->getFrictionSlip();
2915     }   // for i < numWheels
2916 
2917     m_vehicle->setSliding(enable_sliding);
2918 }   // updateSliding
2919 
2920 // ----------------------------------------------------------------------------
2921 /** Adjusts kart translation if the kart is flying (in debug mode).
2922  */
updateFlying()2923 void Kart::updateFlying()
2924 {
2925     m_body->setLinearVelocity(m_body->getLinearVelocity() * 0.99f);
2926 
2927     if (m_controls.getAccel())
2928     {
2929         btVector3 velocity = m_body->getLinearVelocity();
2930         if (velocity.length() < 25)
2931         {
2932             float orientation = getHeading();
2933             m_body->applyCentralImpulse(btVector3(100.0f*sinf(orientation), 0.0,
2934                 100.0f*cosf(orientation)));
2935         }
2936     }
2937     else if (m_controls.getBrake())
2938     {
2939         btVector3 velocity = m_body->getLinearVelocity();
2940         if (velocity.length() > -15)
2941         {
2942             float orientation = getHeading();
2943             m_body->applyCentralImpulse(btVector3(-100.0f*sinf(orientation), 0.0,
2944                 -100.0f*cosf(orientation)));
2945         }
2946     }
2947 
2948     if (m_controls.getSteer()!= 0.0f)
2949     {
2950         m_body->applyTorque(btVector3(0.0, m_controls.getSteer()*3500.0f, 0.0));
2951     }
2952 
2953     // dampen any roll while flying, makes the kart hard to control
2954     btVector3 velocity = m_body->getAngularVelocity();
2955     velocity.setX(0);
2956     velocity.setZ(0);
2957     m_body->setAngularVelocity(velocity);
2958 
2959 }   // updateFlying
2960 
2961 // ----------------------------------------------------------------------------
2962 /** Attaches the right model, creates the physics and loads all special
2963  *  effects (particle systems etc.)
2964  *  \param type Type of the kart.
2965  *  \param is_animated_model True if the model is animated.
2966  */
loadData(RaceManager::KartType type,bool is_animated_model)2967 void Kart::loadData(RaceManager::KartType type, bool is_animated_model)
2968 {
2969     bool always_animated = (type == RaceManager::KT_PLAYER &&
2970         RaceManager::get()->getNumLocalPlayers() == 1);
2971     if (!GUIEngine::isNoGraphics())
2972         m_node = m_kart_model->attachModel(is_animated_model, always_animated);
2973 
2974 #ifdef DEBUG
2975     if (m_node)
2976         m_node->setName( (getIdent()+"(lod-node)").c_str() );
2977 #endif
2978 
2979     // Attachment must be created after attachModel, since only then the
2980     // scene node will exist (to which the attachment is added). But the
2981     // attachment is needed in createPhysics (which gets the mass, which
2982     // is dependent on the attachment).
2983     m_attachment.reset(new Attachment(this));
2984     createPhysics();
2985 
2986     m_slipstream.reset(new SlipStream(this));
2987 
2988 #ifndef SERVER_ONLY
2989     m_skidmarks = nullptr;
2990     m_shadow = nullptr;
2991     if (!GUIEngine::isNoGraphics() &&
2992         m_kart_properties->getSkidEnabled() && CVS->isGLSL())
2993     {
2994         m_skidmarks.reset(new SkidMarks(*this));
2995     }
2996 
2997     if (!GUIEngine::isNoGraphics() &&
2998         CVS->isGLSL() && !CVS->isShadowEnabled() && m_kart_properties
2999         ->getShadowMaterial()->getSamplerPath(0) != "unicolor_white")
3000     {
3001         m_shadow.reset(new Shadow(m_kart_properties->getShadowMaterial(),
3002             *this));
3003     }
3004 #endif
3005     World::getWorld()->kartAdded(this, m_node);
3006     m_kart_gfx.reset(
3007         new KartGFX(this, Track::getCurrentTrack()->getIsDuringDay()));
3008     m_skidding.reset(new Skidding(this));
3009     // Create the stars effect
3010     if (!GUIEngine::isNoGraphics())
3011         m_stars_effect.reset(new Stars(this));
3012 
3013 }   // loadData
3014 
3015 // ----------------------------------------------------------------------------
3016 /** Applies engine power to all the wheels that are traction capable,
3017  *  so other parts of code do not have to be adjusted to simulate different
3018  *  kinds of vehicles in the general case, only if they are trying to
3019  *  simulate traction control, diferentials or multiple independent electric
3020  *  engines, they will have to tweak the power in a per wheel basis.
3021  */
applyEngineForce(float force)3022 void Kart::applyEngineForce(float force)
3023 {
3024     assert(!std::isnan(force));
3025     // Split power to simulate a 4WD 40-60, other values possible
3026     // FWD or RWD is a matter of putting a 0 and 1 in the right place
3027     float frontForce = force*0.4f;
3028     float rearForce = force*0.6f;
3029     // Front wheels
3030     for(unsigned int i=0; i<2; i++)
3031     {
3032         m_vehicle->applyEngineForce (frontForce, i);
3033     }
3034     // Rear wheels
3035     for(unsigned int i=2; i<4; i++)
3036     {
3037         m_vehicle->applyEngineForce (rearForce, i);
3038     }
3039 }   // applyEngineForce
3040 
3041 //-----------------------------------------------------------------------------
3042 /** Computes the transform of the graphical kart chasses with regards to the
3043  *  physical chassis. This function is called once the kart comes to rest
3044  *  before the race starts (see World::resetAllKarts). Based on the current
3045  *  physical kart position it computes an (at this stage Y-only) offset by
3046  *  which the graphical chassis is moved so that it appears the way it is
3047  *  designed in blender. This means that the distance of the wheels from the
3048  *  chassis (i.e. suspension) appears as in blender when karts are in rest.
3049  *  See updateGraphics for more details.
3050  */
kartIsInRestNow()3051 void Kart::kartIsInRestNow()
3052 {
3053     AbstractKart::kartIsInRestNow();
3054     m_default_suspension_force = 0.0f;
3055     for (int i = 0; i < m_vehicle->getNumWheels(); i++)
3056     {
3057         const btWheelInfo &wi = m_vehicle->getWheelInfo(i);
3058         m_default_suspension_force += wi.m_raycastInfo.m_suspensionLength;
3059     }
3060 
3061     // The offset 'lowest point' is added to avoid that the
3062     // visual chassis appears in the ground (it could be any
3063     // constant, there is no real reason to use the lowest point
3064     // but that value has worked good in the past). See documentation
3065     // for updateGraphics() for full details.
3066     m_graphical_y_offset = -m_default_suspension_force /
3067         m_vehicle->getNumWheels() + m_kart_model->getLowestPoint();
3068 
3069     m_kart_model->setDefaultSuspension();
3070 }   // kartIsInRestNow
3071 
3072 //-----------------------------------------------------------------------------
3073 
getNextEmitter()3074 SFXBase* Kart::getNextEmitter()
3075 {
3076     m_emitter_id = (m_emitter_id + 1) % EMITTER_COUNT;
3077 
3078     // The emitter is requested when a new sound is to be played.
3079     // Always reset the volume to 1.0f (full), as crashes may
3080     // have altered it. See issue #3596
3081     m_emitters[m_emitter_id]->setVolume(1.0f);
3082 
3083     return m_emitters[m_emitter_id];
3084 }
3085 
3086 //-----------------------------------------------------------------------------
3087 /** Updates the graphics model. It is responsible for positioning the graphical
3088  *  chasses at an 'appropriate' position: typically, the physical model has
3089  *  much longer suspension, so if the graphical chassis would be at the same
3090  *  location as the physical chassis, the wheels would be too far away.
3091  *  Instead the default suspension length is saved once the kart have been
3092  *  settled at start up (see World::resetAllKarts, which just runs several
3093  *  physics-only simulation steps so that karts come to a rest). Then at
3094  *  race time, only the difference between the current suspension length and
3095  *  this default suspension length is used. The graphical kart chassis will be
3096  *  offset so that when the kart is in rest, i.e. suspension length ==
3097  *  default suspension length, the kart will look the way it was modelled in
3098  *  blender. To explain the various offsets used, here a view from the side
3099  *  focusing on the Y axis only (X/Z position of the graphical chassis is
3100  *  identical to the physical chassis):
3101  *
3102  * Y|     | visual kart                |       physical kart
3103  *  |     |                            |
3104  *  |     |                            |
3105  *  |     |                            |
3106  *  |     |                            +-------------COG---------------
3107  *  |     |                            :
3108  *  |     +---------low------          :
3109  *  |     O                            :
3110  *  +--------------------------------------------------------------------------
3111  *                                                                            X
3112  *  'O'   : visual wheel                ':'  : raycast from physics
3113  *  'low' : lowest Y coordinate of      COG  : Center of gravity (at bottom of
3114  *          model                              chassis)
3115  *
3116  *  The visual kart is stored so that if it is shown at (0,0,0) it would be
3117  *  the same as in blender. This on the other hand means, if the kart is shown
3118  *  at the position of the physical chassis (which is at COG in the picture
3119  *  above), the kart and its wheels would be floating in the air (exactly by
3120  *  as much as the suspension length), and the wheels would be exactly at the
3121  *  bottom of the physical chassis (i.e. just on the plane going through COG
3122  *  and parallel to the ground).
3123  *  If we want to align the visual chassis to be the same as the physical
3124  *  chassis, we would need to subtract 'low' from the physical position.
3125  *  If the kart is then displayed at COG.y-low, the bottom of the kart (which
3126  *  is at 'low' above ground) would be at COG.y-low + low = COG.y --> visual
3127  *  and physical chassis are identical.
3128  *
3129  *  Unfortunately, the suspension length used in the physics is much too high,
3130  *  the karts would be way above their wheels, basically disconneccted
3131  *  (typical physical suspension length is around 0.28, while the distance
3132  *  between wheel and chassis in blender is in the order of 0.10 --> so there
3133  *  would be an additional distance of around 0.18 between wheel chassis as
3134  *  designed in blender and in stk - even more if the kart is driving downhill
3135  *  when the suspension extends further to keep contact with the ground).
3136  *  To make the visuals look closer to what they are in blender, an additional
3137  *  offset is added: before the start of a race the physics simulation is run
3138  *  to find a stable position for each kart (see World::resetAllKarts). Once
3139  *  a kart is stable, we save this suspension length in m_graphical_y_offset.
3140  *  This offset is subtracted from the COG of the kart. So if the kart is in
3141  *  rest (i.e. suspenion == default_suspension == m_graphical_y_offset),
3142  *  The kart is showen exactly at the same height above ground as it is in
3143  *  blender. If the suspension is shorter by DY (because the kart is
3144  *  accelerating, the ground goes up, ...), the visual chassis is lowered by
3145  *  DY as well.
3146  *
3147  *  While the above algorithm indeed results in the right position of the
3148  *  visual chassis, in reality the visual chassis is too low. For example,
3149  *  nolok's chassis has its lowest point at the rear at around 0.10 above the
3150  *  ground (and the lowest point overall is 0.05, though this is at the front
3151  *  and so not easily visible), so if the suspension is compressed by more than
3152  *  that, the chassiswill appear to be in the ground. Testing on the sand track
3153  *  shows that the suspension is compressed by 0.12 (and up to 0.16 in some
3154  *  extreme points), which means that the chassis will appear to be in the
3155  *  ground quite easily. Therefore the chassis is actually moved up a bit to
3156  *  avoid this problem. Historically (due to never sorting out that formula
3157  *  properly) the chassis was moved twice as high as its lowest point, e.g.
3158  *  nolok's lowest point is at 0.05, so the whole chassis was raised by 0.05
3159  *  (this was not done by design, but because of a bug ;)  ). Since this visual
3160  *  offset has worked well in the past, the visual chassis is moved by the
3161  *  same amount higher.
3162  *
3163  *  Of course this means that the Y position of the wheels (relative to the
3164  *  visual kart chassis) needs to be adjusted: if the kart is in rest, the
3165  *  wheels are exactly on the ground. If the suspension is shorter, that wheel
3166  *  would appear to be partly in the ground, and if the suspension is longer,
3167  *  the wheel would not touch the ground.
3168  *
3169  *  The wheels must be offset by how much the current suspension length is
3170  *  longer or shorter than the default (i.e. at rest) suspension length.
3171  *  This is done in KartModel (pos is the position of the wheel relative
3172  *  to the visual kart chassis):
3173  *          pos.Y += m_default_physics_suspension[i]
3174  *                  - wi.m_raycastInfo.m_suspensionLength
3175  *  But since the chassis is raised an additional 'getLowestPoint' (see
3176  *  desctiption two paragraphs above), the wheels need to be lowered by that
3177  *  amount so that they still touch the ground (the wheel nodes are child of
3178  *  the chassis scene node, so if the chassis is raised by X, the wheels need
3179  *  to be lowered by X).
3180  *  This function also takes additional graphical effects into account, e.g.
3181  *  a (visual only) jump when skidding, and leaning of the kart.
3182  */
updateGraphics(float dt)3183 void Kart::updateGraphics(float dt)
3184 {
3185     /* (TODO: add back when properly done)
3186     for (int n = 0; n < SFXManager::NUM_CUSTOMS; n++)
3187     {
3188         if (m_custom_sounds[n] != NULL) m_custom_sounds[n]->position(getXYZ());
3189     }
3190      */
3191 #ifndef SERVER_ONLY
3192     if (m_node && isSquashed() &&
3193         m_node->getScale() != core::vector3df(1.0f, 0.5f, 1.0f))
3194         setSquashGraphics();
3195     else if (m_node && !isSquashed() &&
3196         m_node->getScale() != core::vector3df(1.0f, 1.0f, 1.0f))
3197         unsetSquash();
3198 #endif
3199 
3200     // Disable smoothing network body so it doesn't smooth the animation
3201     // for karts in client
3202     if (NetworkConfig::get()->isNetworking() &&
3203         NetworkConfig::get()->isClient() &&
3204         (!getController() || !getController()->isLocalPlayerController()))
3205     {
3206         if (m_kart_animation && SmoothNetworkBody::isEnabled())
3207         {
3208             SmoothNetworkBody::setEnable(false);
3209         }
3210         else if (!m_kart_animation && !SmoothNetworkBody::isEnabled())
3211         {
3212             SmoothNetworkBody::setEnable(true);
3213             SmoothNetworkBody::reset();
3214             SmoothNetworkBody::setSmoothedTransform(getTrans());
3215         }
3216     }
3217 
3218     if (m_kart_animation)
3219         m_kart_animation->updateGraphics(dt);
3220 
3221     for (int i = 0; i < EMITTER_COUNT; i++)
3222         m_emitters[i]->setPosition(getXYZ());
3223     m_skid_sound->setPosition(getSmoothedXYZ());
3224     m_nitro_sound->setPosition(getSmoothedXYZ());
3225 
3226     m_attachment->updateGraphics(dt);
3227 
3228     // update star effect (call will do nothing if stars are not activated)
3229     // Remove it if no invulnerability
3230     if (m_stars_effect)
3231     {
3232         if (!isInvulnerable() && m_stars_effect->isEnabled())
3233         {
3234             m_stars_effect->reset();
3235             m_stars_effect->update(1);
3236         }
3237         else
3238             m_stars_effect->update(dt);
3239     }
3240 
3241     // Update particle effects (creation rate, and emitter size
3242     // depending on speed)
3243     m_kart_gfx->update(dt);
3244     if (m_collision_particles) m_collision_particles->update(dt);
3245 
3246     // --------------------------------------------------------
3247     float nitro_frac = 0;
3248     if ( (m_controls.getNitro() || m_min_nitro_ticks > 0) &&
3249          m_collected_energy > 0                               )
3250     {
3251         // fabs(speed) is important, otherwise the negative number will
3252         // become a huge unsigned number in the particle scene node!
3253         nitro_frac = fabsf(getSpeed()) / (m_kart_properties->getEngineMaxSpeed());
3254         // The speed of the kart can be higher (due to powerups) than
3255         // the normal maximum speed of the kart.
3256         if(nitro_frac>1.0f) nitro_frac = 1.0f;
3257     }
3258     m_kart_gfx->updateNitroGraphics(nitro_frac);
3259 
3260     // Handle leaning of karts
3261     // -----------------------
3262     // Note that we compare with maximum speed of the kart, not
3263     // maximum speed including terrain effects. This avoids that
3264     // leaning might get less if a kart gets a special that increases
3265     // its maximum speed, but not the current speed (by much). On the
3266     // other hand, that ratio can often be greater than 1.
3267 
3268     float speed_frac = m_speed / m_kart_properties->getEngineMaxSpeed();
3269     float steer_frac = m_skidding->getSteeringFraction();
3270     const float roll_speed = m_kart_properties->getLeanSpeed() * DEGREE_TO_RAD;
3271 
3272     if(speed_frac > 0.8f && fabsf(steer_frac)>0.2f)
3273     {
3274         // Use steering and speed ^ 2,
3275         // which means less effect at lower steering and speed.
3276         speed_frac = std::min(speed_frac - 0.6f, 1.0f);
3277         steer_frac = (steer_frac+0.25f)*0.8f;
3278         const float f = m_skidding->getSteeringFraction();
3279         const float max_lean = -m_kart_properties->getLeanMax() * DEGREE_TO_RAD
3280                              * f * speed_frac * speed_frac;
3281 
3282         int max_lean_sign = extract_sign(max_lean);
3283         m_current_lean += max_lean_sign * dt* roll_speed;
3284         if(  (max_lean > 0 && m_current_lean > max_lean)
3285            ||(max_lean < 0 && m_current_lean < max_lean))
3286             m_current_lean = max_lean;
3287     }
3288     else if(m_current_lean!=0.0f)
3289     {
3290         // Disable any potential roll factor that is still applied
3291         int lean_sign = extract_sign(m_current_lean);
3292         m_current_lean -= lean_sign * dt * roll_speed;
3293         if (lean_sign != extract_sign(m_current_lean))
3294             m_current_lean = 0.0f;
3295     }
3296 
3297     // If the kart is leaning, part of the kart might end up 'in' the track.
3298     // To avoid this, raise the kart enough to offset the leaning.
3299     float lean_height = tanf(m_current_lean) * getKartWidth()*0.5f;
3300 
3301     Moveable::updateSmoothedGraphics(dt);
3302 
3303     // Update the skidding jump height:
3304     Vec3 center_shift(0, 0, 0);
3305     float jump_height = m_skidding->updateGraphics(dt);
3306     center_shift.setY(jump_height + fabsf(lean_height) + m_graphical_y_offset);
3307     center_shift = getSmoothedTrans().getBasis() * center_shift;
3308 
3309     float heading = m_skidding->getVisualSkidRotation();
3310     Moveable::updateGraphics(center_shift,
3311         btQuaternion(heading, 0, -m_current_lean));
3312 
3313     static video::SColor pink(255, 255, 133, 253);
3314     static video::SColor green(255, 61, 87, 23);
3315 
3316 #ifndef SERVER_ONLY
3317     // draw skidmarks if relevant (we force pink skidmarks on when hitting
3318     // a bubblegum)
3319     if (World::getWorld()->getPhase() !=
3320         WorldStatus::IN_GAME_MENU_PHASE &&
3321         m_kart_properties->getSkidEnabled() && m_skidmarks)
3322     {
3323         m_skidmarks->update(dt,
3324             m_bubblegum_ticks > 0,
3325             (m_bubblegum_ticks > 0
3326                 ? (m_has_caught_nolok_bubblegum ? &green
3327                     : &pink)
3328                 : NULL));
3329     }
3330 #endif
3331 
3332     // m_speed * dt is the distance the kart has moved, which determines
3333     // how much the wheels need to rotate.
3334     m_kart_model->update(dt, m_speed * dt, getSteerPercent(), m_speed,
3335         m_current_lean);
3336 
3337 #ifndef SERVER_ONLY
3338     // Determine the shadow position from the terrain Y position. This
3339     // leaves the shadow on the ground even if the kart is jumping because
3340     // of skidding (shadows are disabled when wheel are not on the track).
3341     if (m_shadow)
3342     {
3343         const bool emergency = getKartAnimation() != NULL;
3344         m_shadow->update(isOnGround() && !emergency);
3345     }
3346 #endif
3347 
3348     handleMaterialGFX(dt);
3349     updateEngineSFX(dt);
3350     handleMaterialSFX();
3351 }   // updateGraphics
3352 
3353 // ----------------------------------------------------------------------------
getVisualRotation() const3354 btQuaternion Kart::getVisualRotation() const
3355 {
3356     return getRotation()
3357          * btQuaternion(m_skidding->getVisualSkidRotation(), 0, 0);
3358 }   // getVisualRotation
3359 
3360 // ----------------------------------------------------------------------------
3361 /** Sets a text that is being displayed on top of a kart. This can be 'leader'
3362  *  for the leader kart in a FTL race, the name of a driver, or even debug
3363  *  output.
3364  *  \param text The text to display
3365  */
setOnScreenText(const core::stringw & text)3366 void Kart::setOnScreenText(const core::stringw& text)
3367 {
3368 #ifndef SERVER_ONLY
3369     if (GUIEngine::isNoGraphics())
3370         return;
3371 
3372     BoldFace* bold_face = font_manager->getFont<BoldFace>();
3373     STKTextBillboard* tb =
3374         new STKTextBillboard(
3375         GUIEngine::getSkin()->getColor("font::bottom"),
3376         GUIEngine::getSkin()->getColor("font::top"),
3377         getNode(), irr_driver->getSceneManager(), -1,
3378         core::vector3df(0.0f, 1.5f, 0.0f),
3379         core::vector3df(0.5f, 0.5f, 0.5f));
3380     if (CVS->isGLSL())
3381         tb->init(text, bold_face);
3382     else
3383         tb->initLegacy(text, bold_face);
3384     tb->drop();
3385     // No need to store the reference to the billboard scene node:
3386     // It has one reference to the parent, and will get deleted
3387     // when the parent is deleted.
3388 #endif
3389 }   // setOnScreenText
3390 
3391 // ------------------------------------------------------------------------
3392 /** Returns the normal of the terrain the kart is over atm. This is
3393   * defined even if the kart is flying. */
getNormal() const3394 const Vec3& Kart::getNormal() const
3395 {
3396     return m_terrain_info->getNormal();
3397 } // getNormal
3398 
3399 // ------------------------------------------------------------------------
3400 /** Returns a more recent different previous position */
getRecentPreviousXYZ() const3401 const Vec3& Kart::getRecentPreviousXYZ() const
3402 {
3403     //Not the most recent, because the angle variations would be too
3404     //irregular on some tracks whose roads are not smooth enough
3405     return m_previous_xyz[m_xyz_history_size/5];
3406 }   // getRecentPreviousXYZ
3407 
3408 // ------------------------------------------------------------------------
playSound(SFXBuffer * buffer)3409 void Kart::playSound(SFXBuffer* buffer)
3410 {
3411     if (!RewindManager::get()->isRewinding())
3412         getNextEmitter()->play(getSmoothedXYZ(), buffer);
3413 }   // playSound
3414 
3415 // ------------------------------------------------------------------------
getColor() const3416 const video::SColor& Kart::getColor() const
3417 {
3418     return m_kart_properties->getColor();
3419 } // getColor
3420 
3421 // ------------------------------------------------------------------------
isVisible() const3422 bool Kart::isVisible() const
3423 {
3424     return m_node && m_node->isVisible();
3425 } // isVisible
3426 
3427 /* EOF */
3428