~ubuntu-branches/ubuntu/precise/supertuxkart/precise

« back to all changes in this revision

Viewing changes to src/karts/kart.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger
  • Date: 2011-02-24 22:36:25 UTC
  • mfrom: (1.1.9 upstream) (6.1.4 sid)
  • Revision ID: james.westby@ubuntu.com-20110224223625-ygrjfpg92obovuch
Tags: 0.7+dfsg1-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//  $Id: kart.cpp 3096 2009-02-02 14:26:45Z hikerstk $
 
1
//  $Id: kart.cpp 7118 2010-12-20 22:02:46Z hikerstk $
2
2
//
3
3
//  SuperTuxKart - a fun racing game with go-kart
4
4
//  Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
22
22
 
23
23
#include <math.h>
24
24
#include <iostream>
25
 
 
26
 
#define _WINSOCKAPI_
27
 
#include <plib/ssg.h>
28
 
 
29
 
#include "bullet/Demos/OpenGL/GL_ShapeDrawer.h"
30
 
#include "loader.hpp"
31
 
#include "items/item_manager.hpp"
32
 
#include "file_manager.hpp"
33
 
#include "user_config.hpp"
34
 
#include "material_manager.hpp"
35
 
#include "audio/sound_manager.hpp"
 
25
#include <algorithm> // for min and max
 
26
 
 
27
#include "audio/music_manager.hpp"
36
28
#include "audio/sfx_manager.hpp"
37
29
#include "audio/sfx_base.hpp"
 
30
#include "config/user_config.hpp"
 
31
#include "graphics/camera.hpp"
 
32
#include "graphics/material_manager.hpp"
38
33
#include "graphics/nitro.hpp"
39
34
#include "graphics/shadow.hpp"
40
35
#include "graphics/skid_marks.hpp"
 
36
#include "graphics/slip_stream.hpp"
41
37
#include "graphics/smoke.hpp"
42
 
#include "gui/menu_manager.hpp"
43
 
#include "gui/race_gui.hpp"
 
38
#include "graphics/water_splash.hpp"
 
39
#include "modes/world.hpp"
 
40
#include "io/file_manager.hpp"
 
41
#include "items/item_manager.hpp"
 
42
#include "karts/controller/end_controller.hpp"
44
43
#include "karts/kart_model.hpp"
45
44
#include "karts/kart_properties_manager.hpp"
46
45
#include "network/race_state.hpp"
48
47
#include "physics/btKart.hpp"
49
48
#include "physics/btUprightConstraint.hpp"
50
49
#include "physics/physics.hpp"
 
50
#include "race/history.hpp"
51
51
#include "tracks/track.hpp"
52
52
#include "utils/constants.hpp"
53
 
#include "utils/coord.hpp"
54
 
#include "utils/ssg_help.hpp"
55
 
#include "audio/sfx_manager.hpp"
56
53
 
57
54
#if defined(WIN32) && !defined(__CYGWIN__)
58
55
   // Disable warning for using 'this' in base member initializer list
59
56
#  pragma warning(disable:4355)
60
57
#endif
61
58
 
62
 
Kart::Kart (const std::string& kart_name, int position,
63
 
            const btTransform& init_transform) 
 
59
/** The kart constructor. 
 
60
 *  \param ident  The identifier for the kart model to use.
 
61
 *  \param position The position (or rank) for this kart (between 1 and
 
62
 *         number of karts). This is used to determine the start position.
 
63
 *  \param init_transform  The initial position and rotation for this kart.
 
64
 */
 
65
Kart::Kart (const std::string& ident, int position,
 
66
            const btTransform& init_transform)
64
67
     : TerrainInfo(1),
65
 
       Moveable(), m_attachment(this), m_powerup(this)
 
68
       Moveable(), EmergencyAnimation(this), MaxSpeed(this), m_powerup(this)
66
69
 
67
70
#if defined(WIN32) && !defined(__CYGWIN__)
68
71
#  pragma warning(1:4355)
69
72
#endif
70
73
{
71
 
    m_kart_properties      = kart_properties_manager->getKart(kart_name);
 
74
    m_kart_properties      = kart_properties_manager->getKart(ident);
 
75
    assert(m_kart_properties != NULL);
 
76
    // We have to take a copy of the kart model, since otherwise
 
77
    // the animations will be mixed up (i.e. different instances of
 
78
    // the same model will set different animation frames).
 
79
    // Technically the mesh in m_kart_model needs to be grab'ed and
 
80
    // released when the kart is deleted, but since the original 
 
81
    // kart_model is stored in the kart_properties all the time,
 
82
    // there is no risk of a mesh being deleted to early.
 
83
    m_kart_model           = m_kart_properties->getKartModelCopy();
72
84
    m_initial_position     = position;
 
85
    m_race_position        = position;
73
86
    m_collected_energy     = 0;
74
 
    m_eliminated           = false;
75
87
    m_finished_race        = false;
76
88
    m_finish_time          = 0.0f;
77
89
    m_shadow_enabled       = false;
78
90
    m_shadow               = NULL;
79
91
    m_smoke_system         = NULL;
 
92
    m_water_splash_system  = NULL;
80
93
    m_nitro                = NULL;
 
94
    m_slipstream           = NULL;
81
95
    m_skidmarks            = NULL;
82
 
 
 
96
    m_camera               = NULL;
 
97
    m_controller           = NULL;
 
98
    m_saved_controller     = NULL;
 
99
    m_flying               = false;
 
100
    
83
101
    m_view_blocked_by_plunger = 0;
84
 
    
 
102
 
 
103
    // Initialize custom sound vector (TODO: add back when properly done)
 
104
    // m_custom_sounds.resize(SFXManager::NUM_CUSTOMS);
 
105
 
85
106
    // Set position and heading:
86
 
    m_reset_transform      = init_transform;
87
 
 
88
 
    // Neglecting the roll resistance (which is small for high speeds compared
89
 
    // to the air resistance), maximum speed is reached when the engine
90
 
    // power equals the air resistance force, resulting in this formula:
91
 
    m_max_speed               = m_kart_properties->getMaxSpeed();
92
 
    m_max_speed_reverse_ratio = m_kart_properties->getMaxSpeedReverseRatio();
 
107
    m_reset_transform         = init_transform;
93
108
    m_speed                   = 0.0f;
94
 
 
95
 
    // Setting rescue to false is important! If rescue is set when reset() is
96
 
    // called, it is assumed that this was triggered by a restart, and that
97
 
    // the vehicle must be added back to the physics world. Since reset() is
98
 
    // also called at the very start, it must be guaranteed that rescue is
99
 
    // not set.
100
 
    m_rescue                  = false;
101
109
    m_wheel_rotation          = 0;
102
110
 
103
 
    m_engine_sound = sfx_manager->newSFX(m_kart_properties->getEngineSfxType());
104
 
    m_beep_sound   = sfx_manager->newSFX(  SFXManager::SOUND_BEEP             );
105
 
    m_crash_sound  = sfx_manager->newSFX(  SFXManager::SOUND_CRASH            );
106
 
    m_skid_sound   = sfx_manager->newSFX(  SFXManager::SOUND_SKID             );
107
 
    m_goo_sound    = sfx_manager->newSFX(  SFXManager::SOUND_GOO              );
108
 
    
 
111
    // Create SFXBase for each custom sound (TODO: add back when properly done)
 
112
    /*
 
113
    for (int n = 0; n < SFXManager::NUM_CUSTOMS; n++)
 
114
    {
 
115
        int id = m_kart_properties->getCustomSfxId((SFXManager::CustomSFX)n);
 
116
 
 
117
        // If id == -1 the custom sound was not defined in the .irrkart config file
 
118
        if (id != -1)
 
119
        {
 
120
            m_custom_sounds[n] = sfx_manager->newSFX(id);
 
121
        }
 
122
    }*/
 
123
 
 
124
    m_engine_sound  = sfx_manager->createSoundSource(m_kart_properties->getEngineSfxType());
 
125
    m_beep_sound    = sfx_manager->createSoundSource( "beep"  );
 
126
    m_crash_sound   = sfx_manager->createSoundSource( "crash" );
 
127
    m_goo_sound     = sfx_manager->createSoundSource( "goo"   );
 
128
    m_skid_sound    = sfx_manager->createSoundSource( "skid"  );
 
129
    m_terrain_sound          = NULL;
 
130
    m_previous_terrain_sound = NULL;
 
131
 
109
132
    if(!m_engine_sound)
110
133
    {
111
134
        fprintf(stdout, "Error: Could not allocate a sfx object for the kart. Further errors may ensue!\n");
112
135
    }
113
136
 
114
137
    loadData();
 
138
 
115
139
    reset();
116
140
}   // Kart
117
141
 
118
142
// -----------------------------------------------------------------------------
119
 
 
120
 
btTransform Kart::getKartHeading(const float customPitch)
121
 
{
122
 
    btTransform trans = this->getTrans();
123
 
    
124
 
    // get heading=trans.getBasis*(0,1,0) ... so save the multiplication:
125
 
    btVector3 direction(trans.getBasis()[0][1],
126
 
                        trans.getBasis()[1][1],
127
 
                        trans.getBasis()[2][1]);
128
 
    float heading=atan2(-direction.getX(), direction.getY());
129
 
    
130
 
    TerrainInfo::update(this->getXYZ());
131
 
    float pitch = (customPitch == -1 ? getTerrainPitch(heading) : customPitch);
132
 
    
 
143
/** Saves the old controller in m_saved_controller and stores a new 
 
144
 *  controller. The save controller is needed in case of a reset.
 
145
 *  \param controller The new controller to use (atm it's always an
 
146
 *         end controller).
 
147
 */
 
148
void Kart::setController(Controller *controller)
 
149
{
 
150
    assert(m_saved_controller==NULL);
 
151
    m_saved_controller = m_controller;
 
152
    m_controller       = controller;
 
153
}   // setController
 
154
 
 
155
// -----------------------------------------------------------------------------
 
156
/** Returns a transform that will align an object with the kart: the heading 
 
157
 *  and the pitch will be set appropriately. A custom pitch value can be 
 
158
 *  specified in order to overwrite the terrain pitch (which would be used
 
159
 *  otherwise).
 
160
 *  \param customPitch Pitch value to overwrite the terrain pitch.
 
161
 */
 
162
btTransform Kart::getKartTransform(const float customPitch)
 
163
{
 
164
    btTransform trans = getTrans();
 
165
 
 
166
    float pitch = (customPitch == -1 ? getTerrainPitch(getHeading()) : customPitch);
 
167
 
133
168
    btMatrix3x3 m;
134
 
    m.setEulerZYX(pitch, 0.0f, heading);
 
169
    m.setEulerYPR(-getHeading(), pitch, 0.0f);
135
170
    trans.setBasis(m);
136
 
    
 
171
 
137
172
    return trans;
138
 
}   // getKartHeading
 
173
}   // getKartTransform
139
174
 
140
175
// ----------------------------------------------------------------------------
 
176
/** Creates the physical representation of this kart. Atm it uses the actual
 
177
 *  extention of the kart model to determine the size of the collision body.
 
178
 */
141
179
void Kart::createPhysics()
142
180
{
143
181
    // First: Create the chassis of the kart
144
182
    // -------------------------------------
145
 
    const KartModel *km = m_kart_properties->getKartModel();
146
 
    float kart_width  = km->getWidth();
147
 
    float kart_length = km->getLength();
148
 
    float kart_height = km->getHeight();
 
183
    float kart_width  = getKartWidth();
 
184
    float kart_length = getKartLength();
 
185
    float kart_height = getKartHeight();
149
186
 
150
187
    btBoxShape *shape = new btBoxShape(btVector3(0.5f*kart_width,
151
 
                                                 0.5f*kart_length,
152
 
                                                 0.5f*kart_height));
 
188
                                                 0.5f*kart_height,
 
189
                                                 0.5f*kart_length));
153
190
    btTransform shiftCenterOfGravity;
154
191
    shiftCenterOfGravity.setIdentity();
