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

« back to all changes in this revision

Viewing changes to src/items/plunger.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:
3
3
//  SuperTuxKart - a fun racing game with go-kart
4
4
//  Copyright (C) 2007 Joerg Henrichs
5
5
//
 
6
//  Physics improvements and linear intersection algorithm by
 
7
//  by David Mikos. Copyright (C) 2009.
 
8
//
6
9
//  This program is free software; you can redistribute it and/or
7
10
//  modify it under the terms of the GNU General Public License
8
11
//  as published by the Free Software Foundation; either version 3
19
22
 
20
23
#include "items/plunger.hpp"
21
24
 
22
 
#include "race_manager.hpp"
23
 
#include "graphics/scene.hpp"
 
25
#include "graphics/irr_driver.hpp"
 
26
#include "io/xml_node.hpp"
24
27
#include "items/rubber_band.hpp"
25
28
#include "items/projectile_manager.hpp"
26
 
#include "karts/player_kart.hpp"
 
29
#include "karts/kart.hpp"
27
30
#include "modes/world.hpp"
28
 
#include "physics/moving_physics.hpp"
 
31
#include "physics/physical_object.hpp"
29
32
#include "tracks/track.hpp"
30
33
#include "utils/constants.hpp"
 
34
#include "utils/string_utils.hpp"
 
35
 
 
36
 
 
37
const wchar_t* getPlungerInFaceString()
 
38
{
 
39
    const int PLUNGER_IN_FACE_STRINGS_AMOUNT = 2;
 
40
 
 
41
    RandomGenerator r;
 
42
    const int id = r.get(PLUNGER_IN_FACE_STRINGS_AMOUNT);
 
43
 
 
44
    switch (id)
 
45
    {
 
46
        //I18N: shown when a player receives a plunger in his face
 
47
        case 0: return _("%0 gets a fancy mask from %1");
 
48
        //I18N: shown when a player receives a plunger in his face
 
49
        case 1: return _("%1 merges %0's face with a plunger");
 
50
        default:assert(false); return L"";   // avoid compiler warning
 
51
    }
 
52
}
 
53
 
31
54
 
32
55
// -----------------------------------------------------------------------------
33
 
Plunger::Plunger(Kart *kart) : Flyable(kart, POWERUP_PLUNGER)
 
