1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2012-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 #ifndef HEADER_ABSTRACT_KART_HPP
20 #define HEADER_ABSTRACT_KART_HPP
21 
22 #include <memory>
23 
24 #include "items/powerup_manager.hpp"
25 #include "karts/moveable.hpp"
26 #include "karts/controller/kart_control.hpp"
27 #include "race/race_manager.hpp"
28 
29 namespace irr
30 {
31     namespace scene
32     {
33         class IDummyTransformationSceneNode;
34     }
35 }
36 
37 class AbstractKartAnimation;
38 class Attachment;
39 class btKart;
40 class btQuaternion;
41 class Controller;
42 class Item;
43 class ItemState;
44 class KartGFX;
45 class KartModel;
46 class KartProperties;
47 class Material;
48 class Powerup;
49 class RenderInfo;
50 class SFXBuffer;
51 class Skidding;
52 class SlipStream;
53 class Stars;
54 class TerrainInfo;
55 
56 
57 /** An abstract interface for the actual karts. Some functions are actually
58  *  implemented here in order to allow inlining.
59  * \ingroup karts
60  */
61 class AbstractKart : public Moveable
62 {
63 private:
64     /** Length of the kart, copy of the data from KartModel. */
65     float m_kart_length;
66     /** Width of the kart, copy of the data from KartModel. */
67     float m_kart_width;
68     /** Height of the kart, copy of the data from KartModel. */
69     float m_kart_height;
70     /** Coordinate on up axis */
71     float m_kart_highest_point;
72     /** The position of all four wheels in the 3d model */
73     const Vec3* m_wheel_graphics_position;
74 
75     /** Index of kart in world. */
76     unsigned int m_world_kart_id;
77 
78     /** Name of the kart with translation. */
79     core::stringw m_name;
80 
81     // ------------------------------------------------------------------------
82     void loadKartProperties(const std::string& new_ident,
83                             HandicapLevel handicap,
84                             std::shared_ptr<RenderInfo> ri);
85 protected:
86     btTransform m_starting_transform;
87 
88     int m_live_join_util;
89 
90     /** The kart properties. */
91     std::unique_ptr<KartProperties> m_kart_properties;
92 
93     /** The handicap level of this kart. */
94     HandicapLevel m_handicap;
95 
96     /** This stores a copy of the kart model. It has to be a copy
97      *  since otherwise incosistencies can happen if the same kart
98      *  is used more than once. */
99     std::unique_ptr<KartModel> m_kart_model;
100 
101     /** Handles the attachment the kart might have. */
102     std::unique_ptr<Attachment> m_attachment;
103 
104     /** The kart controls (e.g. steering, fire, ...). */
105     KartControl  m_controls;
106 
107     /** A kart animation object to handle rescue, explosion etc. */
108     AbstractKartAnimation *m_kart_animation;
109 
110     /** Node between wheels and kart. Allows kart to be scaled independent of wheels, when being squashed.*/
111     irr::scene::IDummyTransformationSceneNode    *m_wheel_box;
112 public:
113                    AbstractKart(const std::string& ident,
114                                 int world_kart_id,
115                                 int position, const btTransform& init_transform,
116                                 HandicapLevel handicap,
117                                 std::shared_ptr<RenderInfo> ri);
118     virtual       ~AbstractKart();
119     // ------------------------------------------------------------------------
120     /** Returns a name to be displayed for this kart. */
getName() const121     const core::stringw& getName() const                     { return m_name; }
122     // ------------------------------------------------------------------------
123     virtual void   reset();
124     virtual void   init(RaceManager::KartType type) = 0;
125     // ========================================================================
126     // Functions related to controlling the kart
127     // ------------------------------------------------------------------------
128     /** Returns the current steering value for this kart. */
getSteerPercent() const129     virtual float getSteerPercent() const { return m_controls.getSteer(); }
130     // ------------------------------------------------------------------------
131     /** Returns all controls of this kart. */
getControls()132     KartControl&  getControls() { return m_controls; }
133     // ------------------------------------------------------------------------
134     /** Returns all controls of this kart - const version. */
getControls() const135     const KartControl& getControls() const { return m_controls; }
136 
137     // ========================================================================
138     // Access to the kart properties.
139     // ------------------------------------------------------------------------
140     /** Returns the kart properties of this kart. */
getKartProperties() const141     const KartProperties* getKartProperties() const
142                             { return m_kart_properties.get(); }
143     // ========================================================================
144     /** Change to new kart instancely (used in network live join). */
145     virtual void changeKart(const std::string& new_ident,
146                             HandicapLevel handicap,
147                             std::shared_ptr<RenderInfo> ri);
148     // ========================================================================
149     // Access to the handicap.
150     // ------------------------------------------------------------------------
151     /** Returns the handicap of this kart. */
getHandicap() const152     const HandicapLevel getHandicap() const { return m_handicap; }
153     // ------------------------------------------------------------------------
154     /** Sets the handicap. */
setHandicap(const HandicapLevel h)155     void setHandicap(const HandicapLevel h) { m_handicap=h; }
156 
157     // ------------------------------------------------------------------------
158     /** Returns a unique identifier for this kart (name of the directory the
159      *  kart was loaded from). */
160     virtual const std::string& getIdent() const;
161     // ------------------------------------------------------------------------
162     /** Returns the maximum steering angle for this kart, which depends on the
163      *  speed. */
164     virtual float getMaxSteerAngle () const = 0;
165     // ------------------------------------------------------------------------
166     /** Returns the (maximum) speed for a given turn radius.
167      *  \param radius The radius for which the speed needs to be computed. */
168     virtual float  getSpeedForTurnRadius(float radius) const = 0;
169     // ------------------------------------------------------------------------
170     /** Returns the time till full steering is reached for this kart.
171      *  This can depend on the current steering value, which must be >= 0.
172      */
173     virtual float getTimeFullSteer(float steer) const = 0;
174 
175     // ========================================================================
176     // Attachment related functions.
177     // ------------------------------------------------------------------------
178     /** Returns the current attachment. */
getAttachment() const179     const Attachment* getAttachment() const {return m_attachment.get(); }
180     // ------------------------------------------------------------------------
181     /** Returns the current attachment, non-const version. */
getAttachment()182     Attachment*    getAttachment() {return m_attachment.get(); }
183 
184     // ========================================================================
185     // Access to the graphical kart model.
186     // ------------------------------------------------------------------------
187     /** Returns this kart's kart model. */
getKartModel() const188     KartModel* getKartModel() const { return m_kart_model.get();      }
189     // ------------------------------------------------------------------------
190     /** Returns the length of the kart. */
getKartLength() const191     float getKartLength() const { return m_kart_length; }
192     // ------------------------------------------------------------------------
193     /** Returns the height of the kart. */
getKartHeight() const194     float getKartHeight() const { return m_kart_height; }
195     // ------------------------------------------------------------------------
196     /** Returns the width of the kart. */
getKartWidth() const197     float getKartWidth() const {return m_kart_width; }
198     // ------------------------------------------------------------------------
199     /** Returns the highest point of the kart (coordinate on up axis) */
getHighestPoint() const200     float getHighestPoint() const { return m_kart_highest_point;  }
201     // ------------------------------------------------------------------------
202     /** Called after the kart comes to rest. It can be used to e.g. compute
203      *  differences between graphical and physical chassis. Note that
204      *  overwriting this function is possible, but this implementation must
205      *  be called. */
206     virtual void kartIsInRestNow();
207 
208     // ------------------------------------------------------------------------
209     /** Returns the time at which the kart was at a given distance.
210       * Returns -1.0f if none */
211     virtual float getTimeForDistance(float distance);
212     // ------------------------------------------------------------------------
213     /** Returns true if this kart has no wheels. */
214     bool isWheeless() const;
215     // ------------------------------------------------------------------------
216     /** Returns the coordinates of the front of the kart. This is used for
217      *  determining when the lap line is crossed. */
218     virtual const Vec3& getFrontXYZ() const = 0;
219     // ------------------------------------------------------------------------
220     /** Returns the position of a wheel relative to the kart.
221      *  \param i Index of the wheel: 0=front right, 1 = front left, 2 = rear
222      *           right, 3 = rear left.  */
getWheelGraphicsPosition(int i) const223     const Vec3& getWheelGraphicsPosition(int i) const
224                 {assert(i>=0 && i<4); return m_wheel_graphics_position[i];}
225 
226     // ========================================================================
227     // Emergency animation related functions.
228     // ------------------------------------------------------------------------
229     /** Returns a kart animation (if any), or NULL if currently no kart
230      *  animation is being shown. */
getKartAnimation()231     AbstractKartAnimation *getKartAnimation() { return m_kart_animation; }
232     // ------------------------------------------------------------------------
getKartAnimation() const233     const AbstractKartAnimation *getKartAnimation() const
234                                                    { return m_kart_animation; }
235     // ------------------------------------------------------------------------
236     /** Sets a new kart animation. */
237     virtual void setKartAnimation(AbstractKartAnimation *ka);
238     // ------------------------------------------------------------------------
239 
240     // ------------------------------------------------------------------------
241     // ------------------------------------------------------------------------
242     /** Returns the index of this kart in world. */
getWorldKartId() const243     unsigned int   getWorldKartId() const         { return m_world_kart_id;   }
244     // ------------------------------------------------------------------------
245     /** Saves the old controller in m_saved_controller and stores a new
246      *  controller. The save controller is needed in case of a reset.
247      *  \param controller The new controller to use (atm it's always an
248      *         end controller). */
249     virtual void setController(Controller *controller) = 0;
250     // ------------------------------------------------------------------------
251     /** Returns the controller of this kart. */
252     virtual Controller* getController() = 0;
253     // ------------------------------------------------------------------------
254     /** Returns the controller of this kart (const version). */
255     virtual const Controller* getController() const = 0;
256     // ------------------------------------------------------------------------
257     /** Returns the skidding object for this kart (which can be used to query
258      *  skidding related values). */
259     virtual const Skidding *getSkidding() const = 0;
260     // ------------------------------------------------------------------------
261     virtual RaceManager::KartType getType() const = 0;
262     // ------------------------------------------------------------------------
263     /** Returns the skidding object for this kart (which can be used to query
264      *  skidding related values), non-const. */
265     virtual Skidding *getSkidding() = 0;
266     // ------------------------------------------------------------------------
267     /** Returns true if the kart is eliminated. */
268     virtual bool isEliminated() const = 0;
269     // ------------------------------------------------------------------------
270     /** Marks this kart to be eliminated. */
271     virtual void eliminate() = 0;
272     // ------------------------------------------------------------------------
273     virtual void finishedRace(float time, bool from_server=false) = 0;
274     // ------------------------------------------------------------------------
275     /** Returns the finished time for a kart. */
276     virtual float getFinishTime() const = 0;
277     // ------------------------------------------------------------------------
278     /** Returns true if the kart has a plunger attached to its face. */
279     virtual int getBlockedByPlungerTicks() const = 0;
280     // ------------------------------------------------------------------------
281     /** Sets that the view is blocked by a plunger. The duration depends on
282      *  the difficulty, see KartPorperties getPlungerInFaceTime. */
283     virtual void blockViewWithPlunger() = 0;
284     // ------------------------------------------------------------------------
285     /** Returns if the kart is currently being squashed. */
286     virtual bool isSquashed() const = 0;
287     // ------------------------------------------------------------------------
288     /** Squashes this kart: it will scale the kart in up direction, and causes
289      *  a slowdown while this kart is squashed.
290      *  Returns true if the squash is successful, false otherwise.
291      *  \param time How long the kart will be squashed.
292      *  \param slowdown Reduction of max speed.    */
293     virtual bool setSquash(float time, float slowdown) = 0;
294     // ------------------------------------------------------------------------
295     /** Makes the kart unsquashed again. */
296     virtual void unsetSquash() = 0;
297     // ------------------------------------------------------------------------
298     /** Returns the speed of the kart in meters/second. This is not declared
299      *  pure abstract, since this function is not needed for certain classes,
300      *  like Ghost. */
301     virtual float getSpeed() const = 0;
302     // ------------------------------------------------------------------------
303     /** Returns the current maximum speed for this kart, this includes all
304      *  bonus and maluses that are currently applied. */
305     virtual float getCurrentMaxSpeed() const = 0;
306     // ------------------------------------------------------------------------
307     /** Returns how much increased speed time is left over in the given
308      *  category.
309      *  \param category Which category to report on. */
310     virtual int getSpeedIncreaseTicksLeft(unsigned int category) const = 0;
311 
312     // ------------------------------------------------------------------------
313     /** Sets the kart AI boost state.
314      *  Not pure abstract, since there is no need to implement this e.g. in Ghost.
315      *  \param boosted True if a boost should be applied. */
316     virtual void setBoostAI(bool boosted) = 0;
317 
318     // ------------------------------------------------------------------------
319     /** Returns the kart AI boost state.
320      *  Not pure abstract, since there is no need to implement this e.g. in Ghost. */
321     virtual bool getBoostAI() const = 0;
322 
323     // ------------------------------------------------------------------------
324 
325     /** Sets an increased maximum speed for a category.
326      *  \param category The category for which to set the higher maximum speed.
327      *  \param add_speed How much speed (in m/s) is added to the maximum speed.
328      *  \param engine_force Additional engine force to affect the kart.
329      *  \param duration How long the speed increase will last.
330      *  \param fade_out_time How long the maximum speed will fade out linearly.
331      */
332     virtual void increaseMaxSpeed(unsigned int category, float add_speed,
333                                   float engine_force, int duration,
334                                   int fade_out_time) = 0;
335 
336     // ----------------------------------------------------------------------------
337     /** This adjusts the top speed using increaseMaxSpeed, but additionally
338      *  causes an instant speed boost, which can be smaller than add-max-speed.
339      *  (e.g. a zipper can give an instant boost of 5 m/s, but over time would
340      *  allow the speed to go up by 10 m/s).
341      *  \param category The category for which the speed is increased.
342      *  \param add_max_speed Increase of the maximum allowed speed.
343      *  \param speed_boost An instant speed increase for this kart.
344      *  \param engine_force Additional engine force.
345      *  \param duration Duration of the increased speed.
346      *  \param fade_out_time How long the maximum speed will fade out linearly.
347      */
348     virtual void instantSpeedIncrease(unsigned int category, float add_max_speed,
349                                     float speed_boost, float engine_force,
350                                     int duration, int fade_out_time) = 0;
351 
352     // ------------------------------------------------------------------------
353     /** Defines a slowdown, which is in fraction of top speed.
354      *  \param category The category for which the speed is increased.
355      *  \param max_speed_fraction Fraction of top speed to allow only.
356      *  \param fade_in_time How long till maximum speed is capped. */
357     virtual void setSlowdown(unsigned int category, float max_speed_fraction,
358                              int fade_in_time) = 0;
359     // ------------------------------------------------------------------------
360     /** Returns the remaining collected energy. */
361     virtual float getEnergy() const = 0;
362     // ------------------------------------------------------------------------
363     /** Called when an item is collected. It will either adjust the collected
364      *  energy, or update the attachment or powerup for this kart.
365      *  \param item The item that was hit. */
366     virtual void  collectedItem(ItemState *item_state) = 0;
367     // ------------------------------------------------------------------------
368     /** Returns the current position of this kart in the race. */
369     virtual int getPosition() const = 0;
370     // ------------------------------------------------------------------------
371     /** Returns the current position of this kart in the race. */
372     virtual void setPosition(int p) = 0;
373     // ------------------------------------------------------------------------
374     /** Returns the initial position of this kart. */
375     virtual int getInitialPosition() const = 0;
376     // ------------------------------------------------------------------------
377     /** True if the wheels are touching the ground. */
378     virtual bool isOnGround() const = 0;
379     // ------------------------------------------------------------------------
380     /** Returns the slipstream object of this kart. */
381     virtual const SlipStream* getSlipstream() const = 0;
382     // ------------------------------------------------------------------------
383     /** Returns the slipstream object of this kart. */
384     virtual SlipStream* getSlipstream() = 0;
385     // ------------------------------------------------------------------------
386     /** Activates a slipstream effect, atm that is display some nitro. */
387     virtual void setSlipstreamEffect(float f) = 0;
388     // ------------------------------------------------------------------------
389     /** Plays a beep sfx. */
390     virtual void beep() = 0;
391     // ------------------------------------------------------------------------
392     /** This function will play a particular character voice for this kart.
393      *  It returns whether or not a character voice sample exists for the
394      *  particular event.  If there is no voice sample, a default can be
395      *  played instead. */
396     virtual bool playCustomSFX(unsigned int type) = 0;
397     // ------------------------------------------------------------------------
398     /** Show fire to go with a zipper. */
399     virtual void showZipperFire() = 0;
400     // ------------------------------------------------------------------------
401     /** Sets zipper time, and apply one time additional speed boost. It can be
402      *  used with a specific material, in which case the zipper parmaters are
403      *  taken from this material (parameters that are <0 will be using the
404      *  kart-specific values from kart-properties. */
405     virtual void handleZipper(const Material *m=NULL,
406                               bool play_sound=false) = 0;
407     // ------------------------------------------------------------------------
408     /** Returns true if this kart has finished the race. */
409     virtual bool hasFinishedRace() const = 0;
410     // ------------------------------------------------------------------------
411     virtual void setEnergy(float val) = 0;
412     // ------------------------------------------------------------------------
413     /** Return whether nitro is being used despite the nitro button not being
414      *  pressed due to minimal use time requirements
415      */
416     virtual bool isOnMinNitroTime() const = 0;
417     // ------------------------------------------------------------------------
418     /** Returns the current material the kart is on. */
419     virtual const Material *getMaterial() const = 0;
420     // ------------------------------------------------------------------------
421     /** Returns the previous material the kart was one (which might be
422      *  the same as getMaterial() ). */
423     virtual const Material *getLastMaterial() const = 0;
424     // ------------------------------------------------------------------------
425     /** Returns the current powerup. */
426     virtual const Powerup *getPowerup() const = 0;
427     // ------------------------------------------------------------------------
428     /** Returns the current powerup. */
429     virtual Powerup *getPowerup() = 0;
430     // ------------------------------------------------------------------------
431     /** Returns the last used powerup type. */
432     virtual PowerupManager::PowerupType getLastUsedPowerup() = 0;
433     // ------------------------------------------------------------------------
434     /** Returns the number of powerups. */
435     virtual int getNumPowerup() const = 0;
436     // ------------------------------------------------------------------------
437     /** Returns a points to this kart's graphical effects. */
438     virtual KartGFX* getKartGFX() = 0;
439     // ------------------------------------------------------------------------
440     virtual void setPowerup (PowerupManager::PowerupType t, int n) = 0;
441     // ------------------------------------------------------------------------
442     /** Returns the bullet vehicle which represents this kart. */
443     virtual btKart* getVehicle() const = 0;
444     // ------------------------------------------------------------------------
445     virtual btQuaternion getVisualRotation() const = 0;
446     // ------------------------------------------------------------------------
447     /** Returns true if the kart is 'resting', i.e. (nearly) not moving. */
448     virtual bool isInRest() const = 0;
449     // ------------------------------------------------------------------------
450     /** Starts the engine sound effect. Called once the track intro phase is
451      *  over. */
452     virtual void startEngineSFX() = 0;
453     // ------------------------------------------------------------------------
454     /** Multiplies the velocity of the kart by a factor f (both linear
455      *  and angular). This is used by anvils, which suddenly slow down the kart
456      *  when they are attached. */
457     virtual void adjustSpeed(float f) = 0;
458     // ------------------------------------------------------------------------
459     /** This is used on the client side only to set the speed of the kart
460      *  from the server information.                                       */
461     virtual void setSpeed(float s) = 0;
462     // ------------------------------------------------------------------------
463     /** Returns if the kart is invulnerable. */
464     virtual bool isInvulnerable() const = 0;
465     // ------------------------------------------------------------------------
466     virtual void setInvulnerableTicks(int ticks) = 0;
467     // ------------------------------------------------------------------------
468     /** Returns if the kart is protected by a shield. */
469     virtual bool isShielded() const = 0;
470     // ------------------------------------------------------------------------
471     virtual void setShieldTime(float t) = 0;
472     // ------------------------------------------------------------------------
473     virtual float getShieldTime() const = 0;
474     // ------------------------------------------------------------------------
475     /** Decreases the kart's shield time. */
476     virtual void decreaseShieldTime() = 0;
477     // ------------------------------------------------------------------------
478 
479     /** Shows the star effect for a certain time. */
480     virtual void showStarEffect(float t) = 0;
481     // ------------------------------------------------------------------------
482     /** Returns the terrain info oject. */
483     virtual const TerrainInfo *getTerrainInfo() const = 0;
484     // ------------------------------------------------------------------------
485     /** Called when the kart crashes against another kart.
486      *  \param k The kart that was hit.
487      *  \param update_attachments If true the attachment of this kart and the
488      *          other kart hit will be updated (e.g. bombs will be moved). */
489     virtual void crashed(AbstractKart *k, bool update_attachments) = 0;
490     // ------------------------------------------------------------------------
491     virtual void crashed(const Material *m, const Vec3 &normal) = 0;
492     // ------------------------------------------------------------------------
493     /** Returns the normal of the terrain the kart is over atm. This is
494      *  defined even if the kart is flying. */
495     virtual const Vec3& getNormal() const = 0;
496     // ------------------------------------------------------------------------
497     /** Returns the position 0.25s before */
498     virtual const Vec3& getPreviousXYZ() const = 0;
499     // ------------------------------------------------------------------------
500     /** Returns the most recent different previous position */
501     virtual const Vec3& getRecentPreviousXYZ() const = 0;
502     // ------------------------------------------------------------------------
503     /** Returns the time at which the recent previous position occured */
504     virtual const float getRecentPreviousXYZTime() const = 0;
505     // ------------------------------------------------------------------------
506     /** Returns the height of the terrain. we're currently above */
507     virtual float getHoT() const = 0;
508     // ------------------------------------------------------------------------
509     /** Returns the pitch of the terrain depending on the heading. */
510     virtual float getTerrainPitch(float heading) const = 0;
511     // -------------------------------------------------------------------------
512     /** Returns a bullet transform object located at the kart's position
513         and oriented in the direction the kart is going. Can be useful
514         e.g. to calculate the starting point and direction of projectiles. */
515     virtual btTransform getAlignedTransform(const float customPitch=-1) = 0;
516     // -------------------------------------------------------------------------
517     /** Set a text that is displayed on top of a kart.
518      */
519     virtual void setOnScreenText(const core::stringw& text) = 0;
520     // ------------------------------------------------------------------------
521     /** Returns whether this kart wins or loses. */
522     virtual bool getRaceResult() const = 0;
523     // ------------------------------------------------------------------------
524     /** Returns whether this kart is a ghost (replay) kart. */
525     virtual bool isGhostKart() const = 0;
526     // ------------------------------------------------------------------------
527     /** Returns whether this kart is jumping. */
528     virtual bool isJumping() const = 0;
529     // ------------------------------------------------------------------------
530     virtual void playSound(SFXBuffer* buffer) = 0;
531     // ------------------------------------------------------------------------
532     virtual bool isVisible() const = 0;
533     // ------------------------------------------------------------------------
534     virtual void makeKartRest();
535     // ------------------------------------------------------------------------
536     virtual void setStartupBoost(float val) = 0;
537     // ------------------------------------------------------------------------
538     virtual float getStartupBoost() const = 0;
539     // ------------------------------------------------------------------------
540     virtual float getStartupBoostFromStartTicks(int ticks) const = 0;
541     // ------------------------------------------------------------------------
542     virtual Stars* getStarsEffect() const = 0;
543     // ------------------------------------------------------------------------
getLiveJoinUntilTicks() const544     int getLiveJoinUntilTicks() const              { return m_live_join_util; }
545     // ------------------------------------------------------------------------
setLiveJoinKart(int util_ticks)546     void setLiveJoinKart(int util_ticks)     { m_live_join_util = util_ticks; }
547     // ------------------------------------------------------------------------
548     /** Return the confirmed finish ticks (sent by the server)
549      *  indicating that this kart has really finished the race. */
550     virtual int getNetworkConfirmedFinishTicks() const = 0;
551 };   // AbstractKart
552 
553 
554 #endif
555 
556 /* EOF */
557