155
 
    // Shift center of gravity downwards, so that the kart 
156
 
    // won't topple over too easy. 
157
 
    shiftCenterOfGravity.setOrigin(getGravityCenterShift());
 
192
    // Shift center of gravity downwards, so that the kart
 
193
    // won't topple over too easy.
 
194
    shiftCenterOfGravity.setOrigin(m_kart_properties->getGravityCenterShift());
158
195
    m_kart_chassis.addChildShape(shiftCenterOfGravity, shape);
159
196
 
160
197
    // Set mass and inertia
167
204
    trans.setIdentity();
168
205
    createBody(mass, trans, &m_kart_chassis);
169
206
    m_user_pointer.set(this);
170
 
    m_body->setDamping(m_kart_properties->getChassisLinearDamping(), 
 
207
    m_body->setDamping(m_kart_properties->getChassisLinearDamping(),
171
208
                       m_kart_properties->getChassisAngularDamping() );
172
209
 
173
210
    // Reset velocities
177
214
 
178
215
    // Create the actual vehicle
179
216
    // -------------------------
180
 
    m_vehicle_raycaster = 
181
 
        new btDefaultVehicleRaycaster(RaceManager::getWorld()->getPhysics()->getPhysicsWorld());
 
217
    m_vehicle_raycaster =
 
218
        new btDefaultVehicleRaycaster(World::getWorld()->getPhysics()->getPhysicsWorld());
182
219
    m_tuning  = new btKart::btVehicleTuning();
183
 
        m_tuning->m_maxSuspensionTravelCm = m_kart_properties->getSuspensionTravelCM();
 
220
    m_tuning->m_maxSuspensionTravelCm = m_kart_properties->getSuspensionTravelCM();
184
221
    m_vehicle = new btKart(*m_tuning, m_body, m_vehicle_raycaster,
185
222
                           m_kart_properties->getTrackConnectionAccel());
186
223
 
187
224
    // never deactivate the vehicle
188
225
    m_body->setActivationState(DISABLE_DEACTIVATION);
189
 
    m_vehicle->setCoordinateSystem(/*right: */ 0,  /*up: */ 2,  /*forward: */ 1);
190
 
    
 
226
    m_vehicle->setCoordinateSystem(/*right: */ 0,  /*up: */ 1,  /*forward: */ 2);
 
227
 
191
228
    // Add wheels
192
229
    // ----------
193
230
    float wheel_radius    = m_kart_properties->getWheelRadius();
194
231
    float suspension_rest = m_kart_properties->getSuspensionRest();
195
232
 
196
 
    btVector3 wheel_direction(0.0f, 0.0f, -1.0f);
197
 
    btVector3 wheel_axle(1.0f,0.0f,0.0f);
 
233
    btVector3 wheel_direction(0.0f, -1.0f, 0.0f);
 
234
    btVector3 wheel_axle(-1.0f, 0.0f, 0.0f);
198
235
 
199
236
    for(unsigned int i=0; i<4; i++)
200
237
    {
201
238
        bool is_front_wheel = i<2;
202
239
        btWheelInfo& wheel = m_vehicle->addWheel(
203
 
                            m_kart_properties->getKartModel()->getWheelPhysicsPosition(i), 
 
240
                            m_kart_model->getWheelPhysicsPosition(i),
204
241
                            wheel_direction, wheel_axle, suspension_rest,
205
242
                            wheel_radius, *m_tuning, is_front_wheel);
206
243
        wheel.m_suspensionStiffness      = m_kart_properties->getSuspensionStiffness();
212
249
    // Obviously these allocs have to be properly managed/freed
213
250
    btTransform t;
214
251
    t.setIdentity();
215
 
    m_uprightConstraint=new btUprightConstraint(*m_body, t);
 
252
    m_uprightConstraint=new btUprightConstraint(this, t);
216
253
    m_uprightConstraint->setLimit(m_kart_properties->getUprightTolerance());
217
254
    m_uprightConstraint->setBounce(0.0f);
218
255
    m_uprightConstraint->setMaxLimitForce(m_kart_properties->getUprightMaxForce());
219
256
    m_uprightConstraint->setErp(1.0f);
220
257
    m_uprightConstraint->setLimitSoftness(1.0f);
221
258
    m_uprightConstraint->setDamping(0.0f);
222
 
    RaceManager::getWorld()->getPhysics()->addKart(this);
223
 
 
224
 
    //create the engine sound
 
259
    World::getWorld()->getPhysics()->addKart(this);
 
260
 
 
261
}   // createPhysics
 
262
 
 
263
// ----------------------------------------------------------------------------
 
264
 
 
265
void Kart::flyUp()
 
266
{
 
267
    m_flying = true;
 
268
    Moveable::flyUp();
 
269
}
 
270
 
 
271
void Kart::flyDown()
 
272
{
 
273
    if (isNearGround())
 
274
    {
 
275
        stopFlying();
 
276
        m_flying = false;
 
277
    }
 
278
    else
 
279
    {
 
280
        Moveable::flyDown();
 
281
    }
 
282
}
 
283
 
 
284
// ----------------------------------------------------------------------------
 
285
/** Starts the engine sound effect. Called once the track intro phase is over.
 
286
 */
 
287
void Kart::startEngineSFX()
 
288
{
225
289
    if(m_engine_sound)
226
290
    {
227
291
        m_engine_sound->speed(0.6f);
228
 
        m_engine_sound->loop();
 
292
        m_engine_sound->setLoop(true);
229
293
        m_engine_sound->play();
230
294
    }
231
 
}   // createPhysics
 
295
}   // startEngineSFX
232
296
 
233
 
// -----------------------------------------------------------------------------
234
 
Kart::~Kart() 
 
297
// ----------------------------------------------------------------------------
 
298
/** The destructor frees the memory of this kart, but note that the actual kart
 
299
 *  model is still stored in the kart_properties (m_kart_model variable), so 
 
300
 *  it is not reloaded).
 
301
 */
 
302
Kart::~Kart()
235
303
{
236
 
    //stop the engine sound
237
 
    if(m_engine_sound)
 
304
    // Delete all custom sounds (TODO: add back when properly done)
 
305
    /*
 
306
    for (int n = 0; n < SFXManager::NUM_CUSTOMS; n++)
238
307
    {
239
 
        m_engine_sound->stop();
240
 
    }
 
308
        if (m_custom_sounds[n] != NULL)
 
309
            sfx_manager->deleteSFX(m_custom_sounds[n]);
 
310
    }*/
 
311
 
241
312
    sfx_manager->deleteSFX(m_engine_sound );
242
 
    sfx_manager->deleteSFX(m_beep_sound   );
243
313
    sfx_manager->deleteSFX(m_crash_sound  );
244
314
    sfx_manager->deleteSFX(m_skid_sound   );
245
315
    sfx_manager->deleteSFX(m_goo_sound    );
246
 
    
247
 
    if(m_smoke_system) ssgDeRefDelete(m_smoke_system);
248
 
    if(m_nitro)        ssgDeRefDelete(m_nitro);
 
316
    sfx_manager->deleteSFX(m_beep_sound   );
 
317
    if(m_terrain_sound)          sfx_manager->deleteSFX(m_terrain_sound);
 
318
    if(m_previous_terrain_sound) sfx_manager->deleteSFX(m_previous_terrain_sound);
 
319
    if(m_smoke_system)        delete m_smoke_system;
 
320
    if(m_water_splash_system) delete m_water_splash_system;
 
321
    if(m_nitro)               delete m_nitro;
 
322
    if(m_slipstream)          delete m_slipstream;
249
323
 
250
 
    ssgDeRefDelete(m_shadow);
 
324
    delete m_shadow;
251
325
 
252
326
    if(m_skidmarks) delete m_skidmarks ;
253
327
 
254
 
    RaceManager::getWorld()->getPhysics()->removeKart(this);
 
328
    World::getWorld()->getPhysics()->removeKart(this);
255
329
    delete m_vehicle;
256
330
    delete m_tuning;
257
331
    delete m_vehicle_raycaster;
260
334
    {
261
335
        delete m_kart_chassis.getChildShape(i);
262
336
    }
 
337
    delete m_kart_model;
 
338
    if(m_controller)
 
339
        delete m_controller;
 
340
    if(m_saved_controller)
 
341
        delete m_saved_controller;
 
342
    if (m_camera) delete m_camera;
263
343
}   // ~Kart
264
344
 
265
345
//-----------------------------------------------------------------------------
266
 
void Kart::eliminate()
267
 
{
268
 
    m_eliminated = true;
269
 
    RaceManager::getWorld()->getPhysics()->removeKart(this);
270
 
 
271
 
    // make the kart invisible by placing it way under the track
272
 
    sgVec3 hell; hell[0]=0.0f; hell[1]=0.0f; hell[2] = -10000.0f;
273
 
    getModelTransform()->setTransform(hell);
274
 
}   // eliminate
275
 
 
276
 
//-----------------------------------------------------------------------------
277
 
/** Returns true if the kart is 'resting'
278
 
 *
279
 
 * Returns true if the kart is 'resting', i.e. (nearly) not moving.
 
346
/** Returns true if the kart is 'resting', i.e. (nearly) not moving.
280
347
 */
281
348
bool Kart::isInRest() const
282
349
{
283
 
    return fabs(m_body->getLinearVelocity ().z())<0.2;
 
350
    return fabs(m_body->getLinearVelocity ().y())<0.2;
284
351
}  // isInRest
285
352
 
286
353
//-----------------------------------------------------------------------------
295
362
}   // adjustSpeed
296
363
 
297
364
//-----------------------------------------------------------------------------
 
365
/** Caps the speed at a given value. If necessary the kart will 
 
366
 *  instantaneously change its speed.
 
367
 *  \param max_speed Maximum speed of the kart.
 
368
 */
 
369
void Kart::capSpeed(float max_speed)
 
370
{
 
371
    if ( m_speed >  max_speed && isOnGround() )
 
372
    {
 
373
        const float velocity_ratio = max_speed/m_speed;
 
374
        btVector3 velocity         = getBody()->getLinearVelocity();
 
375
        velocity *= velocity_ratio;
 
376
        getVehicle()->getRigidBody()->setLinearVelocity( velocity );
 
377
    }
 
378
 
 
379
}   // capSpeed
 
380
 
 
381
//-----------------------------------------------------------------------------
298
382
/** This method is to be called every time the mass of the kart is updated,
299
383
 *  which includes attaching an anvil to the kart (and detaching).
300
384
 */
308
392
}   // updatedWeight
309
393
 
310
394
//-----------------------------------------------------------------------------
 
395
/** Reset before a new race. It will remove all attachments, and
 
396
 *  puts the kart back at its original start position.
 
397
 */
