1 //  SuperTuxKart - a fun racing game with go-kart
2 //
3 //  Copyright (C) 2004-2015 Steve Baker <sjbaker1@airmail.net>
4 //  Copyright (C) 2006-2015 SuperTuxKart-Team
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 3
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 
20 #ifndef HEADER_ITEM_HPP
21 #define HEADER_ITEM_HPP
22 
23 /** \defgroup items
24  *  Defines the various collectibles and weapons of STK.
25  */
26 
27 #include "utils/cpp2011.hpp"
28 #include "utils/leak_check.hpp"
29 #include "utils/log.hpp"
30 #include "utils/no_copy.hpp"
31 #include "utils/vec3.hpp"
32 
33 #include <line3d.h>
34 
35 class BareNetworkString;
36 class AbstractKart;
37 class LODNode;
38 
39 namespace irr
40 {
41     namespace scene { class IMesh; class ISceneNode; }
42 }
43 using namespace irr;
44 
45 // ============================================================================
46 /** \ingroup items
47  *  Contains the state information of an item, i.e. all non-visual information
48  *  only, which also can change (e.g. position and AI information is constant
49  *  and therefore not stored here). This class is used as a base class for
50  *  item and for networking to save item states.
51  */
52 class ItemState
53 {
54     LEAK_CHECK();
55 public:
56     /**
57     * The list of all items. Important for the switch item function:
58     * bubblegum must be the last item (since bubble gum can't be
59     * switched with any other item, since it's a different objecct).
60     */
61     enum ItemType
62     {
63         ITEM_FIRST,
64         ITEM_BONUS_BOX = ITEM_FIRST,
65         ITEM_BANANA,
66         ITEM_NITRO_BIG,
67         ITEM_NITRO_SMALL,
68         ITEM_BUBBLEGUM,
69         ITEM_BUBBLEGUM_NOLOK,
70 
71         /** For easter egg mode only. */
72         ITEM_EASTER_EGG,
73         ITEM_LAST = ITEM_EASTER_EGG,
74         ITEM_COUNT,
75         ITEM_NONE
76     };
77 
78 private:
79     /** Item type. */
80     ItemType m_type;
81 
82     /** If the item is switched, this contains the original type.
83     *  It is ITEM_NONE if the item is not switched. */
84     ItemType m_original_type;
85 
86     /** Time till a collected item reappears. When this value is <=0 this
87      *  means that the item is availabe to be collected. When the value is
88      *  > 0 it means that the item is not available. */
89     int m_ticks_till_return;
90 
91     /** Index in item_manager field. This field can also take on a negative
92      *  value when used in the NetworkItemManager. */
93     int  m_item_id;
94 
95     /** Optionally if item was placed by a kart, a timer can be used to
96     *  temporarly deactivate collision so a kart is not hit by its own item */
97     int m_deactive_ticks;
98 
99     /** Counts how often an item is used before it disappears. Used for
100      *  bubble gum to make them disappear after a while. A value >0
101      *  indicates that the item still exists, =0 that the item can be
102      *  deleted, and <0 that the item will never be deleted, i.e. it
103      *  will always reappear after a while. */
104     int m_used_up_counter;
105 
106     /** The position of this ItemState. */
107     Vec3 m_xyz;
108 
109     /** The original rotation of the item. While this is technically a visual
110      *  only value (atm, it could be used for collision detection), it is
111      *  required to make sure a client can display items with the right normal
112      *  (in case that a client would get a different (or no) normal from a
113      *  raycast).
114      */
115     btQuaternion m_original_rotation;
116 
117     /** The 'owner' of the item, i.e. the kart that dropped this item.
118     *  Is NULL if the item is part of the track. */
119     const AbstractKart *m_previous_owner;
120 
121 protected:
122 
123     friend class ItemManager;
124     friend class NetworkItemManager;
125     // ------------------------------------------------------------------------
setType(ItemType type)126     virtual void setType(ItemType type) { m_type = type; }
127     // ------------------------------------------------------------------------
128     // Some convenient functions for the AI only
129     friend class SkiddingAI;
130     friend class TestAI;
131     /** Returns true if the specified line segment would come close enough
132      *  to this item so that this item would be collected.
133      *  \param line The line segment which is tested if it is close enough
134      *         to this item so that this item would be collected.
135      */
hitLine(const core::line3df & line,const AbstractKart * kart=NULL) const136     bool hitLine(const core::line3df &line,
137                  const AbstractKart *kart = NULL) const
138     {
139         if (getPreviousOwner() == kart && getDeactivatedTicks() > 0)
140             return false;
141 
142         Vec3 closest = line.getClosestPoint(getXYZ().toIrrVector());
143         return hitKart(closest, kart);
144     }   // hitLine
145 
146 public:
147     // ------------------------------------------------------------------------
148          ItemState(ItemType type, const AbstractKart *owner=NULL, int id = -1);
149     // ------------------------------------------------------------------------
150          ItemState(const BareNetworkString& buffer);
151     // ------------------------------------------------------------------------
152     void initItem(ItemType type, const Vec3& xyz, const Vec3& normal);
153     void update(int ticks);
154     void setDisappearCounter();
155     virtual void collected(const AbstractKart *kart);
156     // ------------------------------------------------------------------------
~ItemState()157     virtual ~ItemState() {}
158 
159     // -----------------------------------------------------------------------
160     /** Dummy implementation, causing an abort if it should be called to
161      *  catch any errors early. */
updateGraphics(float dt)162     virtual void updateGraphics(float dt)
163     {
164         Log::fatal("ItemState", "updateGraphics() called for ItemState.");
165     }   // updateGraphics
166 
167     // -----------------------------------------------------------------------
hitKart(const Vec3 & xyz,const AbstractKart * kart=NULL) const168     virtual bool hitKart(const Vec3 &xyz,
169                          const AbstractKart *kart = NULL) const
170     {
171         Log::fatal("ItemState", "hitKart() called for ItemState.");
172         return false;
173     }   // hitKart
174 
175     // -----------------------------------------------------------------------
getGraphNode() const176     virtual int getGraphNode() const
177     {
178         Log::fatal("ItemState", "getGraphNode() called for ItemState.");
179         return 0;
180     }   // getGraphNode
181 
182     // -----------------------------------------------------------------------
getAvoidancePoint(bool left) const183     virtual const Vec3 *getAvoidancePoint(bool left) const
184     {
185         Log::fatal("ItemState", "getAvoidancePoint() called for ItemState.");
186         // Return doesn't matter, fatal aborts
187         return &m_xyz;
188     }   // getAvoidancePoint
189 
190     // -----------------------------------------------------------------------
getDistanceFromCenter() const191     virtual float getDistanceFromCenter() const
192     {
193         Log::fatal("itemState",
194                    "getDistanceFromCentre() called for ItemState.");
195         return 0;
196     }   // getDistanceFromCentre
197 
198     // -----------------------------------------------------------------------
199     /** Resets an item to its start state. */
reset()200     virtual void reset()
201     {
202         m_deactive_ticks    = 0;
203         m_ticks_till_return = 0;
204         setDisappearCounter();
205         // If the item was switched:
206         if (m_original_type != ITEM_NONE)
207         {
208             setType(m_original_type);
209             m_original_type = ITEM_NONE;
210         }
211     }   // reset
212 
213     // -----------------------------------------------------------------------
214     /** Switches an item to be of a different type. Used for the switch
215      *  powerup.
216      *  \param type New type for this item.
217      */
switchTo(ItemType type)218     virtual void switchTo(ItemType type)
219     {
220         // triggers and easter eggs should not be switched
221         if (m_type == ITEM_EASTER_EGG) return;
222         m_original_type = m_type;
223         setType(type);
224         return;
225     }   // switchTo
226 
227     // ------------------------------------------------------------------------
228     /** Returns true if this item was not actually switched (e.g. trigger etc)
229      */
switchBack()230     virtual bool switchBack()
231     {
232         // If the item is not switched, do nothing. This can happen if a bubble
233         // gum is dropped while items are switched - when switching back, this
234         // bubble gum has no original type.
235         if (m_original_type == ITEM_NONE)
236             return true;
237         setType(m_original_type);
238         m_original_type = ITEM_NONE;
239         return false;
240     }   // switchBack
241 
242     // ------------------------------------------------------------------------
243     /** Returns if this item is negative, i.e. a banana or bubblegum. */
isNegativeItem() const244     bool isNegativeItem() const
245     {
246         return m_type == ITEM_BANANA || m_type == ITEM_BUBBLEGUM ||
247                m_type == ITEM_BUBBLEGUM_NOLOK;
248     }
249     // ------------------------------------------------------------------------
250     /** Sets how long an item should be disabled. While item itself sets
251      *  a default, this time is too short in case that a kart that has a bomb
252      *  hits a banana: by the time the explosion animation is ended and the
253      *  kart is back at its original position, the banana would be back again
254      *  and therefore hit the kart again. See Attachment::hitBanana for more
255      *  details.
256      *  \param f Time till the item can be used again.
257      */
setTicksTillReturn(int t)258     void setTicksTillReturn(int t) { m_ticks_till_return = t; }
259     // ------------------------------------------------------------------------
260     /** Returns the time the item is disabled for. */
getTicksTillReturn() const261     int getTicksTillReturn() const { return m_ticks_till_return; }
262     // ------------------------------------------------------------------------
263     /** Returns true if this item is currently collected. */
isAvailable() const264     bool isAvailable() const { return m_ticks_till_return <= 0; }
265     // ------------------------------------------------------------------------
266     /** Returns the type of this item. */
getType() const267     ItemType getType() const { return m_type; }
268     // ------------------------------------------------------------------------
269     ItemType getGrahpicalType() const;
270     // ------------------------------------------------------------------------
271     /** Returns the original type of this item. */
getOriginalType() const272     ItemType getOriginalType() const { return m_original_type; }
273     // ------------------------------------------------------------------------
274     /** Sets the index of this item in the item manager list. */
setItemId(unsigned int n)275     void setItemId(unsigned int n) { m_item_id = n; }
276     // ------------------------------------------------------------------------
277     /** Returns the index of this item in the item manager list. */
getItemId() const278     unsigned int getItemId() const { return m_item_id; }
279     // ------------------------------------------------------------------------
280     /** Returns true if this item is used up and can be removed. */
isUsedUp() const281     bool isUsedUp() const { return m_used_up_counter == 0; }
282     // ------------------------------------------------------------------------
283     /** Returns true if this item can be used up, and therefore needs to
284      *  be removed when the game is reset. */
canBeUsedUp() const285     bool canBeUsedUp()  const { return m_used_up_counter>-1; }
286     // ------------------------------------------------------------------------
287     /** Returns the number of ticks during which the item is deactivated (i.e.
288      *  it was collected). */
getDeactivatedTicks() const289     int getDeactivatedTicks() const { return m_deactive_ticks; }
290     // ------------------------------------------------------------------------
291     /** Sets the number of ticks during which the item is deactivated (i.e.
292      *  it was collected). */
setDeactivatedTicks(int ticks)293     void setDeactivatedTicks(int ticks) { m_deactive_ticks = ticks; }
294     // ------------------------------------------------------------------------
295     /** Returns the kart that dropped this item (or NULL if the item was not
296      *  dropped by a kart. */
getPreviousOwner() const297     const AbstractKart *getPreviousOwner() const { return m_previous_owner; }
298     // ------------------------------------------------------------------------
setXYZ(const Vec3 & xyz)299     void setXYZ(const Vec3& xyz) { m_xyz = xyz; }
300     // ------------------------------------------------------------------------
301     /** Returns the XYZ position of the item. */
getXYZ() const302     const Vec3& getXYZ() const { return m_xyz; }
303     // ------------------------------------------------------------------------
304     /** Returns the normal of the ItemState. */
getNormal() const305     const Vec3 getNormal() const
306     {
307         return quatRotate(m_original_rotation, Vec3(0.0f, 1.0f, 0.0f));
308     }
309     // ------------------------------------------------------------------------
310     /** Returns the original rotation of the item. */
getOriginalRotation() const311     const btQuaternion& getOriginalRotation() const
312     {
313         return m_original_rotation;
314     }
315     // ------------------------------------------------------------------------
316     void saveCompleteState(BareNetworkString* buffer) const;
317 };   // class ItemState
318 
319 // ============================================================================
320 /**
321   * \ingroup items
322   */
323 class Item : public ItemState, public NoCopy
324 {
325 
326 private:
327     /** Scene node of this item. */
328     LODNode *m_node;
329 
330     /** Graphical type of the mesh. */
331     ItemType m_graphical_type;
332 
333     /** Stores if the item was available in the previously rendered frame. */
334     bool m_was_available_previously;
335 
336     /** square distance at which item is collected */
337     float m_distance_2;
338 
339     /** The graph node this item is on. */
340     int m_graph_node;
341 
342     /** Distance from the center of the quad this item is in. This value is
343      *  >0 if it is to the right of the center, and undefined if this quad
344      *  is not on any quad. */
345     float m_distance_from_center;
346 
347     /** The closest point to the left and right of this item at which it
348      *  would not be collected. Used by the AI to avoid items. */
349     Vec3 *m_avoidance_points[2];
350 
351     void          initItem(ItemType type, const Vec3 &xyz, const Vec3 &normal);
352     void          setMesh(scene::IMesh* mesh, scene::IMesh* lowres_mesh);
353     void          handleNewMesh(ItemType type);
354 
355 public:
356                   Item(ItemType type, const Vec3& xyz, const Vec3& normal,
357                        scene::IMesh* mesh, scene::IMesh* lowres_mesh,
358                        const AbstractKart *owner);
359     virtual       ~Item ();
360     virtual void  updateGraphics(float dt) OVERRIDE;
361     virtual void  reset() OVERRIDE;
362 
363     //-------------------------------------------------------------------------
364     /** Is called when the item is hit by a kart.  It sets the flag that the
365      *  item has been collected, and the time to return to the parameter.
366      *  \param kart The kart that collected the item.
367      */
collected(const AbstractKart * kart)368     virtual void collected(const AbstractKart *kart)  OVERRIDE
369     {
370         ItemState::collected(kart);
371     }   // isCollected
372     //-------------------------------------------------------------------------
373     /** Switch backs to the original item. Returns true if the item was not
374      *  actually switched (e.g. trigger, or bubblegum dropped during switch
375      *  time). The return value is not actually used, but necessary in order
376      *  to overwrite ItemState::switchBack()
377      */
switchBack()378     virtual bool switchBack() OVERRIDE
379     {
380         if (ItemState::switchBack())
381             return true;
382         return false;
383     }   // switchBack
384     // ------------------------------------------------------------------------
385     /** Returns true if the Kart is close enough to hit this item, the item is
386      *  not deactivated anymore, and it wasn't placed by this kart (this is
387      *  e.g. used to avoid that a kart hits a bubble gum it just dropped).
388      *  \param kart Kart to test.
389      *  \param xyz Location of kart (avoiding to use kart->getXYZ() so that
390      *         kart.hpp does not need to be included here).
391      */
hitKart(const Vec3 & xyz,const AbstractKart * kart=NULL) const392     virtual bool hitKart(const Vec3 &xyz, const AbstractKart *kart=NULL) const
393         OVERRIDE
394     {
395         if (getPreviousOwner() == kart && getDeactivatedTicks() > 0)
396             return false;
397         Vec3 lc = quatRotate(getOriginalRotation(), xyz - getXYZ());
398         // Don't be too strict if the kart is a bit above the item
399         lc.setY(lc.getY() / 2.0f);
400         return lc.length2() < m_distance_2;
401     }   // hitKart
402     // ------------------------------------------------------------------------
rotating() const403     bool rotating() const               { return getType() != ITEM_BUBBLEGUM; }
404 
405 public:
406     // ------------------------------------------------------------------------
407     /** Returns the index of the graph node this item is on. */
getGraphNode() const408     virtual int getGraphNode() const OVERRIDE { return m_graph_node; }
409     // ------------------------------------------------------------------------
410     /** Returns the distance from center: negative means left of center,
411      *  positive means right of center. */
getDistanceFromCenter() const412     virtual float getDistanceFromCenter() const OVERRIDE
413     {
414         return m_distance_from_center;
415     }   // getDistanceFromCenter
416     // ------------------------------------------------------------------------
417     /** Returns a point to the left or right of the item which will not trigger
418      *  a collection of this item.
419      *  \param left If true, return a point to the left, else a point to
420      *         the right. */
getAvoidancePoint(bool left) const421     virtual const Vec3 *getAvoidancePoint(bool left) const OVERRIDE
422     {
423         if(left) return m_avoidance_points[0];
424         return m_avoidance_points[1];
425     }   // getAvoidancePoint
426     // ------------------------------------------------------------------------
getSceneNode()427     scene::ISceneNode *getSceneNode()
428     {
429         return (scene::ISceneNode *) m_node;
430     }
431 };   // class Item
432 
433 #endif
434