Added new smart rescue
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@9807 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
@@ -251,7 +251,7 @@ void Powerup::use()
|
||||
}
|
||||
|
||||
m_sound_use->play();
|
||||
projectile_manager->newProjectile(m_owner, m_type);
|
||||
projectile_manager->newProjectile(m_owner, world->getTrack(), m_type);
|
||||
break ;
|
||||
|
||||
case PowerupManager::POWERUP_SWATTER:
|
||||
|
||||
@@ -152,16 +152,16 @@ void ProjectileManager::updateClient(float dt)
|
||||
|
||||
} // updateClient
|
||||
// -----------------------------------------------------------------------------
|
||||
Flyable *ProjectileManager::newProjectile(Kart *kart,
|
||||
Flyable *ProjectileManager::newProjectile(Kart *kart, Track* track,
|
||||
PowerupManager::PowerupType type)
|
||||
{
|
||||
Flyable *f;
|
||||
switch(type)
|
||||
{
|
||||
case PowerupManager::POWERUP_BOWLING: f = new Bowling(kart); break;
|
||||
case PowerupManager::POWERUP_PLUNGER: f = new Plunger(kart); break;
|
||||
case PowerupManager::POWERUP_CAKE: f = new Cake(kart); break;
|
||||
case PowerupManager::POWERUP_RUBBERBALL: f = new RubberBall(kart);break;
|
||||
case PowerupManager::POWERUP_BOWLING: f = new Bowling(kart); break;
|
||||
case PowerupManager::POWERUP_PLUNGER: f = new Plunger(kart); break;
|
||||
case PowerupManager::POWERUP_CAKE: f = new Cake(kart); break;
|
||||
case PowerupManager::POWERUP_RUBBERBALL: f = new RubberBall(kart, track); break;
|
||||
default: return NULL;
|
||||
}
|
||||
m_active_projectiles.push_back(f);
|
||||
|
||||
@@ -35,6 +35,7 @@ class Vec3;
|
||||
class Kart;
|
||||
class HitEffect;
|
||||
class Flyable;
|
||||
class Track;
|
||||
|
||||
/**
|
||||
* \ingroup items
|
||||
@@ -61,7 +62,7 @@ public:
|
||||
void loadData ();
|
||||
void cleanup ();
|
||||
void update (float dt);
|
||||
Flyable* newProjectile (Kart *kart,
|
||||
Flyable* newProjectile (Kart *kart, Track* track,
|
||||
PowerupManager::PowerupType type);
|
||||
void Deactivate (Flyable *p) {}
|
||||
void removeTextures ();
|
||||
|
||||
@@ -34,10 +34,12 @@ float RubberBall::m_st_squash_slowdown;
|
||||
float RubberBall::m_st_target_distance;
|
||||
int RubberBall::m_next_id = 0;
|
||||
|
||||
RubberBall::RubberBall(Kart *kart)
|
||||
RubberBall::RubberBall(Kart *kart, Track* track)
|
||||
: Flyable(kart, PowerupManager::POWERUP_RUBBERBALL, 0.0f /* mass */),
|
||||
TrackSector()
|
||||
{
|
||||
m_track = track;
|
||||
|
||||
// For debugging purpose: pre-fix each debugging line with the id of
|
||||
// the ball so that it's easy to collect all debug output for one
|
||||
// particular ball only.
|
||||
@@ -65,7 +67,7 @@ RubberBall::RubberBall(Kart *kart)
|
||||
computeTarget();
|
||||
|
||||
// initialises the current graph node
|
||||
TrackSector::update(getXYZ());
|
||||
TrackSector::update(getXYZ(), kart, track);
|
||||
initializeControlPoints(m_owner->getXYZ());
|
||||
|
||||
// At the start the ball aims at quads till it gets close enough to the
|
||||
@@ -320,7 +322,7 @@ bool RubberBall::updateAndDelete(float dt)
|
||||
next_xyz.setY(new_y);
|
||||
|
||||
// Determine new distance along track
|
||||
TrackSector::update(next_xyz);
|
||||
TrackSector::update(next_xyz, m_owner, m_track);
|
||||
|
||||
// Ball squashing:
|
||||
// ===============
|
||||
|
||||
@@ -121,6 +121,8 @@ private:
|
||||
|
||||
/** Sound effect to be played when a ball hits a kart. */
|
||||
SFXBase *m_hit_sfx;
|
||||
|
||||
Track *m_track;
|
||||
|
||||
void computeTarget();
|
||||
void checkDistanceToTarget();
|
||||
@@ -132,7 +134,7 @@ private:
|
||||
void initializeControlPoints(const Vec3 &xyz);
|
||||
float getMaxTerrainHeight() const;
|
||||
public:
|
||||
RubberBall (Kart* kart);
|
||||
RubberBall (Kart* kart, Track* track);
|
||||
virtual ~RubberBall();
|
||||
static void init(const XMLNode &node, scene::IMesh *bowling);
|
||||
virtual bool updateAndDelete(float dt);
|
||||
|
||||
@@ -62,7 +62,7 @@ void LinearWorld::init()
|
||||
for(unsigned int n=0; n<kart_amount; n++)
|
||||
{
|
||||
KartInfo info;
|
||||
info.getSector()->update(m_karts[n]->getXYZ());
|
||||
info.getSector()->update(m_karts[n]->getXYZ(), m_karts[n], m_track);
|
||||
m_kart_info.push_back(info);
|
||||
} // next kart
|
||||
|
||||
@@ -92,7 +92,7 @@ void LinearWorld::restartRace()
|
||||
for(unsigned int i=0; i<kart_amount; i++)
|
||||
{
|
||||
m_kart_info[i].reset();
|
||||
m_kart_info[i].getSector()->update(m_karts[i]->getXYZ());
|
||||
m_kart_info[i].getSector()->update(m_karts[i]->getXYZ(), m_karts[i], m_track);
|
||||
} // next kart
|
||||
|
||||
// First all kart infos must be updated before the kart position can be
|
||||
@@ -149,7 +149,7 @@ void LinearWorld::update(float dt)
|
||||
// Nothing to do for karts that are currently being rescued or eliminated
|
||||
if(kart->playingEmergencyAnimation()) continue;
|
||||
|
||||
kart_info.getSector()->update(kart->getXYZ());
|
||||
kart_info.getSector()->update(kart->getXYZ(), kart, m_track);
|
||||
} // for n
|
||||
|
||||
// Update all positions. This must be done after _all_ karts have
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "io/xml_node.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "tracks/check_manager.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
|
||||
/** Constructor for a lap line.
|
||||
@@ -72,5 +73,16 @@ bool CheckLap::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos, int indx)
|
||||
m_previous_distance[indx], current_distance);
|
||||
}
|
||||
m_previous_distance[indx] = current_distance;
|
||||
|
||||
|
||||
// If a lap was triggered, reset all visit flags
|
||||
if (result)
|
||||
{
|
||||
CheckManager* cm = World::getWorld()->getTrack()->getCheckManager();
|
||||
for (int n=0; n<cm->getCheckStructureCount(); n++)
|
||||
{
|
||||
cm->getCheckStructure(n)->resetVisits();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} // isTriggered
|
||||
|
||||
@@ -77,6 +77,8 @@ void CheckStructure::reset(const Track &track)
|
||||
{
|
||||
m_previous_position.clear();
|
||||
m_is_active.clear();
|
||||
m_was_visited.clear();
|
||||
|
||||
World *world = World::getWorld();
|
||||
for(unsigned int i=0; i<world->getNumKarts(); i++)
|
||||
{
|
||||
@@ -85,6 +87,7 @@ void CheckStructure::reset(const Track &track)
|
||||
|
||||
// Activate all checkline
|
||||
m_is_active.push_back(m_active_at_reset);
|
||||
m_was_visited.push_back(false);
|
||||
} // for i<getNumKarts
|
||||
} // reset
|
||||
|
||||
@@ -173,7 +176,6 @@ void CheckStructure::changeStatus(const std::vector<int> indices,
|
||||
}
|
||||
} // for i<indices.size()
|
||||
|
||||
|
||||
/*
|
||||
printf("--------\n");
|
||||
for (int n=0; n<m_check_manager->getCheckStructureCount(); n++)
|
||||
@@ -186,6 +188,7 @@ void CheckStructure::changeStatus(const std::vector<int> indices,
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
} //changeStatus
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -194,6 +197,8 @@ void CheckStructure::changeStatus(const std::vector<int> indices,
|
||||
*/
|
||||
void CheckStructure::trigger(unsigned int kart_index)
|
||||
{
|
||||
m_was_visited[kart_index] = true;
|
||||
|
||||
switch(m_check_type)
|
||||
{
|
||||
case CT_NEW_LAP :
|
||||
|
||||
@@ -69,6 +69,8 @@ protected:
|
||||
AlignedArray<Vec3> m_previous_position;
|
||||
/** Stores if this check structure is active (for a given kart). */
|
||||
std::vector<bool> m_is_active;
|
||||
/** If this check structure was triggered during this lap (for each kart) */
|
||||
std::vector<bool> m_was_visited;
|
||||
|
||||
/** True if this check structure should be activated at a reset. */
|
||||
bool m_active_at_reset;
|
||||
@@ -120,6 +122,21 @@ public:
|
||||
/** Returns the type of this check structure. */
|
||||
CheckType getType() const { return m_check_type; }
|
||||
|
||||
bool wasVisitedForKart(int kart_id)
|
||||
{
|
||||
assert(kart_id < (int)m_was_visited.size());
|
||||
assert(kart_id >= 0);
|
||||
return m_was_visited[kart_id];
|
||||
}
|
||||
|
||||
void resetVisits()
|
||||
{
|
||||
for (unsigned int n=0; n<m_was_visited.size(); n++)
|
||||
{
|
||||
m_was_visited[n] = false;
|
||||
}
|
||||
}
|
||||
|
||||
}; // CheckStructure
|
||||
|
||||
#endif
|
||||
|
||||
@@ -219,7 +219,7 @@ float GraphNode::getDistance2FromPoint(const Vec3 &xyz)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void GraphNode::setChecklineRequirements(const std::set<int>& r)
|
||||
void GraphNode::setChecklineRequirements(int latest_checkline)
|
||||
{
|
||||
m_checkline_requirements.push_back(r);
|
||||
m_checkline_requirements.push_back(latest_checkline);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#define HEADER_GRAPH_NODE_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include <vector2d.h>
|
||||
#include <dimension2d.h>
|
||||
@@ -104,7 +103,7 @@ class GraphNode
|
||||
* this node (there is a possibility of more than one set because of
|
||||
* alternate ways)
|
||||
*/
|
||||
std::vector< std::set<int> > m_checkline_requirements;
|
||||
std::vector< int > m_checkline_requirements;
|
||||
|
||||
public:
|
||||
/** Keep a shared pointer so that some asserts and tests can be
|
||||
@@ -197,7 +196,9 @@ public:
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
void setChecklineRequirements(const std::set<int>& r);
|
||||
void setChecklineRequirements(int latest_checkline);
|
||||
|
||||
const std::vector<int>& getChecklineRequirements() const { return m_checkline_requirements; }
|
||||
}; // GraphNode
|
||||
|
||||
#endif
|
||||
|
||||
@@ -189,7 +189,7 @@ void QuadGraph::load(const std::string &filename)
|
||||
* Finds which checklines must be visited before driving on this quad
|
||||
* (useful for rescue)
|
||||
*/
|
||||
void QuadGraph::setChecklineRequirements(GraphNode* node, std::set<int> checklines)
|
||||
void QuadGraph::setChecklineRequirements(GraphNode* node, int latest_checkline)
|
||||
{
|
||||
Track* t = World::getWorld()->getTrack();
|
||||
CheckManager* cm = t->getCheckManager();
|
||||
@@ -202,7 +202,7 @@ void QuadGraph::setChecklineRequirements(GraphNode* node, std::set<int> checklin
|
||||
// warp-around
|
||||
if (succ_id == 0) break;
|
||||
|
||||
std::set<int> these_checklines = checklines;
|
||||
int new_latest_checkline = latest_checkline;
|
||||
|
||||
GraphNode* succ = m_all_nodes[succ_id];
|
||||
for (int i=0; i<cm->getCheckStructureCount(); i++)
|
||||
@@ -214,12 +214,14 @@ void QuadGraph::setChecklineRequirements(GraphNode* node, std::set<int> checklin
|
||||
|
||||
if (c->isTriggered(node->getCenter(), succ->getCenter(), 0 /* kart id */))
|
||||
{
|
||||
//printf("* Check %i is triggerred when going from %i to %i\n", i, node->getIndex(), succ_id);
|
||||
these_checklines.insert(i);
|
||||
new_latest_checkline = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
printf("Quad %i : checkline %i\n", succ_id, new_latest_checkline);
|
||||
|
||||
printf("Quad %i :\n", succ_id);
|
||||
for (std::set<int>::iterator it = these_checklines.begin();it != these_checklines.end(); it++)
|
||||
{
|
||||
@@ -227,8 +229,10 @@ void QuadGraph::setChecklineRequirements(GraphNode* node, std::set<int> checklin
|
||||
}
|
||||
*/
|
||||
|
||||
succ->setChecklineRequirements(these_checklines);
|
||||
setChecklineRequirements(succ, these_checklines);
|
||||
if (new_latest_checkline != -1)
|
||||
succ->setChecklineRequirements(new_latest_checkline);
|
||||
|
||||
setChecklineRequirements(succ, new_latest_checkline);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ private:
|
||||
std::string m_quad_filename;
|
||||
|
||||
void setDefaultSuccessors();
|
||||
void setChecklineRequirements(GraphNode* node, std::set<int> checklines);
|
||||
void setChecklineRequirements(GraphNode* node, int latest_checkline);
|
||||
|
||||
void load (const std::string &filename);
|
||||
void createMesh(bool show_invisible=true,
|
||||
@@ -177,7 +177,7 @@ public:
|
||||
|
||||
void setChecklineRequirements()
|
||||
{
|
||||
setChecklineRequirements(m_all_nodes[0], std::set<int>());
|
||||
setChecklineRequirements(m_all_nodes[0], -1);
|
||||
}
|
||||
|
||||
}; // QuadGraph
|
||||
|
||||
@@ -1447,7 +1447,7 @@ void Track::loadTrackModel(World* parent, unsigned int mode_id)
|
||||
irr_driver->getSceneManager()->getMeshCache()->getMeshCount(),
|
||||
irr_driver->getVideoDriver()->getTextureCount());
|
||||
|
||||
//QuadGraph::get()->setChecklineRequirements();
|
||||
QuadGraph::get()->setChecklineRequirements();
|
||||
|
||||
} // loadTrackModel
|
||||
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "modes/world.hpp"
|
||||
#include "tracks/check_manager.hpp"
|
||||
#include "tracks/check_structure.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_sector.hpp"
|
||||
#include "tracks/quad_graph.hpp"
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Initialises the object, and sets the current graph node to be undefined.
|
||||
*/
|
||||
@@ -42,13 +45,26 @@ void TrackSector::reset()
|
||||
* the specified point.
|
||||
* \param xyz The new coordinates to search the graph node for.
|
||||
*/
|
||||
void TrackSector::update(const Vec3 &xyz)
|
||||
void TrackSector::update(const Vec3 &xyz, Kart* kart, Track* track)
|
||||
{
|
||||
int prev_sector = m_current_graph_node;
|
||||
|
||||
QuadGraph::get()->findRoadSector(xyz, &m_current_graph_node);
|
||||
m_on_road = m_current_graph_node != QuadGraph::UNKNOWN_SECTOR;
|
||||
|
||||
int kart_id = -1;
|
||||
World* world = World::getWorld();
|
||||
for (unsigned int i=0; i<world->getNumKarts(); i++)
|
||||
{
|
||||
if (world->getKart(i) == kart)
|
||||
{
|
||||
kart_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(kart_id != -1);
|
||||
|
||||
// If m_track_sector == UNKNOWN_SECTOR, then the kart is not on top of
|
||||
// the road, so we have to use search for the closest graph node.
|
||||
if(m_current_graph_node == QuadGraph::UNKNOWN_SECTOR)
|
||||
@@ -57,9 +73,47 @@ void TrackSector::update(const Vec3 &xyz)
|
||||
QuadGraph::get()->findOutOfRoadSector(xyz,
|
||||
prev_sector);
|
||||
}
|
||||
else
|
||||
m_last_valid_graph_node = m_current_graph_node;
|
||||
|
||||
|
||||
if(m_current_graph_node != QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
// keep the current quad as the latest valid one IF the player has one of the required checklines
|
||||
const std::vector<int>& checkline_requirements =
|
||||
QuadGraph::get()->getNode(m_current_graph_node).getChecklineRequirements();
|
||||
|
||||
//if (m_last_valid_graph_node != m_current_graph_node)
|
||||
// printf("Checking quad %i, which has requirement %i\n", m_current_graph_node,
|
||||
// checkline_requirements.size() == 0 ? -99 : checkline_requirements[0]);
|
||||
|
||||
CheckManager* cm = track->getCheckManager();
|
||||
|
||||
const unsigned int count = cm->getCheckStructureCount();
|
||||
|
||||
if (checkline_requirements.size() == 0)
|
||||
{
|
||||
//if (m_last_valid_graph_node != m_current_graph_node)
|
||||
// printf("[1] m_last_valid_graph_node : %i\n", m_last_valid_graph_node);
|
||||
m_last_valid_graph_node = m_current_graph_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i=0; i<checkline_requirements.size(); i++)
|
||||
{
|
||||
//for (int k=0; k<cm->getCheckStructureCount(); k++)
|
||||
// printf(" Check %i visited : %i\n", k, cm->getCheckStructure(k)->wasVisitedForKart(kart_id));
|
||||
|
||||
if (checkline_requirements[i] < (int)count &&
|
||||
cm->getCheckStructure(checkline_requirements[i])->wasVisitedForKart(kart_id))
|
||||
{
|
||||
//if (m_last_valid_graph_node != m_current_graph_node)
|
||||
// printf("[2] m_last_valid_graph_node : %i\n", m_last_valid_graph_node);
|
||||
|
||||
m_last_valid_graph_node = m_current_graph_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now determine the 'track' coords, i.e. ow far from the start of the
|
||||
// track, and how far to the left or right of the center driveline.
|
||||
QuadGraph::get()->spatialToTrack(&m_current_track_coords, xyz,
|
||||
@@ -69,17 +123,8 @@ void TrackSector::update(const Vec3 &xyz)
|
||||
// ----------------------------------------------------------------------------
|
||||
void TrackSector::rescue()
|
||||
{
|
||||
// If the kart is off road, rescue it to the last valid track position
|
||||
// instead of the current one (since the sector might be determined by
|
||||
// being closest to it, which allows shortcuts like drive towards another
|
||||
// part of the lap, press rescue, and be rescued to this other part of
|
||||
// the track (example: math class, drive towards the left after start,
|
||||
// when hitting the books, press rescue --> you are rescued to the
|
||||
// end of the track).
|
||||
if(!isOnRoad())
|
||||
{
|
||||
if (m_last_valid_graph_node != QuadGraph::UNKNOWN_SECTOR)
|
||||
m_current_graph_node = m_last_valid_graph_node;
|
||||
}
|
||||
|
||||
// Using the predecessor has the additional advantage (besides punishing
|
||||
// the player a bit more) that it makes it less likely to fall in a
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
|
||||
#include "utils/vec3.hpp"
|
||||
|
||||
class Track;
|
||||
class Kart;
|
||||
|
||||
/** This object keeps track of which sector an object is on. A sector is
|
||||
* actually just the graph node (it's called sector to better distinguish
|
||||
* the graph node from say xml node and scene node).
|
||||
@@ -55,7 +58,7 @@ public:
|
||||
TrackSector();
|
||||
void reset();
|
||||
void rescue();
|
||||
void update(const Vec3 &xyz);
|
||||
void update(const Vec3 &xyz, Kart* kart, Track* track);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how far the the object is from the start line. */
|
||||
float getDistanceFromStart() const { return m_current_track_coords.getZ();}
|
||||
|
||||
Reference in New Issue
Block a user