311
398
void Kart::reset()
312
399
{
313
 
    // If the kart was eliminated or rescued, the body was removed from the
314
 
    // physics world. Add it again.
315
 
    if(m_eliminated || m_rescue)
316
 
    {
317
 
        RaceManager::getWorld()->getPhysics()->addKart(this);
318
 
    }
319
 
 
 
400
    if (m_flying)
 
401
    {
 
402
        m_flying = false;
 
403
        stopFlying();
 
404
    }
 
405
    
 
406
    EmergencyAnimation::reset();
 
407
    MaxSpeed::reset();
 
408
    if (m_camera)
 
409
    {
 
410
        m_camera->reset();
 
411
        m_camera->setInitialTransform();
 
412
    }
 
413
    
 
414
    // Stop any animations currently being played.
 
415
    m_kart_model->setAnimation(KartModel::AF_DEFAULT);
 
416
    // If the controller was replaced (e.g. replaced by end controller), 
 
417
    //  restore the original controller. 
 
418
    if(m_saved_controller)
 
419
    {
 
420
        m_controller       = m_saved_controller;
 
421
        m_saved_controller = NULL;
 
422
    }
 
423
    m_kart_model->setAnimation(KartModel::AF_DEFAULT);
320
424
    m_view_blocked_by_plunger = 0.0;
321
 
    m_attachment.clear();
 
425
    m_attachment->clear();
 
426
    m_nitro->setCreationRate(0.0f);
322
427
    m_powerup.reset();
323
428
 
324
 
    m_race_position        = 9;
 
429
    m_race_position        = m_initial_position;
325
430
    m_finished_race        = false;
326
 
    m_eliminated           = false;
327
 
    m_rescue               = false;
328
431
    m_finish_time          = 0.0f;
329
 
    m_zipper_time_left     = 0.0f;
330
432
    m_collected_energy     = 0;
 
433
    m_has_started          = false;
331
434
    m_wheel_rotation       = 0;
332
435
    m_bounce_back_time     = 0.0f;
333
436
    m_skidding             = 1.0f;
334
437
    m_time_last_crash      = 0.0f;
335
 
    m_max_speed_reduction  = 0.0f;
336
 
    m_power_reduction      = 50.0f;
 
438
    m_view_blocked_by_plunger = 0.0f;
 
439
    
 
440
    if(m_terrain_sound)
 
441
    {
 
442
        sfx_manager->deleteSFX(m_terrain_sound);
 
443
    }
 
444
    if(m_previous_terrain_sound)
 
445
    {
 
446
        sfx_manager->deleteSFX(m_previous_terrain_sound);
 
447
    }
 
448
    
 
449
    m_terrain_sound = NULL;
 
450
    m_previous_terrain_sound = NULL;
 
451
    
 
452
    if(m_engine_sound)
 
453
        m_engine_sound->stop();
337
454
 
338
455
    m_controls.m_steer     = 0.0f;
339
456
    m_controls.m_accel     = 0.0f;
341
458
    m_controls.m_nitro     = false;
342
459
    m_controls.m_drift     = false;
343
460
    m_controls.m_fire      = false;
 
461
    m_controls.m_look_back = false;
 
462
    m_slipstream->reset();
 
463
    m_vehicle->deactivateZipper();
344
464
 
345
465
    // Set the brakes so that karts don't slide downhill
346
466
    for(int i=0; i<4; i++) m_vehicle->setBrake(5.0f, i);
347
467
 
348
468
    setTrans(m_reset_transform);
349
469
 
350
 
    m_vehicle->applyEngineForce (0.0f, 2);
351
 
    m_vehicle->applyEngineForce (0.0f, 3);
 
470
    applyEngineForce (0.0f);
352
471
 
353
472
    Moveable::reset();
354
473
    if(m_skidmarks) m_skidmarks->reset();
358
477
    }
359
478
 
360
479
    TerrainInfo::update(getXYZ());
 
480
 
 
481
    // Reset is also called when the kart is created, at which time
 
482
    // m_controller is not yet defined, so this has to be tested here.
 
483
    if(m_controller)
 
484
        m_controller->reset();
 
485
 
361
486
}   // reset
362
487
 
363
488
//-----------------------------------------------------------------------------
364
 
void Kart::raceFinished(float time)
 
489
/** Sets that this kart has finished the race and finishing time. It also
 
490
 *  notifies the race_manager about the race completion for this kart.
 
491
 *  \param time The finishing time for this kart. It can either be the
 
492
 *         actual time when the kart finished (in which case time() = 
 
493
 *         world->getTime()), or the estimated time in case that all
 
494
 *         player kart have finished the race and all AI karts get
 
495
 *         an estimated finish time set.
 
496
 */
 
497
void Kart::finishedRace(float time)
365
498
{
 
499
    // m_finished_race can be true if e.g. an AI kart was set to finish
 
500
    // because the race was over (i.e. estimating the finish time). If
 
501
    // this kart then crosses the finish line (with the end controller)
 
502
    // it would trigger a race end again.
 
503
    if(m_finished_race) return;
366
504
    m_finished_race = true;
367
505
    m_finish_time   = time;
368
 
    race_manager->RaceFinished(this, time);
369
 
}   // raceFinished
 
506
    m_controller->finishedRace(time);
 
507
    race_manager->kartFinishedRace(this, time);
 
508
    
 
509
    if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
 
510
        race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL)
 
511
    {
 
512
        // in modes that support it, start end animation
 
513
        setController(new EndController(this, m_controller->getPlayer()));
 
514
        if(m_race_position<=0.5f*race_manager->getNumberOfKarts() ||
 
515
            m_race_position==1)
 
516
            m_kart_model->setAnimation(KartModel::AF_WIN_START);
 
517
        else 
 
518
            m_kart_model->setAnimation(KartModel::AF_LOSE_START);
 
519
        
 
520
        // Not all karts have a camera
 
521
        if (m_camera) m_camera->setMode(Camera::CM_FINAL);
 
522
        
 
523
        RaceGUIBase* m = World::getWorld()->getRaceGUI();
 
524
        if(m)
 
525
        {
 
526
            m->addMessage((getPosition() == 1 ? _("You won the race!") : _("You finished the race!")) ,
 
527
                          this, 2.0f, 60);
 
528
        }
 
529
    }
 
530
    else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
 
531
    {        
 
532
        // start end animation
 
533
        setController(new EndController(this, m_controller->getPlayer()));
 
534
        if(m_race_position<=2)
 
535
            m_kart_model->setAnimation(KartModel::AF_WIN_START);
 
536
        else if(m_race_position>=0.7f*race_manager->getNumberOfKarts())
 
537
            m_kart_model->setAnimation(KartModel::AF_LOSE_START);
 
538
            
 
539
        // Not all karts have a camera
 
540
        if (m_camera) m_camera->setMode(Camera::CM_REVERSE);
 
541
        
 
542
        RaceGUIBase* m = World::getWorld()->getRaceGUI();
 
543
        if(m)
 
544
        {
 
545
            m->addMessage((getPosition() == 2 ? _("You won the race!") : _("You finished the race!")) ,
 
546
                          this, 2.0f, 60);
 
547
        }
 
548
    }
 
549
    else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES)
 
550
    {
 
551
        setController(new EndController(this, m_controller->getPlayer()));
 
552
    }             
 
553
        
 
554
}   // finishedRace
370
555
 
371
556
//-----------------------------------------------------------------------------
372
 
void Kart::collectedItem(const Item &item, int add_info)
 
557
/** Called when an item is collected. It will either adjust the collected
 
558
 *  energy, or update the attachment or powerup for this kart.
 
559
 *  \param item The item that was hit.
 
560
 *  \param add_info Additional info, used in networking games to force
 
561
 *         a specific item to be used (instead of a random item) to keep
 
562
 *         all karts in synch.
 
563
 */
 
564
void Kart::collectedItem(Item *item, int add_info)
373
565
{
374
 
    const ItemType type = item.getType();
 
566
    float old_energy          = m_collected_energy;
 
567
    const Item::ItemType type = item->getType();
375
568
 
376
569
    switch (type)
377
570
    {
378
 
    case ITEM_BANANA      : m_attachment.hitBanana(item, add_info); break;
379
 
    case ITEM_SILVER_COIN : m_collected_energy++ ;                  break;
380
 
    case ITEM_GOLD_COIN   : m_collected_energy += 3 ;               break;
381
 
    case ITEM_BONUS_BOX   : 
382
 
        { 
383
 
            // In wheelie style, karts get more items depending on energy,
384
 
            // in nitro mode it's only one item.
385
 
            int n = 1;
386
 
            m_powerup.hitBonusBox(n, item,add_info);   
 
571
    case Item::ITEM_BANANA: 
 
572
        m_attachment->hitBanana(item, add_info); 
 
573
        break;
 
574
    case Item::ITEM_NITRO_SMALL: 
 
575
        m_collected_energy += m_kart_properties->getNitroSmallContainer();
 
576
        break;
 
577
    case Item::ITEM_NITRO_BIG:   
 
578
        m_collected_energy += m_kart_properties->getNitroBigContainer();
 
579
        break;
 
580
    case Item::ITEM_BONUS_BOX  :
 
581
        {
 
582
            m_powerup.hitBonusBox(*item, add_info);
387
583
            break;
388
584
        }
389
 
    case ITEM_BUBBLEGUM:
 
585
    case Item::ITEM_BUBBLEGUM:
390
586
        // slow down
391
587
        m_body->setLinearVelocity(m_body->getLinearVelocity()*0.3f);
392
588
        m_goo_sound->position(getXYZ());
393
589
        m_goo_sound->play();
 
590
        // Play appropriate custom character sound
 
591
        playCustomSFX(SFXManager::CUSTOM_GOO);
394
592
        break;
395
593
    default        : break;
396
594
    }   // switch TYPE
399
597
    // functions (hit{Red,Green}Item), so only coins need to be
400
598
    // stored here.
401
599
    if(network_manager->getMode()==NetworkManager::NW_SERVER &&
402
 
        (type==ITEM_SILVER_COIN || type==ITEM_GOLD_COIN)                       )
 
600
        (type==Item::ITEM_NITRO_BIG || type==Item::ITEM_NITRO_SMALL) )
403
601
    {
404
 
        race_state->itemCollected(getWorldKartId(), item.getItemId());
 
602
        race_state->itemCollected(getWorldKartId(), item->getItemId());
405
603
    }
406
604
 
407
605
    if ( m_collected_energy > MAX_ITEMS_COLLECTED )
408
606
        m_collected_energy = MAX_ITEMS_COLLECTED;
 
607
    m_controller->collectedItem(*item, add_info, old_energy);
409
608
 
410
609
}   // collectedItem
411
610
 
412
611
//-----------------------------------------------------------------------------
413
 
// Simulates gears
 
612
/** Simulates gears by adjusting the force of the engine. It also takes the
 
613
 *  effect of the zipper into account.
 
614
 */
414
615
float Kart::getActualWheelForce()
415
616
{
416
 
    float zipperF=(m_zipper_time_left>0.0f) ? stk_config->m_zipper_force : 0.0f;
 
617
    float time_left = MaxSpeed::getSpeedIncreaseTimeLeft(MS_INCREASE_ZIPPER);
 
618
    float zipper_force = time_left>0.0f ? m_kart_properties->getZipperForce(): 0.0f;
417
619
    const std::vector<float>& gear_ratio=m_kart_properties->getGearSwitchRatio();
418
620
    for(unsigned int i=0; i<gear_ratio.size(); i++)
419
621
    {
420
 
        if(m_speed <= getMaxSpeed()*gear_ratio[i])
 
622
        if(m_speed <= m_kart_properties->getMaxSpeed()*gear_ratio[i])
421
623
        {
422
 
            m_current_gear_ratio = gear_ratio[i];
423
 
            return getMaxPower()*m_kart_properties->getGearPowerIncrease()[i]+zipperF;
 
624
            return getMaxPower()*m_kart_properties->getGearPowerIncrease()[i]
 
625
                  +zipper_force;
424
626
        }
425
627
    }
426
 
    return getMaxPower()+zipperF;
 
628
    return getMaxPower()+zipper_force;
427
629
 
428
630
}   // getActualWheelForce
429
631
 
430
632
//-----------------------------------------------------------------------------
431
 
/** The kart is on ground if all 4 wheels touch the ground
432
 
*/
 
633
/** The kart is on ground if all 4 wheels touch the ground, and if no special
 
634
 *  animation (rescue, explosion etc.) is happening).
 
635
 */
433
636
bool Kart::isOnGround() const
434
637
{
435
 
    return m_vehicle->getWheelInfo(0).m_raycastInfo.m_isInContact &&
436
 
           m_vehicle->getWheelInfo(1).m_raycastInfo.m_isInContact &&
437
 
           m_vehicle->getWheelInfo(2).m_raycastInfo.m_isInContact &&
438
 
           m_vehicle->getWheelInfo(3).m_raycastInfo.m_isInContact;
 
638
    return (m_vehicle->getNumWheelsOnGround() == m_vehicle->getNumWheels()
 
639
          && !playingEmergencyAnimation());
439
640
}   // isOnGround
 
641
 