56
Plunger::Plunger(Kart *kart) : Flyable(kart, PowerupManager::POWERUP_PLUNGER)
34
57
{
35
 
    float y_offset = 0.5f*kart->getKartLength()+0.5f*m_extend.getY();
36
 
    
 
58
    const float gravity = 0.0f;
 
59
 
 
60
    float forward_offset = 0.5f*kart->getKartLength()+0.5f*m_extend.getZ();
 
61
    float up_velocity = 0.0f;
 
62
    float plunger_speed = 2 * m_speed;
 
63
 
37
64
    // if the kart is looking backwards, release from the back
38
65
    m_reverse_mode = kart->getControls().m_look_back;
39
 
    
 
66
 
40
67
    // find closest kart in front of the current one
41
 
    const Kart *closest_kart=0;   btVector3 direction;   float kartDistSquared;
42
 
    getClosestKart(&closest_kart, &kartDistSquared, &direction, kart /* search in front of this kart */, m_reverse_mode);
43
 
    
44
 
    btTransform trans = kart->getTrans();
45
 
    
46
 
    btMatrix3x3 thisKartDirMatrix = kart->getKartHeading().getBasis();
47
 
    btVector3 thisKartDirVector(thisKartDirMatrix[0][1],
48
 
                                thisKartDirMatrix[1][1],
49
 
                                thisKartDirMatrix[2][1]);
50
 
    
51
 
    float heading=atan2(-thisKartDirVector.getX(), thisKartDirVector.getY());
52
 
    float pitch = kart->getTerrainPitch(heading);
 
68
    const Kart *closest_kart=0;   
 
69
    Vec3        direction;
 
70
    float       kart_dist_2;
 
71
    getClosestKart(&closest_kart, &kart_dist_2, &direction,
 
72
                   kart /* search in front of this kart */, m_reverse_mode);
 
73
 
 
74
    btTransform kart_transform = kart->getKartTransform();
 
75
    btMatrix3x3 kart_rotation = kart_transform.getBasis();
 
76
    // The current forward vector is rotation*(0,0,1), or:
 
77
    btVector3 forward(kart_rotation.getColumn(2));
 
78
 
 
79
    float heading =kart->getHeading();
 
80
    float pitch  = kart->getTerrainPitch(heading);
53
81
 
54
82
    // aim at this kart if it's not too far
55
 
    if(closest_kart != NULL && kartDistSquared < 30*30)
 
83
    if(closest_kart != NULL && kart_dist_2 < 30*30)
56
84
    {
57
 
        btVector3 closestKartLoc = closest_kart->getTrans().getOrigin();
58
 
        
59
 
        if(!m_reverse_mode) // substracting speeds doesn't work backwards, since both speeds go in opposite directions
60
 
        {
61
 
            // FIXME - this approximation will be wrong if both karts' directions are not colinear
62
 
            const float time = sqrt(kartDistSquared) / (m_speed - closest_kart->getSpeed());
63
 
            
64
 
            // calculate the approximate location of the aimed kart in 'time' seconds
65
 
            closestKartLoc += time*closest_kart->getVelocity();
66
 
        }
67
 
        
68
 
        // calculate the angle at which the projectile should be thrown
69
 
        // to hit the aimed kart
70
 
        float projectileAngle=atan2(-(closestKartLoc.getX() - kart->getTrans().getOrigin().getX()),
71
 
                                    closestKartLoc.getY() - kart->getTrans().getOrigin().getY() );
72
 
        
73
 
        // apply transformation to the bullet object
74
 
        btMatrix3x3 m;
75
 
        m.setEulerZYX(pitch, 0.0f, projectileAngle);
76
 
        trans.setBasis(m);
77
 
        
78
 
        createPhysics(y_offset, btVector3(0.0f, m_speed*2, 0.0f),
79
 
                      new btCylinderShape(0.5f*m_extend), 0.0f /* gravity */, false /* rotates */, false, &trans );
 
85
        float fire_angle     = 0.0f;
 
86
        getLinearKartItemIntersection (kart->getXYZ(), closest_kart,
 
87
                                       plunger_speed, gravity, forward_offset,
 
88
                                       &fire_angle, &up_velocity);
 
89
 
 
90
        btTransform trans = kart->getTrans();
 
91
    
 
92
        trans.setRotation(btQuaternion(btVector3(0, 1, 0), fire_angle));
 
93
 
 
94
        m_initial_velocity = btVector3(0.0f, up_velocity, plunger_speed);
 
95
 
 
96
        createPhysics(forward_offset, m_initial_velocity,
 
97
                      new btCylinderShape(0.5f*m_extend), gravity, 
 
98
                      /* rotates */false , /*turn around*/false, &trans );
80
99
    }
81
100
    else
82
101
    {
83
 
        trans = kart->getKartHeading();
84
 
 
85
 
        createPhysics(y_offset, btVector3(0.0f, m_speed*2, 0.0f),
86
 
                      new btCylinderShape(0.5f*m_extend), 0.0f /* gravity */, false /* rotates */, m_reverse_mode, &trans );
 
102
        createPhysics(forward_offset, btVector3(pitch, 0.0f, plunger_speed),
 
103
                      new btCylinderShape(0.5f*m_extend), gravity, 
 
104
                      false /* rotates */, m_reverse_mode, &kart_transform );
87
105
    }
88
 
    
 
106
 
 
107
    //adjust height according to terrain
 
108
    setAdjustUpVelocity(false);
 
109
 
89
110
    // pulling back makes no sense in battle mode, since this mode is not a race.
90
111
    // so in battle mode, always hide view
91
 
    if( m_reverse_mode || race_manager->isBattleMode(race_manager->getMinorMode()) )
 
112
    if( m_reverse_mode || race_manager->isBattleMode() )
92
113
        m_rubber_band = NULL;
93
114
    else
94
115
    {
95
 
        m_rubber_band = new RubberBand(this, *kart);
96
 
        m_rubber_band->ref();
 
116
        m_rubber_band = new RubberBand(this, kart);
97
117
    }
98
118
    m_keep_alive = -1;
99
119
}   // Plunger
101
121
// -----------------------------------------------------------------------------
102
122
Plunger::~Plunger()
103
123
{
104
 
    m_rubber_band->removeFromScene();
105
 
    ssgDeRefDelete(m_rubber_band);
 
124
    if(m_rubber_band)
 
125
        delete m_rubber_band;
106
126
}   // ~Plunger
107
127
 
108
128
// -----------------------------------------------------------------------------
109
 
void Plunger::init(const lisp::Lisp* lisp, ssgEntity *plunger_model)
 
129
void Plunger::init(const XMLNode &node, scene::IMesh *plunger_model)
110
130
{
111
 
    Flyable::init(lisp, plunger_model, POWERUP_PLUNGER);
 
131
    Flyable::init(node, plunger_model, PowerupManager::POWERUP_PLUNGER);
112
132
}   // init
113
133
 
114
134
// -----------------------------------------------------------------------------
122
142
        {
123
143
            setHasHit();
124
144
            projectile_manager->notifyRemove();
125
 
            ssgTransform *m = getModelTransform();
126
 
            m->removeAllKids();
127
 
            scene->remove(m);
128
145
        }
129
146
        if(m_rubber_band != NULL) m_rubber_band->update(dt);
130
147
        return;
