Converted ItemManager to use a vector of *ItemState (instead of

*Item) for its item handling. This allows us later to use
the switch functions to work on either the current items
or on the confirmed item state (i.e. code reusage for rewind).
This commit is contained in:
hiker 2018-10-02 09:05:32 +10:00
parent e467789e3a
commit c2d0ac4a61
8 changed files with 172 additions and 99 deletions

View File

@ -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
//-----------------------------------------------------------------------------

View File

@ -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. */

View File

@ -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<ItemState*> &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

View File

@ -99,7 +99,7 @@ public:
// ========================================================================
protected:
/** The vector of all items of the current track. */
typedef std::vector<Item*> AllItemTypes;
typedef std::vector<ItemState*> AllItemTypes;
AllItemTypes m_all_items;
private:
@ -111,14 +111,16 @@ private:
/** What item this item is switched to. */
std::vector<ItemState::ItemType> 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<int> &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<btTransform>& 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<Item*>(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<Item*>(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<Item*>((*m_items_in_quads)[n].front());
} // getFirstItemInQuad
}; // ItemManager

View File

@ -553,8 +553,8 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
int node = m_track_node;
float distance = 0;
std::vector<const Item *> items_to_collect;
std::vector<const Item *> items_to_avoid;
std::vector<const ItemState *> items_to_collect;
std::vector<const ItemState *> 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<Item *> &items_ahead =
ItemManager::get()->getItemsInQuads(n_index);
const std::vector<ItemState*> &items_ahead =
ItemManager::get()->getItemsInQuads(n_index);
for(unsigned int i=0; i<items_ahead.size(); i++)
{
evaluateItems(items_ahead[i], kart_aim_direction,
@ -675,7 +675,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
// ----------------------------------
if(items_to_collect.size()>0)
{
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<const Item *> &items_to_avoid)
bool SkiddingAI::hitBadItemWhenAimAt(const ItemState *item,
const std::vector<const ItemState *> &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<const Item *> &items_to_avoid,
bool SkiddingAI::steerToAvoid(const std::vector<const ItemState *> &items_to_avoid,
const core::line3df &line_to_target,
Vec3 *aim_point)
{
@ -958,9 +958,9 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &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<const Item *> *items_to_avoid,
std::vector<const Item *> *items_to_collect)
void SkiddingAI::evaluateItems(const ItemState *item, Vec3 kart_aim_direction,
std::vector<const ItemState *> *items_to_avoid,
std::vector<const ItemState *> *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<const Item*> *list;
std::vector<const ItemState*> *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<const Item *> items_to_collect;
std::vector<const Item *> items_to_avoid;
std::vector<const ItemState *> items_to_collect;
std::vector<const ItemState *> 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<Item *> &items_ahead =
const std::vector<ItemState *> &items_ahead =
ItemManager::get()->getItemsInQuads(n_index);
for(unsigned int i=0; i<items_ahead.size(); i++)
{
@ -1281,8 +1281,9 @@ void SkiddingAI::handleItems(const float dt, const Vec3 *aim_point, int last_nod
* \param items_to_collect The list of close good items
* \param items_to_avoid The list of close bad items
*/
void SkiddingAI::handleBubblegum(int item_skill, const std::vector<const Item *> &items_to_collect,
const std::vector<const Item *> &items_to_avoid)
void SkiddingAI::handleBubblegum(int item_skill,
const std::vector<const ItemState *> &items_to_collect,
const std::vector<const ItemState *> &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<const Item *> &items_to_collect,
const std::vector<const Item *> &items_to_avoid)
void SkiddingAI::handleSwitch(int item_skill,
const std::vector<const ItemState *> &items_to_collect,
const std::vector<const ItemState *> &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<int>(2, energy_reserve);
energy_reserve = std::min(2.0f, energy_reserve);
}
// Don't use nitro or zipper if we are braking

View File

@ -50,7 +50,7 @@
#include <line3d.h>
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<const Item *> &items_to_collect,
const std::vector<const Item *> &items_to_avoid);
void handleBubblegum(int item_skill,
const std::vector<const ItemState *> &items_to_collect,
const std::vector<const ItemState *> &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<const Item *> &items_to_collect,
const std::vector<const Item *> &items_to_avoid);
void handleSwitch(int item_skill,
const std::vector<const ItemState *> &items_to_collect,
const std::vector<const ItemState *> &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<const Item *> &items_to_avoid,
bool steerToAvoid(const std::vector<const ItemState *> &items_to_avoid,
const core::line3df &line_to_target,
Vec3 *aim_point);
bool hitBadItemWhenAimAt(const Item *item,
const std::vector<const Item *> &items_to_avoid);
void evaluateItems(const Item *item, Vec3 kart_aim_direction,
std::vector<const Item *> *items_to_avoid,
std::vector<const Item *> *items_to_collect);
bool hitBadItemWhenAimAt(const ItemState *item,
const std::vector<const ItemState *> &items_to_avoid);
void evaluateItems(const ItemState *item, Vec3 kart_aim_direction,
std::vector<const ItemState *> *items_to_avoid,
std::vector<const ItemState *> *items_to_collect);
void checkCrashes(const Vec3& pos);
void findNonCrashingPointNew(Vec3 *result, int *last_node);

View File

@ -631,8 +631,8 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
int node = m_track_node;
float distance = 0;
std::vector<const Item *> items_to_collect;
std::vector<const Item *> items_to_avoid;
std::vector<const ItemState *> items_to_collect;
std::vector<const ItemState *> 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<Item *> &items_ahead =
const std::vector<ItemState *> &items_ahead =
ItemManager::get()->getItemsInQuads(n_index);
for(unsigned int i=0; i<items_ahead.size(); i++)
{
@ -753,7 +753,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
// ----------------------------------
if(items_to_collect.size()>0)
{
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<const Item *> &items_to_avoid)
bool SkiddingAI::hitBadItemWhenAimAt(const ItemState *item,
const std::vector<const ItemState *> &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<const Item *> &items_to_avoid,
bool SkiddingAI::steerToAvoid(const std::vector<const ItemState *> &items_to_avoid,
const core::line3df &line_to_target,
Vec3 *aim_point)
{
@ -1036,9 +1036,9 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &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<const Item *> *items_to_avoid,
std::vector<const Item *> *items_to_collect)
void SkiddingAI::evaluateItems(const ItemState *item, Vec3 kart_aim_direction,
std::vector<const ItemState *> *items_to_avoid,
std::vector<const ItemState *> *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<const Item*> *list;
std::vector<const ItemState*> *list;
if(avoid)
list = items_to_avoid;
else

View File

@ -51,7 +51,7 @@
#include <line3d.h>
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<const Item *> &items_to_avoid,
bool steerToAvoid(const std::vector<const ItemState *> &items_to_avoid,
const core::line3df &line_to_target,
Vec3 *aim_point);
bool hitBadItemWhenAimAt(const Item *item,
const std::vector<const Item *> &items_to_avoid);
void evaluateItems(const Item *item, Vec3 kart_aim_direction,
std::vector<const Item *> *items_to_avoid,
std::vector<const Item *> *items_to_collect);
bool hitBadItemWhenAimAt(const ItemState *item,
const std::vector<const ItemState *> &items_to_avoid);
void evaluateItems(const ItemState *item, Vec3 kart_aim_direction,
std::vector<const ItemState *> *items_to_avoid,
std::vector<const ItemState *> *items_to_collect);
void checkCrashes(const Vec3& pos);
void findNonCrashingPointFixed(Vec3 *result, int *last_node);