440
642
//-----------------------------------------------------------------------------
441
643
/** The kart is near the ground, but not necesarily on it (small jumps). This
442
644
 *  is used to determine when to switch off the upright constraint, so that
443
 
 *  explosions can be more violent, while still 
 
645
 *  explosions can be more violent, while still
444
646
*/
445
 
 
446
647
bool Kart::isNearGround() const
447
648
{
448
649
    if(getHoT()==Track::NOHIT)
449
650
        return false;
450
651
    else
451
 
        return ((getXYZ().getZ() - getHoT()) < stk_config->m_near_ground);
 
652
        return ((getXYZ().getY() - getHoT()) < stk_config->m_near_ground);
452
653
}   // isNearGround
453
 
//-----------------------------------------------------------------------------
454
 
void Kart::handleExplosion(const Vec3& pos, bool direct_hit)
455
 
{
456
 
    if(direct_hit) 
457
 
    {
458
 
        btVector3 diff((float)(rand()%16/16), (float)(rand()%16/16), 2.0f);
459
 
        diff.normalize();
460
 
        diff*=stk_config->m_explosion_impulse/5.0f;
461
 
        m_uprightConstraint->setDisableTime(10.0f);
462
 
        getVehicle()->getRigidBody()->applyCentralImpulse(diff);
463
 
        getVehicle()->getRigidBody()->applyTorqueImpulse(btVector3(float(rand()%32*5),
464
 
                                                                   float(rand()%32*5),
465
 
                                                                   float(rand()%32*5)));
466
 
    }
467
 
    else  // only affected by a distant explosion
468
 
    {
469
 
        btVector3 diff=getXYZ()-pos;
470
 
        //if the z component is negative, the resulting impulse could push the 
471
 
        // kart through the floor. So in this case ignore z.
472
 
        if(diff.getZ()<0) diff.setZ(0.0f);
473
 
        float len2=diff.length2();
474
 
 
475
 
        // The correct formhale would be to first normalise diff,
476
 
        // then apply the impulse (which decreases 1/r^2 depending
477
 
        // on the distance r), so:
478
 
        // diff/len(diff) * impulseSize/len(diff)^2
479
 
        // = diff*impulseSize/len(diff)^3
480
 
        // We use diff*impulseSize/len(diff)^2 here, this makes the impulse
481
 
        // somewhat larger, which is actually more fun :)
482
 
        diff *= stk_config->m_explosion_impulse/len2;
483
 
        getVehicle()->getRigidBody()->applyCentralImpulse(diff);
484
 
    }
485
 
}   // handleExplosion
486
 
 
487
 
//-----------------------------------------------------------------------------
 
654
 
 
655
//-----------------------------------------------------------------------------
 
656
/** Updates the kart in each time step. It updates the physics setting,
 
657
 *  particle effects, camera position, etc.
 
658
 *  \param dt Time step size.
 
659
 */
488
660
void Kart::update(float dt)
489
661
{
490
 
    if(m_body->getAngularVelocity().getZ()>1.9f)
491
 
        dt=1.0f*dt;
 
662
    // Update the position and other data taken from the physics    
 
663
    Moveable::update(dt);
 
664
 
 
665
    if(!history->replayHistory())
 
666
        m_controller->update(dt);
 
667
    if(m_camera)
 
668
        m_camera->update(dt);
492
669
    // if its view is blocked by plunger, decrease remaining time
493
670
    if(m_view_blocked_by_plunger > 0) m_view_blocked_by_plunger -= dt;
494
 
    
 
671
 
 
672
    m_slipstream->update(dt);
 
673
 
495
674
    // Store the actual kart controls at the start of update in the server
496
 
    // state. This makes it easier to reset some fields when they are not used 
 
675
    // state. This makes it easier to reset some fields when they are not used
497
676
    // anymore (e.g. controls.fire).
498
677
    if(network_manager->getMode()==NetworkManager::NW_SERVER)
499
678
    {
501
680
    }
502
681
 
503
682
    // On a client fiering is done upon receiving the command from the server.
504
 
    if ( m_controls.m_fire && network_manager->getMode()!=NetworkManager::NW_CLIENT 
505
 
         && !isRescue())
 
683
    if ( m_controls.m_fire && network_manager->getMode()!=NetworkManager::NW_CLIENT
 
684
        && !playingEmergencyAnimation())
506
685
    {
507
686
        // use() needs to be called even if there currently is no collecteable
508
687
        // since use() can test if something needs to be switched on/off.
510
689
        m_controls.m_fire = false;
511
690
    }
512
691
 
513
 
    // When really on air, free fly, when near ground, try to glide / adjust for landing
514
 
    if(!isNearGround())
515
 
        m_uprightConstraint->setLimit(M_PI);
516
 
    else
517
 
        m_uprightConstraint->setLimit(m_kart_properties->getUprightTolerance());
518
 
 
519
 
 
520
 
    m_zipper_time_left = m_zipper_time_left>0.0f ? m_zipper_time_left-dt : 0.0f;
 
692
    if (!m_flying)
 
693
    {
 
694
        // When really on air, free fly, when near ground, try to glide / adjust for landing
 
695
        // If zipped, be stable, so ramp+zipper can allow nice jumps without scripting the fly
 
696
        if(!isNearGround() && 
 
697
            MaxSpeed::getSpeedIncreaseTimeLeft(MS_INCREASE_ZIPPER)<=0.0f )
 
698
            m_uprightConstraint->setLimit(M_PI);
 
699
        else
 
700
            m_uprightConstraint->setLimit(m_kart_properties->getUprightTolerance());
 
701
    }
 
702
 
 
703
    
 
704
    // TODO: hiker said this probably will be moved to btKart or so when updating bullet engine.
 
705
    // Neutralize any yaw change if the kart leaves the ground, so the kart falls more or less
 
706
    // straight after jumping, but still allowing some "boat shake" (roll and pitch).
 
707
    // Otherwise many non perfect jumps end in a total roll over or a serious change of
 
708
    // direction, sometimes 90 or even full U turn (real but less fun for a karting game).
 
709
    // As side effect steering becames a bit less responsive (any wheel on air), but not too bad.
 
710
    if(!isOnGround()) {
 
711
        btVector3 speed = m_body->getAngularVelocity();
 
712
        speed.setX(speed.getX() * 0.95f);
 
713
        speed.setY(speed.getY() * 0.25f); // or 0.0f for sharp neutralization of yaw
 
714
        speed.setZ(speed.getZ() * 0.95f);
 
715
        m_body->setAngularVelocity(speed);
 
716
        // This one keeps the kart pointing "100% as launched" instead,
 
717
        // like in ski jump sports, too boring but also works.
 
718
        //m_body->setAngularVelocity(btVector3(0,0,0));
 
719
    }
521
720
 
522
721
    //m_wheel_rotation gives the rotation around the X-axis, and since velocity's
523
722
    //timeframe is the delta time, we don't have to multiply it with dt.
524
723
    m_wheel_rotation += m_speed*dt / m_kart_properties->getWheelRadius();
525
724
    m_wheel_rotation=fmodf(m_wheel_rotation, 2*M_PI);
526
725
 
527
 
    if ( m_rescue )
528
 
    {
529
 
        // Let the kart raise 2m in the 2 seconds of the rescue
530
 
        const float rescue_time   = 2.0f;
531
 
        const float rescue_height = 2.0f;
532
 
        if(m_attachment.getType() != ATTACH_TINYTUX)
533
 
        {
534
 
            m_attachment.set( ATTACH_TINYTUX, rescue_time ) ;
535
 
            m_rescue_pitch = getHPR().getPitch();
536
 
            m_rescue_roll  = getHPR().getRoll();
537
 
            RaceManager::getWorld()->getPhysics()->removeKart(this);
538
 
            race_state->itemCollected(getWorldKartId(), -1, -1);
539
 
        }
540
 
        btQuaternion q_roll (btVector3(0.f, 1.f, 0.f),
541
 
                             -m_rescue_roll*dt/rescue_time*M_PI/180.0f);
542
 
        btQuaternion q_pitch(btVector3(1.f, 0.f, 0.f),
543
 
                             -m_rescue_pitch*dt/rescue_time*M_PI/180.0f);
544
 
        setXYZRotation(getXYZ()+Vec3(0, 0, rescue_height*dt/rescue_time),
545
 
                       getRotation()*q_roll*q_pitch);
546
 
    }   // if m_rescue
547
 
    m_attachment.update(dt);
 
726
    EmergencyAnimation::update(dt);
 
727
 
 
728
    m_attachment->update(dt);
548
729
 
549
730
    //smoke drawing control point
550
 
    if ( user_config->m_graphical_effects )
 
731
    if ( UserConfigParams::m_graphical_effects )
551
732
    {
552
733
        m_smoke_system->update(dt);
553
 
        m_nitro->update(dt);
554
 
    }  // user_config->m_graphical_effects
 
734
        m_water_splash_system->update(dt);
 
735
    }  // UserConfigParams::m_graphical_effects
 
736
 
 
737
    m_nitro->update(dt);
 
738
    
555
739
    updatePhysics(dt);
556
740
 
557
 
    //kart_info.m_last_track_coords = kart_info.m_curr_track_coords;
558
 
 
559
 
    Moveable::update(dt);
560
 
 
 
741
    /* (TODO: add back when properly done)
 
742
    for (int n = 0; n < SFXManager::NUM_CUSTOMS; n++)
 
743
    {
 
744
        if (m_custom_sounds[n] != NULL) m_custom_sounds[n]->position   ( getXYZ() );
 
745
    }
 
746
     */
 
747
    
 
748
    m_beep_sound->position   ( getXYZ() );
561
749
    m_engine_sound->position ( getXYZ() );
562
 
    m_beep_sound->position   ( getXYZ() );
563
750
    m_crash_sound->position  ( getXYZ() );
564
751
    m_skid_sound->position   ( getXYZ() );
565
752
 
566
753
    // Check if a kart is (nearly) upside down and not moving much --> automatic rescue
567
 
    if((fabs(getHPR().getRoll())>60 && fabs(getSpeed())<3.0f) )
 
754
    if((fabs(getRoll())>60*DEGREE_TO_RAD && fabs(getSpeed())<3.0f) )
568
755
    {
569
 
        forceRescue();
 
756
        forceRescue(/*is_auto_rescue*/true);
570
757
    }
571
758
 
572
759
    btTransform trans=getTrans();
573
760
    // Add a certain epsilon (0.3) to the height of the kart. This avoids
574
761
    // problems of the ray being cast from under the track (which happened
575
762
    // e.g. on tux tollway when jumping down from the ramp, when the chassis
576
 
    // partly tunnels through the track). While tunneling should not be 
 
763
    // partly tunnels through the track). While tunneling should not be
577
764
    // happening (since Z velocity is clamped), the epsilon is left in place
578
765
    // just to be on the safe side (it will not hit the chassis itself).
579
 
    Vec3 pos_plus_epsilon = trans.getOrigin()+btVector3(0,0,0.3f);
580
 
    // These values cause the track not to be hit in tuxtrack. I leave
581
 
    // them in as a test case if additional debugging should be needed.
582
 
    // Note: it might be that the kart chassis is actually 'in' the track,
583
 
    // i.e. it's a tunneling problem!
584
 
    //btVector3 pos_plus_epsilon (-54.449902, -139.99402, -3.4524240);
585
 
    // motionstate:               -52.449902, -139.99402, -3.6524241
586
 
    // collision object           -52.221024, -139.99614, -3.5276926
 
766
    Vec3 pos_plus_epsilon = trans.getOrigin()+btVector3(0,0.3f,0);
587
767
 
588
768
    // Make sure that the ray doesn't hit the kart. This is done by
589
769
    // resetting the collision filter group, so that this collision
599
779
    {
600
780
        m_body->getBroadphaseHandle()->m_collisionFilterGroup = old_group;
601
781
    }
602
 
    const Material* material=getMaterial();
603
 
    m_power_reduction = 50.0f;
 
782
    const Material* material=TerrainInfo::getMaterial();
604
783
    if (getHoT()==Track::NOHIT)   // kart falling off the track