133
150
    // Else: update the flyable and rubber band
134
151
    Flyable::update(dt);
135
152
    if(m_rubber_band != NULL) m_rubber_band->update(dt);
136
 
    
 
153
 
137
154
    if(getHoT()==Track::NOHIT) return;
138
 
    float hat = getTrans().getOrigin().getZ()-getHoT();
139
 
    
140
 
    // Use the Height Above Terrain to set the Z velocity.
141
 
    // HAT is clamped by min/max height. This might be somewhat
142
 
    // unphysical, but feels right in the game.
143
 
    hat = std::max(std::min(hat, m_max_height) , m_min_height);
144
 
    float delta = m_average_height - hat;
145
 
    btVector3 v=getVelocity();
146
 
    v.setZ( m_st_force_updown[POWERUP_PLUNGER]*delta);
147
 
    setVelocity(v);
148
 
    
149
155
}   // update
150
156
 
151
157
// -----------------------------------------------------------------------------
154
160
 *  Instead it stays around (though not as a graphical or physical object)
155
161
 *  till the rubber band expires.
156
162
 *  \param kart Pointer to the kart hit (NULL if not a kart).
157
 
 *  \param mp  Pointer to MovingPhysics object if hit (NULL otherwise).
 
163
 *  \param obj  Pointer to PhysicalObject object if hit (NULL otherwise).
158
164
 */
159
 
void Plunger::hit(Kart *kart, MovingPhysics *mp)
 
165
void Plunger::hit(Kart *kart, PhysicalObject *obj)
160
166
{
161
167
    if(isOwnerImmunity(kart)) return;
162
168
 
 
169
    RaceGUIBase* gui = World::getWorld()->getRaceGUI();
 
170
    irr::core::stringw hit_message;
 
171
 
163
172
    // pulling back makes no sense in battle mode, since this mode is not a race.
164
173
    // so in battle mode, always hide view
165
 
    if( m_reverse_mode || race_manager->isBattleMode(race_manager->getMinorMode()) )
 
174
    if( m_reverse_mode || race_manager->isBattleMode() )
166
175
    {
167
 
        if(kart) kart->blockViewWithPlunger();
 
176
        if(kart)
 
177
        {
 
178
            kart->blockViewWithPlunger();
 
179
 
 
180
            hit_message += StringUtils::insertValues(getPlungerInFaceString(),
 
181
                                                     kart->getName().c_str(),
 
182
                                                     m_owner->getName().c_str()
 
183
                                                    ).c_str();
 
184
            gui->addMessage(hit_message, NULL, 3.0f, 40, video::SColor(255, 255, 255, 255), false);
 
185
        }
168
186
 
169
187
        m_keep_alive = 0;
170
 
        // Make this object invisible by placing it faaar down. Not that if this
 
188
        // Make this object invisible by placing it faaar down. Note that if this
171
189
        // objects is simply removed from the scene graph, it might be auto-deleted
172
190
        // because the ref count reaches zero.
173
 
        Vec3 hell(0, 0, -10000);
174
 
        getModelTransform()->setTransform(hell.toFloat());
175
 
        RaceManager::getWorld()->getPhysics()->removeBody(getBody());
 
191
        getNode()->setVisible(false);
 
192
        World::getWorld()->getPhysics()->removeBody(getBody());
176
193
    }
177
194
    else
178
195
    {
181
198
        // Make this object invisible by placing it faaar down. Not that if this
182
199
        // objects is simply removed from the scene graph, it might be auto-deleted
183
200
        // because the ref count reaches zero.
184
 
        Vec3 hell(0, 0, -10000);
185
 
        getModelTransform()->setTransform(hell.toFloat());
186
 
        RaceManager::getWorld()->getPhysics()->removeBody(getBody());
187
 
        
 
201
        scene::ISceneNode *node = getNode();
 
202
        if(node)
 
203
        {
 
204
            node->setVisible(false);
 
205
        }
 
206
        World::getWorld()->getPhysics()->removeBody(getBody());
 
207
 
188
208
        if(kart)
189
209
        {
190
210
            m_rubber_band->hit(kart);
191
211
            return;
192
212
        }
193
 
        else if(mp)
 
213
        else if(obj)
194
214
        {
195
 
            Vec3 pos(mp->getBody()->getWorldTransform().getOrigin());
 
215
            Vec3 pos(obj->getBody()->getWorldTransform().getOrigin());
196
216
            m_rubber_band->hit(NULL, &pos);
197
217
        }
198
218
        else
204
224
 
205
225
// -----------------------------------------------------------------------------
206
226
/** Called when the plunger hits the track. In this case, notify the rubber
207
 
 *  band, and remove the plunger (but keep it alive). 
 
227
 *  band, and remove the plunger (but keep it alive).
208
228
 */
209
229
void Plunger::hitTrack()
210
230
{