1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2010-2015 Joerg Henrichs
4 //
5 //  This program is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU General Public License
7 //  as published by the Free Software Foundation; either version 3
8 //  of the License, or (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 #include "karts/abstract_kart_animation.hpp"
20 
21 #include "graphics/slip_stream.hpp"
22 #include "items/powerup.hpp"
23 #include "karts/abstract_kart.hpp"
24 #include "karts/kart_model.hpp"
25 #include "karts/skidding.hpp"
26 #include "modes/world.hpp"
27 #include "network/network_string.hpp"
28 #include "physics/btKart.hpp"
29 #include "physics/physics.hpp"
30 #include "physics/triangle_mesh.hpp"
31 #include "tracks/track.hpp"
32 #include "utils/mini_glm.hpp"
33 
34 #include <limits>
35 
36 /** Constructor. Note that kart can be NULL in case that the animation is
37  *  used for a basket ball in a cannon animation.
38  *  \param kart Pointer to the kart that is animated, or NULL if the
39  *         the animation is meant for a basket ball etc.
40  */
AbstractKartAnimation(AbstractKart * kart,const std::string & name)41 AbstractKartAnimation::AbstractKartAnimation(AbstractKart* kart,
42                                              const std::string &name)
43 {
44     m_kart = kart;
45     m_name = name;
46     m_created_ticks = World::getWorld()->getTicksSinceStart();
47     m_created_transform = btTransform(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f));
48     // Remove previous animation if there is one
49 #ifndef DEBUG
50     // Use this code in non-debug mode to avoid a memory leak (and messed
51     // up animations) if this should happen. In debug mode this condition
52     // is caught by setKartAnimation(), and useful error messages are
53     // printed
54     if (kart && kart->getKartAnimation())
55     {
56         AbstractKartAnimation* ka = kart->getKartAnimation();
57         kart->setKartAnimation(NULL);
58         delete ka;
59     }
60 #endif
61     // Register this animation with the kart (which will free it
62     // later).
63     if (kart)
64     {
65         m_created_transform = kart->getTrans();
66         kart->setKartAnimation(this);
67         Physics::get()->removeKart(m_kart);
68         kart->getSkidding()->reset();
69         kart->getSlipstream()->reset();
70         if (kart->isSquashed())
71         {
72             // A time of 0 reset the squashing
73             kart->setSquash(0.0f, 0.0f);
74         }
75     }
76     MiniGLM::compressbtTransform(m_created_transform,
77         m_created_transform_compressed);
78 }   // AbstractKartAnimation
79 
80 // ----------------------------------------------------------------------------
~AbstractKartAnimation()81 AbstractKartAnimation::~AbstractKartAnimation()
82 {
83     // If m_end_ticks != int max, this object is deleted because the kart
84     // is deleted (at the end of a race), which means that
85     // world is in the process of being deleted. In this case
86     // we can't call getPhysics() anymore.
87     if (m_end_ticks != std::numeric_limits<int>::max() && m_kart)
88     {
89         Vec3 linear_velocity = m_kart->getBody()->getLinearVelocity();
90         Vec3 angular_velocity = m_kart->getBody()->getAngularVelocity();
91         // Use getTrans so the setXYZ and setRotation from subclass result
92         // can be used here
93         btTransform transform = m_kart->getTrans();
94         m_kart->getBody()->setLinearVelocity(linear_velocity);
95         m_kart->getBody()->setAngularVelocity(angular_velocity);
96         m_kart->getBody()->proceedToTransform(transform);
97         m_kart->setTrans(transform);
98         // Reset all btKart members (bounce back ticks / rotation ticks..)
99         m_kart->getVehicle()->reset();
100         Physics::get()->addKart(m_kart);
101     }
102 }   // ~AbstractKartAnimation
103 
104 // ----------------------------------------------------------------------------
105 /** In CTF mode call this to reset kart powerup when get hit.
106  */
resetPowerUp()107 void AbstractKartAnimation::resetPowerUp()
108 {
109     if (m_kart)
110         m_kart->getPowerup()->reset();
111 }   // resetPowerUp
112 
113 // ----------------------------------------------------------------------------
114 /** Updates the timer, and if it expires, the kart animation will be
115  *  removed from the kart and this object will be deleted.
116  *  NOTE: calling this function must be the last thing done in any kart
117  *  animation class, since this object might be deleted, so accessing any
118  *  members might be invalid.
119  *  \param ticks Number of time steps - should be 1.
120  */
update(int ticks)121 void AbstractKartAnimation::update(int ticks)
122 {
123     // See if the timer expires, if so return the kart to normal game play
124     World* w = World::getWorld();
125     if (!w)
126         return;
127 
128     if (m_end_ticks - w->getTicksSinceStart() == 0)
129     {
130         if (m_kart)
131             m_kart->setKartAnimation(NULL);
132         delete this;
133     }
134 }   // update
135 
136 // ----------------------------------------------------------------------------
updateGraphics(float dt)137 void AbstractKartAnimation::updateGraphics(float dt)
138 {
139     // Reset the wheels (and any other animation played for that kart)
140     // This avoid the effect that some wheels might be way below the kart
141     // which is very obvious in the rescue animation.
142     if (m_kart)
143         m_kart->getKartModel()->resetVisualWheelPosition();
144 }   // updateGraphics
145 
146 // ----------------------------------------------------------------------------
147 /** Returns the current animation timer.
148   */
getAnimationTimer() const149 float AbstractKartAnimation::getAnimationTimer() const
150 {
151     World* w = World::getWorld();
152     if (!w)
153         return 0.0f;
154     return stk_config->ticks2Time(m_end_ticks - w->getTicksSinceStart());
155 }   // getAnimationTimer
156 
157 // ----------------------------------------------------------------------------
158 /** Determine maximum rescue height with up-raycast
159  */
getMaximumHeight(const Vec3 & up_vector,float height_remove)160 float AbstractKartAnimation::getMaximumHeight(const Vec3& up_vector,
161                                               float height_remove)
162 {
163     float hit_dest = 9999999.9f;
164     Vec3 hit;
165     const Material* m = NULL;
166     Vec3 to = up_vector * 10000.0f;
167     const TriangleMesh &tm = Track::getCurrentTrack()->getTriangleMesh();
168     if (tm.castRay(m_created_transform.getOrigin(), to, &hit, &m,
169         NULL/*normal*/, /*interpolate*/true))
170     {
171         hit_dest = (hit - m_created_transform.getOrigin()).length();
172         hit_dest -= height_remove;
173         if (hit_dest < 1.0f)
174         {
175             hit_dest = 1.0f;
176         }
177     }
178     return hit_dest;
179 }   // getMaximumHeight
180 
181 // ----------------------------------------------------------------------------
saveState(BareNetworkString * buffer)182 void AbstractKartAnimation::saveState(BareNetworkString* buffer)
183 {
184     buffer->addUInt32(m_created_ticks);
185     buffer->addInt24(m_created_transform_compressed[0])
186         .addInt24(m_created_transform_compressed[1])
187         .addInt24(m_created_transform_compressed[2])
188         .addUInt32(m_created_transform_compressed[3]);
189 }   // saveState
190 
191 // ----------------------------------------------------------------------------
192 /** Used in constructor of sub-class as no virtual function can be used there.
193  */
restoreBasicState(BareNetworkString * buffer)194 void AbstractKartAnimation::restoreBasicState(BareNetworkString* buffer)
195 {
196     m_created_ticks = buffer->getUInt32();
197     m_created_transform_compressed[0] = buffer->getInt24();
198     m_created_transform_compressed[1] = buffer->getInt24();
199     m_created_transform_compressed[2] = buffer->getInt24();
200     m_created_transform_compressed[3] = buffer->getUInt32();
201     m_created_transform =
202         MiniGLM::decompressbtTransform(m_created_transform_compressed);
203 }   // restoreBasicState
204