605
784
    {
606
785
        // let kart fall a bit before rescuing
607
 
        if( RaceManager::getTrack()->m_left_driveline.size() > 0 &&
608
 
            fabs( getXYZ().getZ() - RaceManager::getTrack()->m_left_driveline[0].getZ() ) > 17)
609
 
            forceRescue();    
610
 
    } 
 
786
        const Vec3 *min, *max;
 
787
        World::getWorld()->getTrack()->getAABB(&min, &max);
 
788
        if(min->getY() - getXYZ().getY() > 17)
 
789
            forceRescue();
 
790
    }
 
791
 
 
792
    // Sometimes the material can be 0. This can happen if a kart is above
 
793
    // another kart (e.g. mass collision, or one kart falling on another
 
794
    // kart). Bullet does not have any triangle information in this case,
 
795
    // and so material can not be set. In this case it is simply ignored
 
796
    // since it can't hurt (material is only used for friction, zipper and
 
797
    // rescue, so those things are not triggered till the kart is on the
 
798
    // track again)
611
799
    else if(material)
612
800
    {
613
 
        // Sometimes the material can be 0. This can happen if a kart is above
614
 
        // another kart (e.g. mass collision, or one kart falling on another 
615
 
        // kart). Bullet does not have any triangle information in this case,
616
 
        // and so material can not be set. In this case it is simply ignored 
617
 
        // since it can't hurt (material is only used for friction, zipper and
618
 
        // rescue, so those things are not triggered till the kart is on the 
619
 
        // track again)
 
801
        // If a terrain specific sfx is already being played, when a new
 
802
        // terrain is entered, an old sfx should be finished (once, not
 
803
        // looped anymore of course). The m_terrain_sound is then copied
 
804
        // to a m_previous_terrain_sound, for which looping is disabled.
 
805
        // In case that three sfx needed to be played (i.e. a previous is
 
806
        // playing, a current is playing, and a new terrain with sfx is
 
807
        // entered), the oldest (previous) sfx is stopped and deleted.
 
808
        if(getLastMaterial()!=material)
 
809
        {
 
810
            // First stop any previously playing terrain sound
 
811
            // and remove it, sp that m_previous_terrain_sound
 
812
            // can be used again.
 
813
            if(m_previous_terrain_sound)
 
814
            {
 
815
                sfx_manager->deleteSFX(m_previous_terrain_sound);
 
816
            }
 
817
            m_previous_terrain_sound = m_terrain_sound;
 
818
            if(m_previous_terrain_sound)
 
819
                m_previous_terrain_sound->setLoop(false);
 
820
 
 
821
            const std::string s = material->getSFXName();
 
822
            if(s!="")
 
823
            {
 
824
                m_terrain_sound = sfx_manager->createSoundSource(s);
 
825
                m_terrain_sound->play();
 
826
                m_terrain_sound->setLoop(true);
 
827
            }
 
828
            else
 
829
                m_terrain_sound = NULL;
 
830
        }
 
831
        if(m_previous_terrain_sound && 
 
832
            m_previous_terrain_sound->getStatus()==SFXManager::SFX_STOPPED)
 
833
        {
 
834
            // We don't modify the position of m_previous_terrain_sound 
 
835
            // anymore, so that it keeps on playing at the place where the 
 
836
            // kart left the material.
 
837
            sfx_manager->deleteSFX(m_previous_terrain_sound);
 
838
            m_previous_terrain_sound = NULL;
 
839
        }
 
840
        if(m_terrain_sound) 
 
841
        {
 
842
            m_terrain_sound->position(getXYZ());
 
843
            material->setSFXSpeed(m_terrain_sound, m_speed);
 
844
        }
 
845
 
620
846
        if     (material->isReset()  && isOnGround()) forceRescue();
621
 
        else if(material->isZipper() && isOnGround()) handleZipper();
 
847
        else if(material->isZipper() && isOnGround()) handleZipper(material);
622
848
        else
623
849
        {
624
 
            m_power_reduction = material->getSlowDown();
625
 
            // Normal driving on terrain. Adjust for maximum terrain speed
626
 
            float max_speed_here = material->getMaxSpeedFraction()*getMaxSpeed();
627
 
            // If the speed is too fast, reduce the maximum speed gradually.
628
 
            // The actual capping happens in updatePhysics
629
 
            if(max_speed_here<m_speed)
630
 
                m_max_speed_reduction += dt*material->getSlowDown();
631
 
            else
632
 
                m_max_speed_reduction = 0.0f;
 
850
            MaxSpeed::setSlowdown(MaxSpeed::MS_DECREASE_TERRAIN,
 
851
                                  material->getMaxSpeedFraction(), 
 
852
                                  material->getSlowDownTime()     );
 
853
#ifdef DEBUG
 
854
            if(UserConfigParams::m_material_debug)
 
855
            {
 
856
                printf("%s\tfraction %f\ttime %f.\n",
 
857
                       material->getTexFname().c_str(),
 
858
                       material->getMaxSpeedFraction(),
 
859
                       material->getSlowDownTime()       );
 
860
            }
 
861
#endif
633
862
        }
634
863
    }   // if there is material
635
864
 
636
865
    // Check if any item was hit.
637
 
    item_manager->hitItem(this);
 
866
    item_manager->checkItemHit(this);
638
867
    if(m_kart_properties->hasSkidmarks())
639
868
        m_skidmarks->update(dt);
640
869
 
 
870
    const bool emergency = playingEmergencyAnimation();
 
871
    
 
872
    if (emergency)
 
873
    {
 
874
        m_view_blocked_by_plunger = 0.0f;
 
875
    }
 
876
    
641
877
    // Remove the shadow if the kart is not on the ground (if a kart
642
878
    // is rescued isOnGround might still be true, since the kart rigid
643
879
    // body was removed from the physics, but still retain the old
644
880
    // values for the raycasts).
645
 
    if( (!isOnGround() || m_rescue) && m_shadow_enabled)
 
881
    if( (!isOnGround() || emergency) && m_shadow_enabled)
646
882
    {
647
883
        m_shadow_enabled = false;
648
 
        m_model_transform->removeKid(m_shadow);
 
884
        m_shadow->disableShadow();
649
885
    }
650
 
    if(!m_shadow_enabled && isOnGround() && !m_rescue)
 
886
    if(!m_shadow_enabled && isOnGround() && !emergency)
651
887
    {
 
888
        m_shadow->enableShadow();
652
889
        m_shadow_enabled = true;
653
 
        m_model_transform->addKid(m_shadow);
654
890
    }
655
891
}   // update
656
892
 
657
893
//-----------------------------------------------------------------------------
658
 
/** Sets zipper time, and apply one time additional speed boost.
 
894
/** Sets zipper time, and apply one time additional speed boost. It can be 
 
895
 *  used with a specific material, in which case the zipper parmaters are
 
896
 *  taken from this material (parameters that are <0 will be using the
 
897
 *  kart-specific values from kart-properties.
 
898
 *  \param material If not NULL, will be used to determine the zipper
 
899
 *                  parameters, otherwise the defaults from kart properties
 
900
 *                  will be used.
 
901
 * \param play_sound If true this will cause a sfx to be played even if the
 
902
 *                  terrain hasn't changed. It is used by the zipper powerup.
659
903
 */
660
 
void Kart::handleZipper()
 
904
void Kart::handleZipper(const Material *material, bool play_sound)
661
905
{
 
906
    /** The additional speed allowed on top of the kart-specific maximum kart 
 
907
     *  speed. */
 
908
    float max_speed_increase;
 
909
 
 
910
    /**Time the zipper stays activated. */
 
911
    float duration;
 
912
    /** A one time additional speed gain - the kart will instantly add this 
 
913
     *  amount of speed to its current speed. */
 
914
    float speed_gain;
 
915
    /** Time it takes for the zipper advantage to fade out. */
 
916
    float fade_out_time;
 
917
 
 
918
    if(material)
 
919
    {
 
920
        material->getZipperParameter(&max_speed_increase, &duration, 
 
921
                                     &speed_gain, &fade_out_time);
 
922
        if(max_speed_increase<0) 
 
923
            max_speed_increase = m_kart_properties->getZipperMaxSpeedIncrease();
 
924
        if(duration<0)
 
925
            duration           = m_kart_properties->getZipperTime();
 
926
        if(speed_gain<0)
 
927
            speed_gain         = m_kart_properties->getZipperSpeedGain();
 
928
        if(fade_out_time<0)
 
929
            fade_out_time      = m_kart_properties->getZipperFadeOutTime();
 
930
    }
 
931
    else
 
932
    {
 
933
        max_speed_increase = m_kart_properties->getZipperMaxSpeedIncrease();
 
934
        duration           = m_kart_properties->getZipperTime();
 
935
        speed_gain         = m_kart_properties->getZipperSpeedGain();
 
936
        fade_out_time      = m_kart_properties->getZipperFadeOutTime();
 
937
    }
662
938
    // Ignore a zipper that's activated while braking
663
 
    if(m_controls.m_brake) return;
664
 
    m_zipper_time_left  = stk_config->m_zipper_time;
665
 
    btVector3 v         = m_body->getLinearVelocity();
666
 
    float current_speed = v.length();
667
 
    float speed         = std::min(current_speed+stk_config->m_zipper_speed_gain, 
668
 
                                   getMaxSpeedOnTerrain());
669
 
    // If the speed is too low, very minor components of the velocity vector
670
 
    // can become too big. E.g. each kart has a z component (to offset gravity
671
 
    // I assume, around 0.16) --> if the karts are (nearly) at standstill,
672
 
    // the z component is exaggerated, resulting in a jump. Even if Z
673
 
    // is set to 0, minor left/right movements are then too strong.
674
 
    // Therefore a zipper only adds the speed if the speed is at least 1
675
 
    // (experimentally found valud).  It also avoids NAN problems (if v=0).
676
 
    if(current_speed>1.0f) m_body->setLinearVelocity(v*(speed/current_speed));
 
939
    if(m_controls.m_brake || m_speed<0) return;
 
940
 
 
941
    MaxSpeed::increaseMaxSpeed(MaxSpeed::MS_INCREASE_ZIPPER, 
 
942
                               max_speed_increase, duration, fade_out_time);
 
943
    // This will result in all max speed settings updated, but no 
 
944
    // changes to any slow downs since dt=0
 
945
    MaxSpeed::update(0);
 
946
    float speed = std::min(m_speed + speed_gain, 
 
947
                           MaxSpeed::getCurrentMaxSpeed() );
 
948
 
 
949
    m_vehicle->activateZipper(speed);
 
950
    // Play custom character sound (weee!)
 
951
    playCustomSFX(SFXManager::CUSTOM_ZIPPER);
 
952
    m_controller->handleZipper(play_sound);
677
953
}   // handleZipper
678
 
//-----------------------------------------------------------------------------
679
 
#define sgn(x) ((x<0)?-1.0f:((x>0)?1.0f:0.0f))
680
 
 
681
 
// -----------------------------------------------------------------------------
682
 
void Kart::draw()
683
 
{
684
 
    float m[16];
685
 
    btTransform t=getTrans();
686
 
    t.getOpenGLMatrix(m);
687
 
 
688
 
    btVector3 wire_color(0.5f, 0.5f, 0.5f);
689
 
    //RaceManager::getWorld()->getPhysics()->debugDraw(m, m_body->getCollisionShape(), 
690
 
    //                               wire_color);
691
 
    btCylinderShapeX wheelShape( btVector3(0.1f,
692
 
                                        m_kart_properties->getWheelRadius(),
693
 
                                        m_kart_properties->getWheelRadius()));
694
 
    btVector3 wheelColor(1,0,0);
695
 
    for(int i=0; i<m_vehicle->getNumWheels(); i++)
696
 
    {
697
 
        m_vehicle->updateWheelTransform(i, true);
698
 
        float m[16];
699
 
        m_vehicle->getWheelInfo(i).m_worldTransform.getOpenGLMatrix(m);
700
 
        RaceManager::getWorld()->getPhysics()->debugDraw(m, &wheelShape, wheelColor);
701
 
    }
702
 
}   // draw
703
954
 
