diff --git a/src/items/item.cpp b/src/items/item.cpp index c0b375d53..4063c665e 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -287,18 +287,21 @@ void Item::setType(ItemType type) void Item::switchTo(ItemType type, scene::IMesh *mesh, scene::IMesh *lowmesh) { setMesh(mesh, lowmesh); - ItemState::switchTo(type); + ItemState::switchTo(type, mesh, lowmesh); } // switchTo //----------------------------------------------------------------------------- -/** Switch backs to the original item. +/** Switch backs to the original item. Returns true if the item wa snot + * actually switched (e.g. trigger, or bubblegum dropped during switch + * time). The return value is not actually used, but necessary in order + * to overwrite ItemState::switchBack() */ -void Item::switchBack() +bool Item::switchBack() { setMesh(m_original_mesh, m_original_lowmesh); if (ItemState::switchBack()) - return; + return true; if (m_node != NULL) { @@ -306,6 +309,7 @@ void Item::switchBack() hpr.setHPR(m_original_rotation); m_node->setRotation(hpr.toIrrHPR()); } + return false; } // switchBack //----------------------------------------------------------------------------- diff --git a/src/items/item.hpp b/src/items/item.hpp index 9e7bb20a8..7aca6887d 100644 --- a/src/items/item.hpp +++ b/src/items/item.hpp @@ -132,6 +132,24 @@ protected: friend class NetworkItemManager; // ------------------------------------------------------------------------ virtual void setType(ItemType type) { m_type = type; } + // ------------------------------------------------------------------------ + // Some convenient functions for the AI only + friend class SkiddingAI; + friend class TestAI; + /** Returns true if the specified line segment would come close enough + * to this item so that this item would be collected. + * \param line The line segment which is tested if it is close enough + * to this item so that this item would be collected. + */ + bool hitLine(const core::line3df &line, + const AbstractKart *kart = NULL) const + { + if (getPreviousOwner() == kart && getDeactivatedTicks() > 0) + return false; + + Vec3 closest = line.getClosestPoint(getXYZ().toIrrVector()); + return hitKart(closest, kart); + } // hitLine public: ItemState(ItemType type, const AbstractKart *owner=NULL, int id = -1); @@ -143,6 +161,48 @@ public: virtual ~ItemState() {} // ----------------------------------------------------------------------- + /** Dummy implementation, causing an abort if it should be called to + * catch any errors early. */ + virtual void updateGraphics(float dt) + { + Log::fatal("ItemState", "updateGraphics() called for ItemState."); + } // updateGraphics + + // ----------------------------------------------------------------------- + virtual bool hitKart(const Vec3 &xyz, + const AbstractKart *kart = NULL) const + { + Log::fatal("ItemState", "hitKart() called for ItemState."); + return false; + } // hitKart + // ----------------------------------------------------------------------- + virtual bool isPredicted() const + { + Log::fatal("ItemState", "isPredicted() called for ItemState."); + return false; + } // isPredicted + // ----------------------------------------------------------------------- + virtual int getGraphNode() const + { + Log::fatal("ItemState", "getGraphNode() called for ItemState."); + return 0; + } // getGraphNode + // ----------------------------------------------------------------------- + const Vec3 *getAvoidancePoint(bool left) const + { + Log::fatal("ItemState", "getAvoidancePoint() called for ItemState."); + // Return doesn't matter, fatal aborts + return &m_xyz; + } // getAvoidancePoint + // ----------------------------------------------------------------------- + float getDistanceFromCenter() const + { + Log::fatal("itemState", + "getDistanceFromCentre() called for ItemState."); + return 0; + } // getDistanceFromCentre + // ----------------------------------------------------------------------- + /** Resets an item to its start state. */ void reset() { m_deactive_ticks = 0; @@ -156,22 +216,27 @@ public: } } // reset - // ------------------------------------------------------------------------ + // ----------------------------------------------------------------------- /** Switches an item to be of a different type. Used for the switch * powerup. * \param type New type for this item. + * \param mesh Ignored. + * \param lowmesh Ignored. */ - void switchTo(ItemType type) + virtual void switchTo(ItemType type, scene::IMesh *mesh, + scene::IMesh *lowmesh) { // triggers and easter eggs should not be switched if (m_type == ITEM_TRIGGER || m_type == ITEM_EASTER_EGG) return; m_original_type = m_type; setType(type); + return; } // switchTo + // ------------------------------------------------------------------------ /** Returns true if this item was not actually switched (e.g. trigger etc) */ - bool switchBack() + virtual bool switchBack() { // triggers should not be switched if (m_type == ITEM_TRIGGER) return true; @@ -311,12 +376,12 @@ public: Item(const Vec3& xyz, float distance, TriggerItemListener* trigger); virtual ~Item (); - void updateGraphics(float dt); + virtual void updateGraphics(float dt) OVERRIDE; virtual void collected(const AbstractKart *kart) OVERRIDE; void reset(); void switchTo(ItemType type, scene::IMesh *mesh, scene::IMesh *lowmesh); - void switchBack(); + virtual bool switchBack() OVERRIDE; // ------------------------------------------------------------------------ /** Returns true if the Kart is close enough to hit this item, the item is @@ -326,7 +391,7 @@ public: * \param xyz Location of kart (avoiding to use kart->getXYZ() so that * kart.hpp does not need to be included here). */ - bool hitKart(const Vec3 &xyz, const AbstractKart *kart=NULL) const + virtual bool hitKart(const Vec3 &xyz, const AbstractKart *kart=NULL) const { if (getPreviousOwner() == kart && getDeactivatedTicks() > 0) return false; @@ -336,35 +401,16 @@ public: return lc.length2() < m_distance_2; } // hitKart -protected: - // ------------------------------------------------------------------------ - // Some convenient functions for the AI only - friend class SkiddingAI; - friend class TestAI; - /** Returns true if the specified line segment would come close enough - * to this item so that this item would be collected. - * \param line The line segment which is tested if it is close enough - * to this item so that this item would be collected. - */ - bool hitLine(const core::line3df &line, - const AbstractKart *kart=NULL) const - { - if (getPreviousOwner() == kart && getDeactivatedTicks() > 0) - return false; - - Vec3 closest = line.getClosestPoint(getXYZ().toIrrVector()); - return hitKart(closest, kart); - } // hitLine public: // ------------------------------------------------------------------------ /** Sets if this is a predicted item or not. */ void setPredicted(bool p) { m_is_predicted = p; } // ------------------------------------------------------------------------ /** Returns if this item is predicted or not. */ - bool isPredicted() const { return m_is_predicted; } + virtual bool isPredicted() const OVERRIDE { return m_is_predicted; } // ------------------------------------------------------------------------ /** Returns the index of the graph node this item is on. */ - int getGraphNode() const { return m_graph_node; } + virtual int getGraphNode() const OVERRIDE { return m_graph_node; } // ------------------------------------------------------------------------ /** Returns the distance from center: negative means left of center, * positive means right of center. */ diff --git a/src/items/item_manager.cpp b/src/items/item_manager.cpp index cec02434f..157668fcd 100644 --- a/src/items/item_manager.cpp +++ b/src/items/item_manager.cpp @@ -460,8 +460,8 @@ void ItemManager::update(int ticks) m_switch_ticks -= ticks; if(m_switch_ticks<0) { - for(AllItemTypes::iterator i =m_all_items.begin(); - i!=m_all_items.end(); i++) + for(AllItemTypes::iterator i = m_all_items.begin(); + i!= m_all_items.end(); i++) { if(*i) (*i)->switchBack(); } // for m_all_items @@ -501,7 +501,7 @@ void ItemManager::updateGraphics(float dt) * items, and then frees the item itself. * \param The item to delete. */ -void ItemManager::deleteItem(Item *item) +void ItemManager::deleteItem(ItemState *item) { // First check if the item needs to be removed from the items-in-quad list if(m_items_in_quads) @@ -523,12 +523,21 @@ void ItemManager::deleteItem(Item *item) //----------------------------------------------------------------------------- /** Switches all items: boxes become bananas and vice versa for a certain - * amount of time (as defined in stk_config.xml. + * amount of time (as defined in stk_config.xml). */ void ItemManager::switchItems() { - for(AllItemTypes::iterator i =m_all_items.begin(); - i!=m_all_items.end(); i++) + switchItemsInternal(m_all_items); +} // switchItems + +//----------------------------------------------------------------------------- +/** Switches all items: boxes become bananas and vice versa for a certain + * amount of time (as defined in stk_config.xml). + */ +void ItemManager::switchItemsInternal(std::vector &all_items) +{ + for(AllItemTypes::iterator i = m_all_items.begin(); + i != m_all_items.end(); i++) { if(!*i) continue; @@ -546,7 +555,8 @@ void ItemManager::switchItems() if (new_type == (*i)->getType()) continue; if(m_switch_ticks<0) - (*i)->switchTo(new_type, m_item_mesh[(int)new_type], m_item_lowres_mesh[(int)new_type]); + (*i)->switchTo(new_type, m_item_mesh[(int)new_type], + m_item_lowres_mesh[(int)new_type]); else (*i)->switchBack(); } // for m_all_items diff --git a/src/items/item_manager.hpp b/src/items/item_manager.hpp index 26614eebf..115d2f3de 100644 --- a/src/items/item_manager.hpp +++ b/src/items/item_manager.hpp @@ -99,7 +99,7 @@ public: // ======================================================================== protected: /** The vector of all items of the current track. */ - typedef std::vector AllItemTypes; + typedef std::vector AllItemTypes; AllItemTypes m_all_items; private: @@ -111,14 +111,16 @@ private: /** What item this item is switched to. */ std::vector m_switch_to; +protected: /** Remaining time that items should remain switched. If the * value is <0, it indicates that the items are not switched atm. */ int m_switch_ticks; -protected: - void deleteItem(Item *item); + void deleteItem(ItemState *item); virtual unsigned int insertItem(Item *item); + void switchItemsInternal(std::vector < ItemState*> &all_items); void setSwitchItems(const std::vector &switch_items); + ItemManager(); public: virtual ~ItemManager(); @@ -134,7 +136,7 @@ public: void checkItemHit (AbstractKart* kart); void reset (); virtual void collectedItem (ItemState *item, AbstractKart *kart); - void switchItems (); + virtual void switchItems (); bool randomItemsForArena(const AlignedArray& pos); // ------------------------------------------------------------------------ /** Only used in the NetworkItemManager. */ @@ -151,10 +153,16 @@ public: } // ------------------------------------------------------------------------ /** Returns a pointer to the n-th item. */ - const Item* getItem(unsigned int n) const { return m_all_items[n]; }; + const ItemState* getItem(unsigned int n) const + { + return dynamic_cast(m_all_items[n]); + }; // ------------------------------------------------------------------------ /** Returns a pointer to the n-th item. */ - Item* getItem(unsigned int n) { return m_all_items[n]; }; + ItemState* getItem(unsigned int n) + { + return dynamic_cast(m_all_items[n]); + } // ------------------------------------------------------------------------ /** Returns a reference to the array of all items on the specified quad. */ @@ -171,8 +179,9 @@ public: { assert(m_items_in_quads); assert(n < m_items_in_quads->size()); - return ((*m_items_in_quads)[n]).empty() ? NULL : - (*m_items_in_quads)[n].front(); + return ((*m_items_in_quads)[n]).empty() + ? NULL + : dynamic_cast((*m_items_in_quads)[n].front()); } // getFirstItemInQuad }; // ItemManager diff --git a/src/karts/controller/skidding_ai.cpp b/src/karts/controller/skidding_ai.cpp index 26bb42670..5a1c97407 100644 --- a/src/karts/controller/skidding_ai.cpp +++ b/src/karts/controller/skidding_ai.cpp @@ -553,8 +553,8 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, int node = m_track_node; float distance = 0; - std::vector items_to_collect; - std::vector items_to_avoid; + std::vector items_to_collect; + std::vector items_to_avoid; // 1) Filter and sort all items close by // ------------------------------------- @@ -562,8 +562,8 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, while(distance < max_item_lookahead_distance) { int n_index= DriveGraph::get()->getNode(node)->getIndex(); - const std::vector &items_ahead = - ItemManager::get()->getItemsInQuads(n_index); + const std::vector &items_ahead = + ItemManager::get()->getItemsInQuads(n_index); for(unsigned int i=0; i0) { - const Item *item_to_collect = items_to_collect[0]; + const ItemState *item_to_collect = items_to_collect[0]; // Test if we would hit a bad item when aiming at this good item. // If so, don't change the aim. In this case it has already been // ensured that we won't hit the bad item (otherwise steerToAvoid @@ -745,8 +745,8 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, * to be avoided. * \return True if it would hit any of the bad items. */ -bool SkiddingAI::hitBadItemWhenAimAt(const Item *item, - const std::vector &items_to_avoid) +bool SkiddingAI::hitBadItemWhenAimAt(const ItemState *item, + const std::vector &items_to_avoid) { core::line3df to_item(m_kart->getXYZ().toIrrVector(), item->getXYZ().toIrrVector()); @@ -805,7 +805,7 @@ bool SkiddingAI::handleSelectedItem(Vec3 kart_aim_direction, Vec3 *aim_point) * into account). * \return True if steering is necessary to avoid an item. */ -bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, +bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, const core::line3df &line_to_target, Vec3 *aim_point) { @@ -958,9 +958,9 @@ bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, * (NULL if no item was avoided so far). * \param item_to_collect A pointer to a previously selected item to collect. */ -void SkiddingAI::evaluateItems(const Item *item, Vec3 kart_aim_direction, - std::vector *items_to_avoid, - std::vector *items_to_collect) +void SkiddingAI::evaluateItems(const ItemState *item, Vec3 kart_aim_direction, + std::vector *items_to_avoid, + std::vector *items_to_collect) { const KartProperties *kp = m_kart->getKartProperties(); @@ -1032,7 +1032,7 @@ void SkiddingAI::evaluateItems(const Item *item, Vec3 kart_aim_direction, // Now insert the item into the sorted list of items to avoid // (or to collect). The lists are (for now) sorted by distance - std::vector *list; + std::vector *list; if(avoid) list = items_to_avoid; else @@ -1146,8 +1146,8 @@ void SkiddingAI::handleItems(const float dt, const Vec3 *aim_point, int last_nod int node = m_track_node; float distance = 0; - std::vector items_to_collect; - std::vector items_to_avoid; + std::vector items_to_collect; + std::vector items_to_avoid; // 1) Filter and sort all items close by // ------------------------------------- @@ -1155,7 +1155,7 @@ void SkiddingAI::handleItems(const float dt, const Vec3 *aim_point, int last_nod while(distance < max_item_lookahead_distance) { int n_index= DriveGraph::get()->getNode(node)->getIndex(); - const std::vector &items_ahead = + const std::vector &items_ahead = ItemManager::get()->getItemsInQuads(n_index); for(unsigned int i=0; i &items_to_collect, - const std::vector &items_to_avoid) +void SkiddingAI::handleBubblegum(int item_skill, + const std::vector &items_to_collect, + const std::vector &items_to_avoid) { float shield_radius = m_ai_properties->m_shield_incoming_radius; @@ -1722,8 +1723,9 @@ void SkiddingAI::handleSwatter(int item_skill) * \param items_to_collect The list of close good items * \param items_to_avoid The list of close bad items */ -void SkiddingAI::handleSwitch(int item_skill, const std::vector &items_to_collect, - const std::vector &items_to_avoid) +void SkiddingAI::handleSwitch(int item_skill, + const std::vector &items_to_collect, + const std::vector &items_to_avoid) { // It's extremely unlikely two switches are used close one after another if(item_skill == 2) @@ -2212,7 +2214,7 @@ void SkiddingAI::handleNitroAndZipper(float max_safe_speed) // just keep enough to help accelerating after an accident if(race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER) { - energy_reserve = std::min(2, energy_reserve); + energy_reserve = std::min(2.0f, energy_reserve); } // Don't use nitro or zipper if we are braking diff --git a/src/karts/controller/skidding_ai.hpp b/src/karts/controller/skidding_ai.hpp index 8895d9240..8718df32e 100644 --- a/src/karts/controller/skidding_ai.hpp +++ b/src/karts/controller/skidding_ai.hpp @@ -50,7 +50,7 @@ #include -class Item; +class ItemState; class LinearWorld; class Track; @@ -178,7 +178,7 @@ private: unsigned int m_last_direction_node; /** If set an item that the AI should aim for. */ - const Item *m_item_to_collect; + const ItemState *m_item_to_collect; /** True if items to avoid are close by. Used to avoid using zippers * (which would make it more difficult to avoid items). */ @@ -209,7 +209,7 @@ private: /** The last item selected for collection, for which a probability * was determined. */ - const Item *m_last_item_random; + const ItemState *m_last_item_random; /** True if m_last_item_random was randomly selected to be collected. */ bool m_really_collect_item; @@ -256,13 +256,15 @@ private: int computeSkill(SkillType type); void handleItems(const float dt, const Vec3 *aim_point, int last_node, int item_skill); - void handleBubblegum(int item_skill, const std::vector &items_to_collect, - const std::vector &items_to_avoid); + void handleBubblegum(int item_skill, + const std::vector &items_to_collect, + const std::vector &items_to_avoid); void handleCake(int item_skill); void handleBowling(int item_skill); void handleSwatter(int item_skill); - void handleSwitch(int item_skill, const std::vector &items_to_collect, - const std::vector &items_to_avoid); + void handleSwitch(int item_skill, + const std::vector &items_to_collect, + const std::vector &items_to_avoid); void handleRescue(const float dt); void handleBraking(float max_turn_speed, float min_speed); void handleNitroAndZipper(float max_safe_speed); @@ -270,14 +272,14 @@ private: void handleItemCollectionAndAvoidance(Vec3 *aim_point, int last_node); bool handleSelectedItem(Vec3 kart_aim_direction, Vec3 *aim_point); - bool steerToAvoid(const std::vector &items_to_avoid, + bool steerToAvoid(const std::vector &items_to_avoid, const core::line3df &line_to_target, Vec3 *aim_point); - bool hitBadItemWhenAimAt(const Item *item, - const std::vector &items_to_avoid); - void evaluateItems(const Item *item, Vec3 kart_aim_direction, - std::vector *items_to_avoid, - std::vector *items_to_collect); + bool hitBadItemWhenAimAt(const ItemState *item, + const std::vector &items_to_avoid); + void evaluateItems(const ItemState *item, Vec3 kart_aim_direction, + std::vector *items_to_avoid, + std::vector *items_to_collect); void checkCrashes(const Vec3& pos); void findNonCrashingPointNew(Vec3 *result, int *last_node); diff --git a/src/karts/controller/test_ai.cpp b/src/karts/controller/test_ai.cpp index f90ef8086..445393e14 100644 --- a/src/karts/controller/test_ai.cpp +++ b/src/karts/controller/test_ai.cpp @@ -631,8 +631,8 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, int node = m_track_node; float distance = 0; - std::vector items_to_collect; - std::vector items_to_avoid; + std::vector items_to_collect; + std::vector items_to_avoid; // 1) Filter and sort all items close by // ------------------------------------- @@ -640,7 +640,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, while(distance < max_item_lookahead_distance) { int n_index= DriveGraph::get()->getNode(node)->getIndex(); - const std::vector &items_ahead = + const std::vector &items_ahead = ItemManager::get()->getItemsInQuads(n_index); for(unsigned int i=0; i0) { - const Item *item_to_collect = items_to_collect[0]; + const ItemState *item_to_collect = items_to_collect[0]; // Test if we would hit a bad item when aiming at this good item. // If so, don't change the aim. In this case it has already been // ensured that we won't hit the bad item (otherwise steerToAvoid @@ -823,8 +823,8 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, * to be avoided. * \return True if it would hit any of the bad items. */ -bool SkiddingAI::hitBadItemWhenAimAt(const Item *item, - const std::vector &items_to_avoid) +bool SkiddingAI::hitBadItemWhenAimAt(const ItemState *item, + const std::vector &items_to_avoid) { core::line3df to_item(m_kart->getXYZ().toIrrVector(), item->getXYZ().toIrrVector()); @@ -883,7 +883,7 @@ bool SkiddingAI::handleSelectedItem(Vec3 kart_aim_direction, Vec3 *aim_point) * into account). * \return True if steering is necessary to avoid an item. */ -bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, +bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, const core::line3df &line_to_target, Vec3 *aim_point) { @@ -1036,9 +1036,9 @@ bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, * (NULL if no item was avoided so far). * \param item_to_collect A pointer to a previously selected item to collect. */ -void SkiddingAI::evaluateItems(const Item *item, Vec3 kart_aim_direction, - std::vector *items_to_avoid, - std::vector *items_to_collect) +void SkiddingAI::evaluateItems(const ItemState *item, Vec3 kart_aim_direction, + std::vector *items_to_avoid, + std::vector *items_to_collect) { const KartProperties *kp = m_kart->getKartProperties(); @@ -1110,7 +1110,7 @@ void SkiddingAI::evaluateItems(const Item *item, Vec3 kart_aim_direction, // Now insert the item into the sorted list of items to avoid // (or to collect). The lists are (for now) sorted by distance - std::vector *list; + std::vector *list; if(avoid) list = items_to_avoid; else diff --git a/src/karts/controller/test_ai.hpp b/src/karts/controller/test_ai.hpp index d9b8615fd..cc7a83497 100644 --- a/src/karts/controller/test_ai.hpp +++ b/src/karts/controller/test_ai.hpp @@ -51,7 +51,7 @@ #include -class Item; +class ItemState; #ifdef AI_DEBUG class ShowCurve; @@ -131,7 +131,7 @@ private: unsigned int m_last_direction_node; /** If set an item that the AI should aim for. */ - const Item *m_item_to_collect; + const ItemState *m_item_to_collect; /** True if items to avoid are close by. Used to avoid using zippers * (which would make it more difficult to avoid items). */ @@ -156,7 +156,7 @@ private: /** The last item selected for collection, for which a probability * was determined. */ - const Item *m_last_item_random; + const ItemState *m_last_item_random; /** True if m_last_item_random was randomly selected to be collected. */ bool m_really_collect_item; @@ -210,14 +210,14 @@ private: void handleItemCollectionAndAvoidance(Vec3 *aim_point, int last_node); bool handleSelectedItem(Vec3 kart_aim_direction, Vec3 *aim_point); - bool steerToAvoid(const std::vector &items_to_avoid, + bool steerToAvoid(const std::vector &items_to_avoid, const core::line3df &line_to_target, Vec3 *aim_point); - bool hitBadItemWhenAimAt(const Item *item, - const std::vector &items_to_avoid); - void evaluateItems(const Item *item, Vec3 kart_aim_direction, - std::vector *items_to_avoid, - std::vector *items_to_collect); + bool hitBadItemWhenAimAt(const ItemState *item, + const std::vector &items_to_avoid); + void evaluateItems(const ItemState *item, Vec3 kart_aim_direction, + std::vector *items_to_avoid, + std::vector *items_to_collect); void checkCrashes(const Vec3& pos); void findNonCrashingPointFixed(Vec3 *result, int *last_node);