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