704
955
// -----------------------------------------------------------------------------
705
956
/** Returned an additional engine power boost when using nitro.
707
958
 */
708
959
float Kart::handleNitro(float dt)
709
960
{
710
 
    if(!m_controls.m_nitro) return 0.0;
711
 
    m_collected_energy -= dt;
 
961
    if(!m_controls.m_nitro || !isOnGround()) return 0.0;
 
962
    m_collected_energy -= dt * m_kart_properties->getNitroConsumption();
712
963
    if(m_collected_energy<0)
713
964
    {
714
965
        m_collected_energy = 0;
715
966
        return 0.0;
716
967
    }
 
968
    MaxSpeed::increaseMaxSpeed(MaxSpeed::MS_INCREASE_NITRO,
 
969
                               m_kart_properties->getNitroMaxSpeedIncrease(),
 
970
                               m_kart_properties->getNitroDuration(), 
 
971
                               m_kart_properties->getNitroFadeOutTime()      );
717
972
    return m_kart_properties->getNitroPowerBoost() * getMaxPower();
718
973
 
719
974
}   // handleNitro
720
975
 
721
976
// -----------------------------------------------------------------------------
 
977
/** Activates a slipstream effect, atm that is display some nitro. */
 
978
void Kart::setSlipstreamEffect(float f)
 
979
{
 
980
    m_nitro->setCreationRate(f);
 
981
}   // setSlipstreamEffect
 
982
 
 
983
// -----------------------------------------------------------------------------
722
984
/** This function is called when the race starts. Up to then all brakes are
723
985
    braking (to avoid the kart from rolling downhill), but they need to be set
724
986
    to zero (otherwise the brakes will be braking whenever no engine force
728
990
{
729
991
    for(int i=0; i<4; i++) m_vehicle->setBrake(0.0f, i);
730
992
}   // resetBrakes
 
993
 
731
994
// -----------------------------------------------------------------------------
 
995
/** Called when the kart crashes against the track (k=NULL) or another kart.
 
996
 *  \params k Either a kart if a kart was hit, or NULL if the track was hit.
 
997
 */
732
998
void Kart::crashed(Kart *k)
733
999
{
734
 
    /** If a kart is crashing against the track, the collision is often 
 
1000
    m_controller->crashed();
 
1001
    /** If a kart is crashing against the track, the collision is often
735
1002
     *  reported more than once, resulting in a machine gun effect, and too
736
 
     *  long disabling of the engine. Therefore, this reaction is disabled 
 
1003
     *  long disabling of the engine. Therefore, this reaction is disabled
737
1004
     *  for 0.5 seconds after a crash.
738
1005
     */
739
 
    if(RaceManager::getWorld()->getTime()-m_time_last_crash < 0.5f) return;
 
1006
    if(World::getWorld()->getTime()-m_time_last_crash < 0.5f) return;
740
1007
 
741
 
    m_time_last_crash = RaceManager::getWorld()->getTime();
742
 
    // After a collision disable the engine for a short time so that karts 
 
1008
    m_time_last_crash = World::getWorld()->getTime();
 
1009
    // After a collision disable the engine for a short time so that karts
743
1010
    // can 'bounce back' a bit (without this the engine force will prevent
744
1011
    // karts from bouncing back, they will instead stuck towards the obstable).
745
1012
    if(m_bounce_back_time<=0.0f)
748
1015
        // it's not already playing.
749
1016
        if(m_crash_sound->getStatus() != SFXManager::SFX_PLAYING)
750
1017
            m_crash_sound->play();
 
1018
 
751
1019
        m_bounce_back_time = 0.1f;
752
1020
    }
753
1021
}   // crashed
755
1023
// -----------------------------------------------------------------------------
756
1024
void Kart::beep()
757
1025
{
758
 
    m_beep_sound->play();
 
1026
    // If the custom horn can't play (isn't defined) then play the default one
 
1027
    if (!playCustomSFX(SFXManager::CUSTOM_HORN))
 
1028
        m_beep_sound->play();
 
1029
 
759
1030
} // beep
760
1031
 
761
1032
// -----------------------------------------------------------------------------
762
 
void Kart::updatePhysics (float dt) 
763
 
{
 
1033
/*
 
1034
    playCustomSFX()
 
1035
 
 
1036
    This function will play a particular character voice for this kart.  It
 
1037
    returns whether or not a character voice sample exists for the particular
 
1038
    event.  If there is no voice sample, a default can be played instead.
 
1039
 
 
1040
    Use entries from the CustomSFX enumeration as a parameter (see
 
1041
    sfx_manager.hpp).  eg. playCustomSFX(SFXManager::CUSTOM_CRASH)
 
1042
 
 
1043
    Obviously we don't want a certain character voicing multiple phrases
 
1044
    simultaneously.  It just sounds bad.  There are two ways of avoiding this:
 
1045
 
 
1046
    1.  If there is already a voice sample playing for the character
 
1047
        don't play another until it is finished.
 
1048
 
 
1049
    2.  If there is already a voice sample playing for the character
 
1050
        stop the sample, and play the new one.
 
1051
 
 
1052
    Currently we're doing #2.
 
1053
 
 
1054
    rforder
 
1055
 
 
1056
*/
 
1057
 
 
1058
bool Kart::playCustomSFX(unsigned int type)
 
1059
{
 
1060
    // (TODO: add back when properly done)
 
1061
    return false;
 
1062
    
 
1063
    /*
 
1064
    bool ret = false;
 
1065
 
 
1066
    // Stop all other character voices for this kart before playing a new one
 
1067
    // we don't want overlapping phrases coming from the same kart
 
1068
    for (unsigned int n = 0; n < SFXManager::NUM_CUSTOMS; n++)
 
1069
    {
 
1070
        if (m_custom_sounds[n] != NULL)
 
1071
        {
 
1072
            // If the sound we're trying to play is already playing
 
1073
            // don't stop it, we'll just let it finish.
 
1074
            if (type != n) m_custom_sounds[n]->stop();
 
1075
        }
 
1076
    }
 
1077
 
 
1078
    if (type < SFXManager::NUM_CUSTOMS) 
 
1079
    {
 
1080
        if (m_custom_sounds[type] != NULL)
 
1081
        {
 
1082
            ret = true;
 
1083
            //printf("Kart SFX: playing %s for %s.\n", sfx_manager->getCustomTagName(type), m_kart_properties->getIdent().c_str());
 
1084
            // If it's already playing, let it finish
 
1085
            if (m_custom_sounds[type]->getStatus() != SFXManager::SFX_PLAYING)
 
1086
            {
 
1087
                m_custom_sounds[type]->play();
 
1088
            }
 
1089
        }
 
1090
    }
 
1091
    return ret;
 
1092
     */
 
1093
}
 
1094
// ----------------------------------------------------------------------------
 
1095
/** Updates the physics for this kart: computing the driving force, set 
 
1096
 *  steering, handles skidding, terrain impact on kart, ...
 
1097
 *  \param dt Time step size.
 
1098
 */
 
1099
void Kart::updatePhysics(float dt)
 
1100
{
 
1101
    // Check if accel is pressed for the first time. The actual timing
 
1102
    // is done in getStartupBoost - it returns 0 if the start was actually
 
1103
    // too slow to qualify for a boost.
 
1104
    if(!m_has_started && m_controls.m_accel)
 
1105
    {
 
1106
        m_has_started = true;
 
1107
        float f       = m_kart_properties->getStartupBoost();
 
1108
        m_vehicle->activateZipper(f);
 
1109
        MaxSpeed::increaseMaxSpeed(MS_INCREASE_ZIPPER, +10,
 
1110
                                   5.0f, 5.0f);
 
1111
 
 
1112
    }
 
1113
 
764
1114
    m_bounce_back_time-=dt;
765
 
    float engine_power = getActualWheelForce() + handleNitro(dt);
766
 
    if(m_attachment.getType()==ATTACH_PARACHUTE) engine_power*=0.2f;
767
 
 
 
1115
    float engine_power = getActualWheelForce() + handleNitro(dt)
 
1116
                       + m_slipstream->getSlipstreamPower();
 
1117
 
 
1118
    if(m_attachment->getType()==ATTACH_PARACHUTE) engine_power*=0.2f;
 
1119
 
 
1120
    if (m_flying)
 
1121
    {
 
1122
        if (m_controls.m_accel)
 
1123
        {
 
1124
            float orientation = getHeading();
 
1125
            m_body->applyCentralImpulse(btVector3(60.0f*sin(orientation), 0.0, 60.0f*cos(orientation)));
 
1126
        }
 
1127
        if (m_controls.m_steer != 0.0f)
 
1128
        {
 
1129
            m_body->applyTorque(btVector3(0.0, m_controls.m_steer * 3500.0f, 0.0));
 
1130
        }
 
1131
        if (m_controls.m_brake)
 
1132
        {
 
1133
            btVector3 velocity = m_body->getLinearVelocity(); 
 
1134
            
 
1135
            const float x = velocity.x();
 
1136
            if (x > 0.2f)        velocity.setX(x - 0.2f);
 
1137
            else if (x < -0.2f)  velocity.setX(x + 0.2f);
 
1138
            else                 velocity.setX(0);
 
1139
            
 
1140
            const float y = velocity.y();
 
1141
            if (y > 0.2f)        velocity.setY(y - 0.2f);
 
1142
            else if (y < -0.2f)  velocity.setY(y + 0.2f);
 
1143
            else                 velocity.setY(0);
 
1144
            
 
1145
            const float z = velocity.z();
 
1146
            if (z > 0.2f)        velocity.setZ(z - 0.2f);
 
1147
            else if (z < -0.2f)  velocity.setZ(z + 0.2f);
 
1148
            else                 velocity.setZ(0);
 
1149
            
 
1150
            m_body->setLinearVelocity(velocity);
 
1151
            
 
1152
            //float orientation = getHeading();
 
1153
            //m_body->applyCentralImpulse(btVector3(-60.0f*sin(orientation), 0.0, -60.0f*cos(orientation)));
 
1154
        }
 
1155
 
 
1156
        // dampen any roll while flying, makes the kart hard to control
 
1157
        btVector3 velocity = m_body->getAngularVelocity();
 
1158
        const float z = velocity.z();
 
1159
        if (z > 0.1f)        velocity.setZ(z - 0.1f);
 
1160
        else if (z < -0.1f)  velocity.setZ(z + 0.1f);
 
1161
        else                 velocity.setZ(0);
 
1162
        m_body->setAngularVelocity(velocity);
 
1163
    }
 
1164
    
 
1165
    
768
1166
    if(m_controls.m_accel)   // accelerating
769
 
    {   // For a short time after a collision disable the engine,
 
1167
    {
 
1168
        // For a short time after a collision disable the engine,
770
1169
        // so that the karts can bounce back a bit from the obstacle.
771
 
        if(m_bounce_back_time>0.0f) 
 
1170
        if(m_bounce_back_time>0.0f)
772
1171
            engine_power = 0.0f;
773
1172
        // let a player going backwards accelerate quickly (e.g. if a player hits a
774
1173
        // wall, he needs to be able to start again quickly after going backwards)
775
1174
        else if(m_speed < 0.0f)
776
1175
            engine_power *= 5.0f;
777
 
        // Engine slow down due to terrain (see m_power_reduction is set in
778
 
        // update() depending on terrain type.
779
 
        engine_power *= m_power_reduction/stk_config->m_slowdown_factor;
780
 
        m_vehicle->applyEngineForce(engine_power, 2);
781
 
        m_vehicle->applyEngineForce(engine_power, 3);
 
1176
 
 
1177
        // Lose some traction when skidding, to balance the adventage
 
1178
        // Up to r5483 AIs were allowed to cheat in medium and high diff levels
 
1179
        if(m_controls.m_drift)
 
1180
            engine_power *= 0.5f;
 
1181
 
 
1182
        applyEngineForce(engine_power*m_controls.m_accel);
 
1183
 
782
1184
        // Either all or no brake is set, so test only one to avoid
783
1185
        // resetting all brakes most of the time.
784
 
        if(m_vehicle->getWheelInfo(0).m_brake && 
785
 
            !RaceManager::getWorld()->isStartPhase())
 
1186
        if(m_vehicle->getWheelInfo(0).m_brake &&
 
1187
            !World::getWorld()->isStartPhase())
786
1188
            resetBrakes();
787
 
                
788
1189
    }
789
1190
    else
790
1191
    {   // not accelerating
792
1193
        {   // check if the player is currently only slowing down or moving backwards
793
1194
            if(m_speed > 0.0f)
794
1195
            {   // going forward
795
 
                m_vehicle->applyEngineForce(0.f, 2);//engine off
796
 
                m_vehicle->applyEngineForce(0.f, 3);
 
1196
                applyEngineForce(0.f);
797
1197
 
798
1198
                //apply the brakes
799
1199
                for(int i=0; i<4; i++) m_vehicle->setBrake(getBrakeFactor(), i);
805
1205
            {
806
1206
                resetBrakes();
807
1207
                // going backward, apply reverse gear ratio (unless he goes too fast backwards)
808
 
                if ( -m_speed <  getMaxSpeedOnTerrain()*m_max_speed_reverse_ratio )
 
1208
                if ( -m_speed <  MaxSpeed::getCurrentMaxSpeed()
 
1209
                                 *m_kart_properties->getMaxSpeedReverseRatio() )
809
1210
                {
810
1211
                    // The backwards acceleration is artificially increased to
811
1212
                    // allow players to get "unstuck" quicker if they hit e.g.
812
 
                    // a wall. At the same time we have to prevent that driving
813
 
                    // backards gives an advantage (see m_max_speed_reverse_ratio),
814
 
                    // and that a potential slowdown due to the terrain the 
815
 
                    // kart is driving on feels right. The speedup factor on 
816
 
                    // normal terrain (power_reduction/slowdown_factor should 
817
 
                    // be 2.5 (which was experimentally determined to feel 
818
 
                    // right).
819
 
                    float f = 2.5f - 3.8f*(1-m_power_reduction/stk_config->m_slowdown_factor);
820
 
                    // Avoid that a kart gets really stuck:
821
 
                    if(f<0.1f) f=0.1f;
822
 
                    m_vehicle->applyEngineForce(-engine_power*f, 2);
823
 
                    m_vehicle->applyEngineForce(-engine_power*f, 3);
 
1213
                    // a wall. 
 
1214
                    applyEngineForce(-engine_power*2.5f);
824
1215
                }
825
 
                else
 
1216
                else  // -m_speed >= max speed on this terrain
826
1217
                {
827
 
                    m_vehicle->applyEngineForce(0.f, 2);
828
 
                    m_vehicle->applyEngineForce(0.f, 3);
829
 
                }    
830
 
                
831
 
            }
 
1218
                    applyEngineForce(0.0f);
 
1219
                }
 
1220
 
 
1221
            }   // m_speed <00
832
1222
        }
833
 
        else
 
1223
        else   // !m_brake
834
1224
        {
835
1225
            // lift the foot from throttle, brakes with 10% engine_power
836
 
            m_vehicle->applyEngineForce(-m_controls.m_accel*engine_power*0.1f, 2);
837
 
            m_vehicle->applyEngineForce(-m_controls.m_accel*engine_power*0.1f, 3);
 
1226
            applyEngineForce(-m_controls.m_accel*engine_power*0.1f);
838
1227
 
839
 
            if(!RaceManager::getWorld()->isStartPhase())
840
 
                resetBrakes();
841
 
        }
842
 
    }
 
1228
            // If not giving power (forward or reverse gear), and speed is low
 
1229
            // we are "parking" the kart, so in battle mode we can ambush people, eg
 
1230
            if(abs(m_speed) < 5.0f) {
 
1231
                for(int i=0; i<4; i++) m_vehicle->setBrake(20.0f, i);
 
1232
            }
 
1233
        }   // !m_brake
 
1234
    }   // not accelerating
843
1235
#ifdef ENABLE_JUMP
844
1236
    if(m_controls.jump && isOnGround())
845
 
    { 
 
1237
    {
846
1238
      //Vector3 impulse(0.0f, 0.0f, 10.0f);
847
1239
      //        getVehicle()->getRigidBody()->applyCentralImpulse(impulse);
848
1240
        btVector3 velocity         = m_body->getLinearVelocity();
872
1264
    }
873
1265
    if(m_skidding>1.0f)
874
1266
    {
875
 
        if(m_skid_sound->getStatus() != SFXManager::SFX_PLAYING && 
 
1267
        if(m_skid_sound->getStatus() != SFXManager::SFX_PLAYING &&
876
1268
            m_kart_properties->hasSkidmarks())
877
1269
            m_skid_sound->play();
878
1270
    }
880
1272
    {
881
1273
        m_skid_sound->stop();
882
1274
    }
 
1275
    
 
1276
    // dynamically determine friction so that the kart looses its traction 
 
1277
    // when trying to drive on too steep surfaces. Below angles of 0.25 rad, 
 
1278
    // you have full traction; above 0.5 rad angles you have absolutely none; 
 
1279
    // inbetween  there is a linear change in friction
 
1280
    float friction = 1.0f;
 
1281
    bool enable_skidding = false;
 
1282
    
 
1283
    // If a material has friction of more than 10000 treat this
 
1284
    // as no-skidding possible. This way the current skidding
 
1285
    // handling can be disabled for certain material (e.g. the
 
1286
    // curve in skyline on which otherwise karts could not drive).
 
1287
    // We also had a crash reported here, which was caused by not
 
1288
    // having a material here - no idea how this could have happened,
 
1289
    // but this problem is now avoided by testing if there is a material
 
1290
    if (isOnGround() && 
 
1291
         (!getMaterial() || getMaterial()->getFriction()<10000.0f))
 
1292
    {
 
1293
        const btMatrix3x3 &m = m_vehicle->getChassisWorldTransform().getBasis();
 
1294
        // To get the angle between up=(0,1,0), we have to do:
 
1295
        // m*(0,1,0) to get the up vector of the kart, then the 
 
1296
        // scalar product between this and (0,1,0) - which is m[1][1]:
 
1297
        float distanceFromUp = m[1][1];
 
1298
        
 
1299
        if (distanceFromUp < 0.85f)
 
1300
        {
 
1301
            friction = 0.0f;
 
1302
            enable_skidding = true;
 
1303
        }
 
1304
        else if (distanceFromUp > 0.9f)
 
1305
        {
 
1306
            friction = 1.0f;
 
1307
        }
 
1308
        else
 
1309
        {
 
1310
            friction = (distanceFromUp - 0.85f) / 0.5f;
 
1311
            enable_skidding = true;
 
1312
        }
 
1313
    }
 
1314
    
 
1315
    for (unsigned int i=0; i<4; i++)
 
1316
    {
 
1317
        btWheelInfo& wheel = m_vehicle->getWheelInfo(i);
 
1318
        wheel.m_frictionSlip = friction*m_kart_properties->getFrictionSlip();
 
1319
    }
 
1320
    
 
1321
    m_vehicle->enableSliding(enable_skidding);
 
1322
 
 
1323
    
 
1324
    /*
 
1325
    // debug prints
 
1326
    static float f = 0.0f;
 
1327
    f += dt;
 
1328
    if (f > 0.5f)
 
1329
    {
 
1330
        f -= 0.5f;
 
1331
        printf("[%s] %f %f --> friction = %f\n", m_kart_properties->getIdent().c_str(), getPitch(), getRoll(), friction);
 
1332
    }
 
1333
    */
 
1334
 
883
1335
    float steering = getMaxSteerAngle() * m_controls.m_steer*m_skidding;
884
1336
 
885
1337
    m_vehicle->setSteeringValue(steering, 0);
893
1345
    // calculate direction of m_speed
894
1346
    const btTransform& chassisTrans = getVehicle()->getChassisWorldTransform();
895
1347
    btVector3 forwardW (
896
 
               chassisTrans.getBasis()[0][1],
897
 
               chassisTrans.getBasis()[1][1],
898
 
               chassisTrans.getBasis()[2][1]);
 
1348
               chassisTrans.getBasis()[0][2],
 
1349
               chassisTrans.getBasis()[1][2],
 
1350
               chassisTrans.getBasis()[2][2]);
899
1351
 
900
1352
    if (forwardW.dot(getVehicle()->getRigidBody()->getLinearVelocity()) < btScalar(0.))
901
1353
        m_speed *= -1.f;
902
1354
 
903
 
    //cap at maximum velocity
904
 
    const float max_speed = getMaxSpeedOnTerrain();
905
 
    if ( m_speed >  max_speed )
906
 
    {
907
 
        const float velocity_ratio = max_speed/m_speed;
908
 
        m_speed                    = max_speed;
909
 
        btVector3 velocity         = m_body->getLinearVelocity();
910
 
 
911
 
        velocity.setY( velocity.getY() * velocity_ratio );
912
 
        velocity.setX( velocity.getX() * velocity_ratio );
913
 
 
914
 
        getVehicle()->getRigidBody()->setLinearVelocity( velocity );
915
 
 
916
 
    }
 
1355
    // Cap speed if necessary
 
1356
    MaxSpeed::update(dt);
917
1357
 
918
1358
    // To avoid tunneling (which can happen on long falls), clamp the
919
 
    // velocity in Z direction. Tunneling can happen if the Z velocity
 
1359
    // velocity in Y direction. Tunneling can happen if the Y velocity
920
1360
    // is larger than the maximum suspension travel (per frame), since then
921
1361
    // the wheel suspension can not stop/slow down the fall (though I am
922
1362
    // not sure if this is enough in all cases!). So the speed is limited
923
1363
    // to suspensionTravel / dt with dt = 1/60 (since this is the dt
924
1364
    // bullet is using).
 
1365
    // Only apply if near ground instead of purely based on speed avoiding
 
1366
    // the "parachute on top" look.
925
1367
    const Vec3 &v = m_body->getLinearVelocity();
926
 
    if(v.getZ() < - m_kart_properties->getSuspensionTravelCM()*0.01f*60)
 
1368
    if(/*isNearGround() &&*/ v.getY() < - m_kart_properties->getSuspensionTravelCM()*0.01f*60)
927
1369
    {
928
1370
        Vec3 v_clamped = v;
929
1371
        // clamp the speed to 99% of the maxium falling speed.
930
 
        v_clamped.setZ(-m_kart_properties->getSuspensionTravelCM()*0.01f*60 * 0.99f);
 
1372
        v_clamped.setY(-m_kart_properties->getSuspensionTravelCM()*0.01f*60 * 0.99f);
931
1373
        m_body->setLinearVelocity(v_clamped);
932
1374
    }
933
1375
 
938
1380
    // when going faster, use higher pitch for engine
939
1381
    if(m_engine_sound && sfx_manager->sfxAllowed())
940
1382
    {
941
 
        m_engine_sound->speed(0.6f + (float)(m_speed / max_speed)*0.7f);
 
1383
        if(isOnGround())
 
1384
        {
 
1385
            float max_speed = MaxSpeed::getCurrentMaxSpeed();
 
1386
            // Engine noise is based half in total speed, half in fake gears:
 
1387
            // With a sawtooth graph like /|/|/| we get 3 even spaced gears,
 
1388
            // ignoring the gear settings from stk_config, but providing a
 
1389
            // good enough brrrBRRRbrrrBRRR sound effect. Speed factor makes
 
1390
            // it a "staired sawtooth", so more acoustically rich.
 
1391
            float f = m_speed/max_speed;
 
1392
            // Speed at this stage is not yet capped, so it can be > 1, which 
 
1393
            // results in odd engine sfx.
 
1394
            if (f>1.0f) f=1.0f;
 
1395
 
 
1396
            float gears = 3.0f * fmod(f, 0.333334f);
 
1397
            m_engine_sound->speed(0.6f + (f +gears)* 0.35f);
 
1398
        }
 
1399
        else
 
1400
        {
 
1401
            // When flying, fixed value but not too high pitch
 
1402
            // This gives some variation (vs previous "on wheels" one)
 
1403
            m_engine_sound->speed(0.9f);
 
1404
        }
942
1405
        m_engine_sound->position(getXYZ());
943
1406
    }
944
 
#ifdef XX   
 
1407
#ifdef XX
945
1408
    printf("forward %f %f %f %f  side %f %f %f %f angVel %f %f %f heading %f\n"
946
1409
       ,m_vehicle->m_forwardImpulse[0]
947
1410
       ,m_vehicle->m_forwardImpulse[1]
954
1417
       ,m_body->getAngularVelocity().getX()
955
1418
       ,m_body->getAngularVelocity().getY()
956
1419
       ,m_body->getAngularVelocity().getZ()
957
 
       ,getHPR().getHeading()
 
1420
       ,getHeading()
958
1421
       );
959
1422
#endif
 
1423
    
960
1424
}   // updatePhysics
961
1425
 
962
 
//-----------------------------------------------------------------------------
963
 
void Kart::forceRescue()
964
 
{
965
 
    m_rescue=true;
966
 
}   // forceRescue
967
 
//-----------------------------------------------------------------------------
968
 
/** Drops a kart which was rescued back on the track.
 
1426
 
 
1427
//-----------------------------------------------------------------------------
 
1428
/** Attaches the right model, creates the physics and loads all special 
 
1429
 *  effects (particle systems etc.)
969
1430
 */
970
 
void Kart::endRescue()
971
 
{
972
 
    m_rescue = false ;
973
 
 
974
 
    m_body->setLinearVelocity (btVector3(0.0f,0.0f,0.0f));
975
 
    m_body->setAngularVelocity(btVector3(0.0f,0.0f,0.0f));
976
 
 
977
 
    // let the mode decide where to put the kart
978
 
    RaceManager::getWorld()->moveKartAfterRescue(this, m_body);
979
 
    
980
 
    RaceManager::getWorld()->getPhysics()->addKart(this);
981
 
}   // endRescue
982
 
 
983
 
//-----------------------------------------------------------------------------
984
 
 
985
1431
void Kart::loadData()
986
1432
{
987
 
    float r [ 2 ] = { -10.0f, 100.0f } ;
988
 
 
989
 
 
990
 
    ssgEntity *obj = m_kart_properties->getKartModel()->getRoot();
 
1433
    m_kart_model->attachModel(&m_node);
 
1434
    // Attachment must be created after attachModel, since only then the
 
1435
    // scene node will exist (to which the attachment is added). But the
 
1436
    // attachment is needed in createPhysics (which gets the mass, which
 
1437
    // is dependent on the attachment).
 
1438
    m_attachment = new Attachment(this);
991
1439
    createPhysics();
992
1440
 
993
 
    SSGHelp::createDisplayLists(obj);  // create all display lists
994
 
    ssgRangeSelector *lod = new ssgRangeSelector ;
995
 
 
996
 
    lod -> addKid ( obj ) ;
997
 
    lod -> setRanges ( r, 2 ) ;
998
 
 
999
 
    getModelTransform() -> addKid ( lod ) ;
1000
 
 
1001
1441
    // Attach Particle System
1002
 
    m_smoke_system = new Smoke(this);
1003
 
    m_smoke_system->ref();
1004
 
    m_nitro = new Nitro(this);
1005
 
    m_nitro->ref();
 
1442
    if ( UserConfigParams::m_graphical_effects )
 
1443
    {
 
1444
        m_smoke_system        = new Smoke(this);
 
1445
    }
 
1446
    m_water_splash_system = new WaterSplash(this);
 
1447
    m_nitro               = new Nitro(this);
 
1448
    m_slipstream          = new SlipStream(this);
1006
1449
 
1007
1450
    if(m_kart_properties->hasSkidmarks())
1008
1451
        m_skidmarks = new SkidMarks(*this);
1009
 
 
1010
 
    m_shadow = createShadow(m_kart_properties->getShadowFile(), -1, 1, -1, 1);
1011
 
    m_shadow->ref();
1012
 
    m_model_transform->addKid ( m_shadow );
1013
 
    m_shadow_enabled = true;
 
1452
       
 
1453
    m_shadow = new Shadow(m_kart_properties->getShadowTexture(),
 
1454
                          m_node);
1014
1455
}   // loadData
1015
1456
 
1016
1457
//-----------------------------------------------------------------------------
1017
 
/** Stores the current suspension length. This function is called from world 
 
1458
/** Stores the current suspension length. This function is called from world
1018
1459
 *  after all karts are in resting position (see World::resetAllKarts), so
1019
1460
 *  that the default suspension rest length can be stored. This is then used
1020
1461
 *  later to move the wheels depending on actual suspension, so that when
1021
 
 *  a kart is in rest, the wheels are at the position at which they were 
 
1462
 *  a kart is in rest, the wheels are at the position at which they were
1022
1463
 *  modelled.
1023
1464
 */
1024
1465
void Kart::setSuspensionLength()
1031
1472
}   // setSuspensionLength
1032
1473
 
1033
1474
//-----------------------------------------------------------------------------
1034
 
void Kart::updateGraphics(const Vec3& off_xyz,  const Vec3& off_hpr)
1035
 
{
1036
 
    float wheel_z_axis[4];
1037
 
    KartModel *kart_model = m_kart_properties->getKartModel();
 
1475
/** Applies engine power to all the wheels that are traction capable,
 
1476
 *  so other parts of code do not have to be adjusted to simulate different
 
1477
 *  kinds of vehicles in the general case, only if they are trying to
 
1478
 *  simulate traction control, diferentials or multiple independent electric
 
1479
 *  engines, they will have to tweak the power in a per wheel basis.
 
1480
 */
 
1481
void Kart::applyEngineForce(float force)
 
1482
{
 
1483
    // Split power to simulate a 4WD 40-60, other values possible
 
1484
    // FWD or RWD is a matter of putting a 0 and 1 in the right place
 
1485
    float frontForce = force*0.4f;
 
1486
    float rearForce = force*0.6f;
 
1487
    // Front wheels
 
1488
    for(unsigned int i=0; i<2; i++)
 
1489
    {
 
1490
        m_vehicle->applyEngineForce (frontForce, i);
 
1491
    }
 
1492
    // Rear wheels
 
1493
    for(unsigned int i=2; i<4; i++)
 
1494
    {
 
1495
        m_vehicle->applyEngineForce (rearForce, i);
 
1496
    }
 
1497
}   // applyEngineForce
 
1498
 
 
1499
//-----------------------------------------------------------------------------
 
1500
/** Updates the graphics model. Mainly set the graphical position to be the
 
1501
 *  same as the physics position, but uses offsets to position and rotation
 
1502
 *  for special gfx effects (e.g. skidding will turn the karts more). These
 
1503
 *  variables are actually not used here atm, but are defined here and then
 
1504
 *  used in Moveable.
 
1505
 *  \param offset_xyz Offset to be added to the position.
 
1506
 *  \param rotation Additional rotation.
 
1507
 */
 
1508
void Kart::updateGraphics(const Vec3& offset_xyz, 
 
1509
                          const btQuaternion& rotation)
 
1510
{
 
1511
    float wheel_up_axis[4];
1038
1512
    for(unsigned int i=0; i<4; i++)
1039
1513
    {
1040
1514
        // Set the suspension length
1041
 
        wheel_z_axis[i] = m_default_suspension_length[i]
1042
 
                        - m_vehicle->getWheelInfo(i).m_raycastInfo.m_suspensionLength;
 
1515
        wheel_up_axis[i] = m_default_suspension_length[i]
 
1516
                         - m_vehicle->getWheelInfo(i).m_raycastInfo.m_suspensionLength;
1043
1517
    }
1044
 
#define AUTO_SKID_VISUAL 1.7f
1045
 
    float auto_skid; 
1046
 
    if (m_skidding>AUTO_SKID_VISUAL) // Above a limit, start counter rotating the wheels to get drifting look 
1047
 
        auto_skid = m_controls.m_steer*30.0f*((AUTO_SKID_VISUAL - m_skidding) / 0.8f); // divisor comes from max_skid - AUTO_SKID_VISUAL
1048
 
    else
1049
 
        auto_skid = m_controls.m_steer*30.0f;
1050
 
    kart_model->adjustWheels(m_wheel_rotation, auto_skid,
1051
 
                             wheel_z_axis);
 
1518
    m_kart_model->update(m_wheel_rotation, getSteerPercent(), wheel_up_axis);
1052
1519
 
1053
 
    Vec3        center_shift  = getGravityCenterShift();
1054
 
    float X = m_vehicle->getWheelInfo(0).m_chassisConnectionPointCS.getZ()
 
1520
    Vec3        center_shift  = m_kart_properties->getGravityCenterShift();
 
1521
    float y = m_vehicle->getWheelInfo(0).m_chassisConnectionPointCS.getY()
1055
1522
            - m_default_suspension_length[0]
1056
1523
            - m_vehicle->getWheelInfo(0).m_wheelsRadius
1057
 
            - (kart_model->getWheelGraphicsRadius(0)
1058
 
               -kart_model->getWheelGraphicsPosition(0).getZ() );
1059
 
    center_shift.setZ(X);
 
1524
            - (m_kart_model->getWheelGraphicsRadius(0)
 
1525
               -m_kart_model->getWheelGraphicsPosition(0).getY() );
 
1526
    center_shift.setY(y);
1060
1527
 
1061
1528
    if(m_smoke_system)
1062
1529
    {
1063
 
        float f = fabsf(m_controls.m_steer) > 0.8 ? 50.0f : 0.0f;
 
1530
        float f=0.0f;
 
1531
        if(getMaterial() && getMaterial()->hasSmoke() && 
 
1532
            fabsf(m_controls.m_steer) > 0.8           &&
 
1533
            isOnGround()                                  )
 
1534
            f=250.0f;
1064
1535
        m_smoke_system->setCreationRate((m_skidding-1)*f);
1065
1536
    }
 
1537
    if(m_water_splash_system)
 
1538
    {
 
1539
        float f = getMaterial() && getMaterial()->hasWaterSplash() && isOnGround()
 
1540
                ? sqrt(getSpeed())*40.0f
 
1541
                : 0.0f;
 
1542
        m_water_splash_system->setCreationRate(f);
 
1543
    }
1066
1544
    if(m_nitro)
1067
 
        m_nitro->setCreationRate(m_controls.m_nitro && m_collected_energy>0
1068
 
                                 ? getSpeed()*5.0f : 0);
1069
 
 
1070
 
    float speed_ratio    = getSpeed()/getMaxSpeed();
 
1545
        // fabs(speed) is important, otherwise the negative number will
 
1546
        // become a huge unsigned number in the particle scene node!
 
1547
        m_nitro->setCreationRate(m_controls.m_nitro && isOnGround() && m_collected_energy>0
 
1548
                                 ? (10.0f + fabsf(getSpeed())*20.0f) : 0);
 
1549
 
 
1550
    // For testing purposes mis-use the nitro graphical effects to show
 
1551
    // then the slipstream becomes usable.
 
1552
    if(m_slipstream->inUse())
 
1553
        m_nitro->setCreationRate(20.0f);
 
1554
 
 
1555
    float speed_ratio    = getSpeed()/MaxSpeed::getCurrentMaxSpeed();
1071
1556
    float offset_heading = getSteerPercent()*m_kart_properties->getSkidVisual()
1072
1557
                         * speed_ratio * m_skidding*m_skidding;
1073
 
    Moveable::updateGraphics(center_shift, Vec3(offset_heading, 0, 0));
 
1558
    Moveable::updateGraphics(center_shift, 
 
1559
                             btQuaternion(offset_heading, 0, 0));
1074
1560
}   // updateGraphics
1075
1561
 
1076
1562
/* EOF */