Merge branch 'master' of https://github.com/supertuxkart/stk-code
This commit is contained in:
commit
dc885fbf05
@ -4,7 +4,7 @@ out vec4 FragColor;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec3 eyedir = vec3(gl_FragCoord.xy / screen, 1.);
|
||||
vec3 eyedir = vec3(mod(gl_FragCoord.xy, screen) / screen, 1.);
|
||||
eyedir = 2.0 * eyedir - 1.0;
|
||||
vec4 tmp = (InverseProjectionMatrix * vec4(eyedir, 1.));
|
||||
tmp /= tmp.w;
|
||||
|
@ -8,28 +8,28 @@
|
||||
<summary>A racing game</summary>
|
||||
<description>
|
||||
<p>
|
||||
SuperTuxKart is a fun 3D kart racing game.
|
||||
You can play with up to 4 friends on one PC, racing against each other or
|
||||
just try to beat the computer.
|
||||
Supertuxkart is a free 3D kart racing game, with a focus on having fun over
|
||||
realism. You can play with up to 4 friends on one PC, racing against each
|
||||
other, or try to beat the computer in single-player mode.
|
||||
</p>
|
||||
<p>
|
||||
See the great lighthouse or drive through the sand and visit the pyramids.
|
||||
Race underground or in space, watching the stars passing by.
|
||||
Have some rest under the palms on the beach (watching the other karts
|
||||
overtaking you :) ).
|
||||
But don't eat the bananas! Watch for bowling balls, plungers, bubble gum
|
||||
and cakes thrown by opponents.
|
||||
Race underground or in space, watching the stars pass by. Or rest under the
|
||||
palm trees on the beach, watching the other karts overtake you. But don't eat
|
||||
the bananas! Watch for bowling balls, plungers, bubble gum and cakes thrown by
|
||||
your opponents.
|
||||
</p>
|
||||
<p>
|
||||
You can do a single race against other karts, compete in one of several
|
||||
Grand Prix, try to beat the high score in time trials on your own, play
|
||||
battle mode against your friends, and more!
|
||||
You can do a single race against other karts, compete in one of several Grand
|
||||
Prix, try to beat the high score in time trials on your own, play battle mode
|
||||
against the computer or your friends, and more!
|
||||
</p>
|
||||
</description>
|
||||
<url type="homepage">http://supertuxkart.sourceforge.net/</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">http://supertuxkart.sourceforge.net/persistent/images/4/4d/SuperTuxKart_0.8_screenshot.jpg</screenshot>
|
||||
<screenshot>http://supertuxkart.sourceforge.net/persistent/images/1/1f/SuperTuxKart_0.8_screenshot4.jpg</screenshot>
|
||||
<screenshot type="default">http://supertuxkart.sourceforge.net/persistent/images/4/4e/Supertuxkart-0.9-screenshot-2.jpg</screenshot>
|
||||
<screenshot>http://supertuxkart.sourceforge.net/persistent/images/a/a9/Supertuxkart-0.9-screenshot-1.jpg</screenshot>
|
||||
<screenshot>http://supertuxkart.sourceforge.net/persistent/images/6/63/Supertuxkart-0.9-screenshot-3.jpg</screenshot>
|
||||
</screenshots>
|
||||
<updatecontact>supertuxkart-devel@lists.sourceforge.net</updatecontact>
|
||||
</application>
|
||||
|
@ -289,17 +289,18 @@ void AIBaseController::checkPosition(const Vec3 &point,
|
||||
{
|
||||
// Convert to local coordinates from the point of view of current kart
|
||||
btQuaternion q(btVector3(0, 1, 0), -m_kart->getHeading());
|
||||
Vec3 p = point - m_kart->getXYZ();
|
||||
Vec3 p = point - m_kart->getXYZ();
|
||||
Vec3 local_coordinates = quatRotate(q, p);
|
||||
|
||||
// Save local coordinates for later use if needed
|
||||
if (lc) *lc = local_coordinates;
|
||||
|
||||
// on_side: tell whether it's left or right hand side
|
||||
if (pos_data == NULL) return;
|
||||
// lhs: tell whether it's left or right hand side
|
||||
if (local_coordinates.getX() < 0)
|
||||
pos_data->on_side = true;
|
||||
pos_data->lhs = true;
|
||||
else
|
||||
pos_data->on_side = false;
|
||||
pos_data->lhs = false;
|
||||
|
||||
// behind: tell whether it's behind or not
|
||||
if (local_coordinates.getZ() < 0)
|
||||
|
@ -65,7 +65,7 @@ protected:
|
||||
static int m_test_ai;
|
||||
|
||||
/** Position info structure of targets. */
|
||||
struct posData {bool behind; bool on_side; float angle; float distance;};
|
||||
struct posData {bool behind; bool lhs; float angle; float distance;};
|
||||
|
||||
void setControllerName(const std::string &name);
|
||||
float steerToPoint(const Vec3 &point);
|
||||
|
@ -33,6 +33,7 @@ ArenaAI::ArenaAI(AbstractKart *kart)
|
||||
: AIBaseController(kart)
|
||||
{
|
||||
m_debug_sphere = NULL;
|
||||
m_debug_sphere_next = NULL;
|
||||
} // ArenaAI
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -242,7 +243,7 @@ void ArenaAI::handleArenaSteering(const float dt)
|
||||
#endif
|
||||
if (m_cur_kart_pos_data.behind)
|
||||
{
|
||||
m_adjusting_side = m_cur_kart_pos_data.on_side;
|
||||
m_adjusting_side = m_cur_kart_pos_data.lhs;
|
||||
m_is_uturn = true;
|
||||
}
|
||||
else
|
||||
@ -262,11 +263,22 @@ void ArenaAI::handleArenaSteering(const float dt)
|
||||
|
||||
checkPosition(m_target_point, &m_cur_kart_pos_data);
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere->setPosition(m_target_point.toIrrVector());
|
||||
if (m_path_corners.size() > 2)
|
||||
{
|
||||
m_debug_sphere->setVisible(true);
|
||||
m_debug_sphere_next->setVisible(true);
|
||||
m_debug_sphere->setPosition(m_path_corners[1].toIrrVector());
|
||||
m_debug_sphere_next->setPosition(m_path_corners[2].toIrrVector());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_debug_sphere->setVisible(false);
|
||||
m_debug_sphere_next->setVisible(false);
|
||||
}
|
||||
#endif
|
||||
if (m_cur_kart_pos_data.behind)
|
||||
{
|
||||
m_adjusting_side = m_cur_kart_pos_data.on_side;
|
||||
m_adjusting_side = m_cur_kart_pos_data.lhs;
|
||||
m_is_uturn = true;
|
||||
}
|
||||
else
|
||||
@ -306,7 +318,7 @@ void ArenaAI::handleArenaBanana()
|
||||
{
|
||||
// Check whether it's straight ahead towards a banana
|
||||
// If so, adjust target point
|
||||
banana_lc = (banana_pos.on_side ? banana_lc + Vec3 (2, 0, 0) :
|
||||
banana_lc = (banana_pos.lhs ? banana_lc + Vec3 (2, 0, 0) :
|
||||
banana_lc - Vec3 (2, 0, 0));
|
||||
m_target_point = m_kart->getTrans()(banana_lc);
|
||||
m_target_node = BattleGraph::get()
|
||||
@ -478,28 +490,25 @@ void ArenaAI::stringPull(const Vec3& start_pos, const Vec3& end_pos)
|
||||
*/
|
||||
void ArenaAI::handleArenaBraking()
|
||||
{
|
||||
m_controls->m_brake = false;
|
||||
|
||||
if (getCurrentNode() == BattleGraph::UNKNOWN_POLY ||
|
||||
m_target_node == BattleGraph::UNKNOWN_POLY) return;
|
||||
|
||||
// A kart will not brake when the speed is already slower than this
|
||||
// value. This prevents a kart from going too slow (or even backwards)
|
||||
// in tight curves.
|
||||
const float MIN_SPEED = 5.0f;
|
||||
|
||||
std::vector<Vec3> points;
|
||||
if (forceBraking() && m_kart->getSpeed() > MIN_SPEED)
|
||||
{
|
||||
// Brake now
|
||||
return;
|
||||
}
|
||||
|
||||
points.push_back(m_kart->getXYZ());
|
||||
points.push_back(m_path_corners[0]);
|
||||
points.push_back((m_path_corners.size()>=2) ? m_path_corners[1] : m_path_corners[0]);
|
||||
m_controls->m_brake = false;
|
||||
|
||||
float current_curve_radius = determineTurnRadius(points);
|
||||
if (getCurrentNode() == BattleGraph::UNKNOWN_POLY ||
|
||||
m_target_node == BattleGraph::UNKNOWN_POLY) return;
|
||||
|
||||
Vec3 d1 = m_kart->getXYZ() - m_target_point;
|
||||
Vec3 d2 = m_kart->getXYZ() - m_path_corners[0];
|
||||
if (d1.length2_2d() < d2.length2_2d())
|
||||
current_curve_radius = d1.length_2d();
|
||||
float current_curve_radius = determineTurnRadius(m_kart->getXYZ(),
|
||||
m_path_corners[0], (m_path_corners.size() >= 2 ? m_path_corners[1] :
|
||||
m_path_corners[0]));
|
||||
|
||||
float max_turn_speed = m_kart->getSpeedForTurnRadius(current_curve_radius);
|
||||
|
||||
@ -516,55 +525,44 @@ void ArenaAI::handleArenaBraking()
|
||||
* location of AI, first corner and the second corner. Once the constants are
|
||||
* computed, a formula is used to find the radius of curvature at the kart's
|
||||
* current location.
|
||||
* NOTE: This method does not apply enough braking, should think of something
|
||||
* else.
|
||||
*/
|
||||
float ArenaAI::determineTurnRadius( std::vector<Vec3>& points )
|
||||
float ArenaAI::determineTurnRadius(const Vec3& p1, const Vec3& p2,
|
||||
const Vec3& p3)
|
||||
{
|
||||
// Declaring variables
|
||||
float a, b;
|
||||
irr::core::CMatrix4<float> A;
|
||||
irr::core::CMatrix4<float> X;
|
||||
irr::core::CMatrix4<float> B;
|
||||
// The parabola function is as following: y=ax2+bx+c
|
||||
// No need to calculate c as after differentiating c will be zero
|
||||
const float eps = 0.01f;
|
||||
const float denominator = (p1.x() - p2.x()) * (p1.x() - p3.x()) *
|
||||
(p2.x() - p3.x());
|
||||
|
||||
//Populating matrices
|
||||
for (unsigned int i = 0; i < 3; i++)
|
||||
{
|
||||
A(i, 0) = points[i].x()*points[i].x();
|
||||
A(i, 1) = points[i].x();
|
||||
A(i, 2) = 1.0f;
|
||||
A(i, 3) = 0.0f;
|
||||
}
|
||||
A(3, 0) = A(3, 1) = A(3, 2) = 0.0f;
|
||||
A(3, 3) = 1.0f;
|
||||
// Avoid nan, this will happen if three values of coordinates x are too
|
||||
// close together, ie a straight line, return a large radius
|
||||
// so no braking is needed
|
||||
if (fabsf(denominator) < eps) return 25.0f;
|
||||
|
||||
for (unsigned int i = 0; i < 3; i++)
|
||||
{
|
||||
B(i, 0) = points[i].z();
|
||||
B(i, 1) = 0.0f;
|
||||
B(i, 2) = 0.0f;
|
||||
B(i, 3) = 0.0f;
|
||||
}
|
||||
B(3, 0) = B(3, 1) = B(3, 2) = B(3, 3) = 0.0f;
|
||||
const float a = (p3.x() * (p2.z() - p1.z()) +
|
||||
p2.x() * (p1.z() - p3.z()) +
|
||||
p1.x() * (p3.z() - p2.z())) / denominator;
|
||||
|
||||
//Computing inverse : X = inv(A)*B
|
||||
irr::core::CMatrix4<float> invA;
|
||||
if (!A.getInverse(invA))
|
||||
return -1;
|
||||
// Should not happen, otherwise y=c which is a straight line
|
||||
if (fabsf(a) < eps) return 25.0f;
|
||||
|
||||
X = invA*B;
|
||||
a = X(0, 0);
|
||||
b = X(0, 1);
|
||||
//c = X(0, 2);
|
||||
const float b = (p3.x() * p3.x() * (p1.z() - p2.z()) +
|
||||
p2.x() * p2.x() * (p3.z() - p1.z()) +
|
||||
p1.x() * p1.x() * (p2.z() - p3.z())) / denominator;
|
||||
|
||||
float x = points.front().x();
|
||||
//float z = a*pow(x, 2) + b*x + c;
|
||||
float dx_by_dz = 2*a*x + b;
|
||||
float d2x_by_dz = 2*a;
|
||||
// Differentiate the function, so y=ax2+bx+c will become y=2ax+b for dy_dx,
|
||||
// y=2a for d2y_dx2
|
||||
// Use the p1 (current location of AI) as x
|
||||
const float dy_dx = 2 * a * p1.x() + b;
|
||||
const float d2y_dx2 = 2 * a;
|
||||
|
||||
float radius = pow(abs(1 + pow(dx_by_dz, 2)), 1.5f)/ abs(d2x_by_dz);
|
||||
// Calculate the radius of curvature at current location of AI
|
||||
const float radius = pow(1 + pow(dy_dx, 2), 1.5f) / fabsf(d2y_dx2);
|
||||
assert(!std::isnan(radius));
|
||||
|
||||
return radius;
|
||||
// Avoid returning too large radius
|
||||
return (radius > 25.0f ? 25.0f : radius);
|
||||
} // determineTurnRadius
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -663,7 +661,8 @@ void ArenaAI::handleArenaItems(const float dt)
|
||||
if (m_time_since_last_shot < 1.0f) break;
|
||||
|
||||
if (m_closest_kart_pos_data.distance < 6.0f &&
|
||||
(difficulty || perfect_aim))
|
||||
(difficulty || perfect_aim) &&
|
||||
!m_closest_kart->isInvulnerable())
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = fire_behind;
|
||||
|
@ -56,6 +56,7 @@ protected:
|
||||
/** For debugging purpose: a sphere indicating where the AI
|
||||
* is targeting at. */
|
||||
irr::scene::ISceneNode *m_debug_sphere;
|
||||
irr::scene::ISceneNode *m_debug_sphere_next;
|
||||
|
||||
/** The node(poly) at which the target point lies in. */
|
||||
int m_target_node;
|
||||
@ -104,7 +105,8 @@ private:
|
||||
float m_time_since_uturn;
|
||||
|
||||
void checkIfStuck(const float dt);
|
||||
float determineTurnRadius(std::vector<Vec3>& points);
|
||||
float determineTurnRadius(const Vec3& p1, const Vec3& p2,
|
||||
const Vec3& p3);
|
||||
void findPortals(int start, int end);
|
||||
void handleArenaAcceleration(const float dt);
|
||||
void handleArenaBanana();
|
||||
@ -118,6 +120,7 @@ private:
|
||||
virtual bool isWaiting() const = 0;
|
||||
virtual void findClosestKart(bool use_difficulty) = 0;
|
||||
virtual void findTarget() = 0;
|
||||
virtual bool forceBraking() { return false; }
|
||||
public:
|
||||
ArenaAI(AbstractKart *kart);
|
||||
virtual ~ArenaAI() {};
|
||||
|
@ -41,8 +41,11 @@ BattleAI::BattleAI(AbstractKart *kart)
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
video::SColor col_debug(128, 128, 0, 0);
|
||||
video::SColor col_debug_next(128, 0, 128, 128);
|
||||
m_debug_sphere = irr_driver->addSphere(1.0f, col_debug);
|
||||
m_debug_sphere->setVisible(true);
|
||||
m_debug_sphere_next = irr_driver->addSphere(1.0f, col_debug_next);
|
||||
m_debug_sphere_next->setVisible(true);
|
||||
#endif
|
||||
m_world = dynamic_cast<ThreeStrikesBattle*>(World::getWorld());
|
||||
m_track = m_world->getTrack();
|
||||
@ -59,6 +62,7 @@ BattleAI::~BattleAI()
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
irr_driver->removeNode(m_debug_sphere);
|
||||
irr_driver->removeNode(m_debug_sphere_next);
|
||||
#endif
|
||||
} // ~BattleAI
|
||||
|
||||
@ -157,12 +161,12 @@ void BattleAI::findTarget()
|
||||
}
|
||||
} // findTarget
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
int BattleAI::getCurrentNode() const
|
||||
{
|
||||
return m_world->getKartNode(m_kart->getWorldKartId());
|
||||
} // getCurrentNode
|
||||
// ------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool BattleAI::isWaiting() const
|
||||
{
|
||||
return m_world->isStartPhase();
|
||||
|
@ -41,11 +41,15 @@ SoccerAI::SoccerAI(AbstractKart *kart)
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
video::SColor col_debug(128, 128, 0, 0);
|
||||
video::SColor col_debug_next(128, 0, 128, 128);
|
||||
m_debug_sphere = irr_driver->addSphere(1.0f, col_debug);
|
||||
m_debug_sphere->setVisible(true);
|
||||
m_debug_sphere_next = irr_driver->addSphere(1.0f, col_debug_next);
|
||||
m_debug_sphere_next->setVisible(true);
|
||||
#endif
|
||||
m_world = dynamic_cast<SoccerWorld*>(World::getWorld());
|
||||
m_track = m_world->getTrack();
|
||||
m_cur_team = m_world->getKartTeam(m_kart->getWorldKartId());
|
||||
|
||||
// Don't call our own setControllerName, since this will add a
|
||||
// billboard showing 'AIBaseController' to the kart.
|
||||
@ -59,6 +63,7 @@ SoccerAI::~SoccerAI()
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
irr_driver->removeNode(m_debug_sphere);
|
||||
irr_driver->removeNode(m_debug_sphere_next);
|
||||
#endif
|
||||
} // ~SoccerAI
|
||||
|
||||
@ -71,31 +76,15 @@ void SoccerAI::reset()
|
||||
AIBaseController::reset();
|
||||
|
||||
m_saving_ball = false;
|
||||
if (race_manager->getNumPlayers() == 1)
|
||||
{
|
||||
// Same handle in SoccerWorld::createKart
|
||||
if (race_manager->getKartInfo(0).getSoccerTeam() == SOCCER_TEAM_RED)
|
||||
{
|
||||
m_cur_team = (m_kart->getWorldKartId() % 2 == 0 ?
|
||||
SOCCER_TEAM_BLUE : SOCCER_TEAM_RED);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_team = (m_kart->getWorldKartId() % 2 == 0 ?
|
||||
SOCCER_TEAM_RED : SOCCER_TEAM_BLUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_team = (m_kart->getWorldKartId() % 2 == 0 ?
|
||||
SOCCER_TEAM_BLUE : SOCCER_TEAM_RED);
|
||||
}
|
||||
m_force_brake = false;
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SoccerAI::update(float dt)
|
||||
{
|
||||
m_saving_ball = false;
|
||||
m_force_brake = false;
|
||||
|
||||
if (World::getWorld()->getPhase() == World::GOAL_PHASE)
|
||||
{
|
||||
m_controls->m_brake = false;
|
||||
@ -147,8 +136,8 @@ void SoccerAI::findClosestKart(bool use_difficulty)
|
||||
void SoccerAI::findTarget()
|
||||
{
|
||||
// Check whether any defense is needed
|
||||
if ((m_world->getBallPosition() - NavMesh::get()->getNavPoly(m_world
|
||||
->getGoalNode(m_cur_team)).getCenter()).length_2d() < 50.0f &&
|
||||
if ((m_world->getBallPosition() - m_world->getGoalLocation(m_cur_team,
|
||||
CheckGoal::POINT_CENTER)).length_2d() < 50.0f &&
|
||||
m_world->getDefender(m_cur_team) == (signed)m_kart->getWorldKartId())
|
||||
{
|
||||
m_target_node = m_world->getBallNode();
|
||||
@ -174,86 +163,110 @@ Vec3 SoccerAI::correctBallPosition(const Vec3& orig_pos)
|
||||
{
|
||||
// Notice: Build with AI_DEBUG and change camera target to an AI kart,
|
||||
// to debug or see how AI steer with the ball
|
||||
|
||||
posData ball_pos = {0};
|
||||
posData goal_pos = {0};
|
||||
Vec3 ball_lc(0, 0, 0);
|
||||
Vec3 ball_lc;
|
||||
checkPosition(orig_pos, &ball_pos, &ball_lc);
|
||||
|
||||
// opposite team goal
|
||||
checkPosition(NavMesh::get()->getNavPoly(m_world
|
||||
->getGoalNode(m_cur_team == SOCCER_TEAM_BLUE ?
|
||||
SOCCER_TEAM_RED : SOCCER_TEAM_BLUE)).getCenter(), &goal_pos);
|
||||
// Too far / behind from the ball,
|
||||
// use path finding from arena ai to get close
|
||||
if (!(ball_pos.distance < 3.0f) || ball_pos.behind) return orig_pos;
|
||||
|
||||
if (goal_pos.behind)
|
||||
// Save the opposite team
|
||||
SoccerTeam opp_team = (m_cur_team == SOCCER_TEAM_BLUE ?
|
||||
SOCCER_TEAM_RED : SOCCER_TEAM_BLUE);
|
||||
|
||||
// Prevent lost control when steering with ball
|
||||
const bool need_braking = ball_pos.angle > 0.1f &&
|
||||
m_kart->getSpeed() > 9.0f && ball_pos.distance <2.5f;
|
||||
|
||||
// Goal / own goal detection first, as different aiming method will be used
|
||||
const bool likely_to_goal =
|
||||
ball_pos.angle < 0.2f && isLikelyToGoal(opp_team);
|
||||
if (likely_to_goal)
|
||||
{
|
||||
if (goal_pos.angle > 0.3f && ball_pos.distance < 3.0f &&
|
||||
!ball_pos.behind)
|
||||
if (need_braking)
|
||||
{
|
||||
// Only steer with ball if same sides for ball and goal
|
||||
if (ball_pos.on_side && goal_pos.on_side)
|
||||
{
|
||||
ball_lc = ball_lc + Vec3 (1, 0, 1);
|
||||
return m_kart->getTrans()(ball_lc);
|
||||
}
|
||||
else if (!ball_pos.on_side && !goal_pos.on_side)
|
||||
{
|
||||
ball_lc = ball_lc - Vec3 (1, 0, 0) + Vec3 (0, 0, 1);
|
||||
return m_kart->getTrans()(ball_lc);
|
||||
}
|
||||
else
|
||||
m_controls->m_brake = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This case is facing straight ahead opposite goal
|
||||
// (which is straight behind itself), apply more
|
||||
// offset for skidding, to save the ball from behind
|
||||
// scored.
|
||||
// Notice: this assume map maker make soccer field
|
||||
// with two goals facing each other straight
|
||||
ball_lc = (goal_pos.on_side ? ball_lc - Vec3 (2, 0, 0) +
|
||||
Vec3 (0, 0, 2) : ball_lc + Vec3 (2, 0, 2));
|
||||
|
||||
if (ball_pos.distance < 3.0f &&
|
||||
(m_cur_difficulty == RaceManager::DIFFICULTY_HARD ||
|
||||
m_cur_difficulty == RaceManager::DIFFICULTY_BEST))
|
||||
m_saving_ball = true;
|
||||
return m_kart->getTrans()(ball_lc);
|
||||
m_controls->m_brake = true;
|
||||
m_force_brake = true;
|
||||
// Prevent keep pushing by aiming a nearer point
|
||||
return m_kart->getTrans()(ball_lc - Vec3(0, 0, 1));
|
||||
}
|
||||
// Keep pushing the ball straight to the goal
|
||||
return orig_pos;
|
||||
}
|
||||
|
||||
if (ball_pos.distance < 3.0f &&
|
||||
!ball_pos.behind && !goal_pos.behind)
|
||||
const bool likely_to_own_goal =
|
||||
ball_pos.angle < 0.2f && isLikelyToGoal(m_cur_team);
|
||||
if (likely_to_own_goal)
|
||||
{
|
||||
if (goal_pos.angle < 0.5f)
|
||||
return orig_pos;
|
||||
else
|
||||
{
|
||||
// Same with above
|
||||
if (ball_pos.on_side && goal_pos.on_side)
|
||||
{
|
||||
ball_lc = ball_lc + Vec3 (1, 0, 1);
|
||||
return m_kart->getTrans()(ball_lc);
|
||||
}
|
||||
else if (!ball_pos.on_side && !goal_pos.on_side)
|
||||
{
|
||||
ball_lc = ball_lc - Vec3 (1, 0, 0) + Vec3 (0, 0, 1);
|
||||
return m_kart->getTrans()(ball_lc);
|
||||
}
|
||||
else
|
||||
m_controls->m_brake = true;
|
||||
}
|
||||
// It's getting likely to own goal, apply more
|
||||
// offset for skidding, to save the ball from behind
|
||||
// scored.
|
||||
if (m_cur_difficulty == RaceManager::DIFFICULTY_HARD ||
|
||||
m_cur_difficulty == RaceManager::DIFFICULTY_BEST)
|
||||
m_saving_ball = true;
|
||||
return m_kart->getTrans()(ball_pos.lhs ?
|
||||
ball_lc - Vec3(2, 0, 0) + Vec3(0, 0, 2) :
|
||||
ball_lc + Vec3(2, 0, 2));
|
||||
}
|
||||
return orig_pos;
|
||||
|
||||
// Now try to make the ball face towards the goal
|
||||
// Aim at upper/lower left/right corner of ball depends on location
|
||||
posData goal_pos = {0};
|
||||
checkPosition(m_world->getGoalLocation(opp_team, CheckGoal::POINT_CENTER),
|
||||
&goal_pos);
|
||||
Vec3 corrected_pos;
|
||||
if (ball_pos.lhs && goal_pos.lhs)
|
||||
{
|
||||
corrected_pos = ball_lc + Vec3(1, 0, 1);
|
||||
}
|
||||
else if (!ball_pos.lhs && !goal_pos.lhs)
|
||||
{
|
||||
corrected_pos = ball_lc - Vec3(1, 0, 0) + Vec3(0, 0, 1);
|
||||
}
|
||||
else if (!ball_pos.lhs && goal_pos.lhs)
|
||||
{
|
||||
corrected_pos = ball_lc + Vec3(1, 0, 0) - Vec3(0, 0, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
corrected_pos = ball_lc - Vec3(1, 0, 1);
|
||||
}
|
||||
if (need_braking)
|
||||
{
|
||||
m_controls->m_brake = true;
|
||||
m_force_brake = true;
|
||||
}
|
||||
return m_kart->getTrans()(corrected_pos);
|
||||
|
||||
} // correctBallPosition
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool SoccerAI::isLikelyToGoal(SoccerTeam team) const
|
||||
{
|
||||
// Use local coordinate for easy compare
|
||||
Vec3 first_pos;
|
||||
Vec3 last_pos;
|
||||
checkPosition(m_world->getGoalLocation(team, CheckGoal::POINT_FIRST),
|
||||
NULL, &first_pos);
|
||||
checkPosition(m_world->getGoalLocation(team, CheckGoal::POINT_LAST),
|
||||
NULL, &last_pos);
|
||||
|
||||
// If the kart lies between the first and last pos, and faces
|
||||
// in front of them, than it's likely to goal
|
||||
if ((first_pos.z() > 0.0f && last_pos.z() > 0.0f) &&
|
||||
((first_pos.x() < 0.0f && last_pos.x() > 0.0f) ||
|
||||
(last_pos.x() < 0.0f && first_pos.x() > 0.0f)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
} // isLikelyToGoal
|
||||
//-----------------------------------------------------------------------------
|
||||
int SoccerAI::getCurrentNode() const
|
||||
{
|
||||
return m_world->getKartNode(m_kart->getWorldKartId());
|
||||
} // getCurrentNode
|
||||
// ------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool SoccerAI::isWaiting() const
|
||||
{
|
||||
return m_world->isStartPhase();
|
||||
|
@ -36,14 +36,17 @@ private:
|
||||
|
||||
SoccerTeam m_cur_team;
|
||||
bool m_saving_ball;
|
||||
bool m_force_brake;
|
||||
|
||||
Vec3 correctBallPosition(const Vec3&);
|
||||
bool isLikelyToGoal(SoccerTeam team) const;
|
||||
|
||||
virtual void findClosestKart(bool use_difficulty);
|
||||
virtual void findTarget();
|
||||
virtual int getCurrentNode() const;
|
||||
virtual bool isWaiting() const;
|
||||
virtual bool canSkid(float steer_fraction) { return m_saving_ball; }
|
||||
virtual bool forceBraking() OVERRIDE { return m_force_brake; }
|
||||
public:
|
||||
SoccerAI(AbstractKart *kart);
|
||||
~SoccerAI();
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include "karts/controller/soccer_ai.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
#include "states_screens/race_gui_base.hpp"
|
||||
#include "tracks/check_goal.hpp"
|
||||
#include "tracks/check_manager.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_object_manager.hpp"
|
||||
@ -54,6 +53,8 @@ SoccerWorld::SoccerWorld() : WorldWithRank()
|
||||
}
|
||||
|
||||
m_use_highscores = false;
|
||||
m_red_ai = 0;
|
||||
m_blue_ai = 0;
|
||||
} // SoccerWorld
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -76,8 +77,11 @@ void SoccerWorld::init()
|
||||
m_display_rank = false;
|
||||
m_goal_timer = 0.0f;
|
||||
m_ball_hitter = -1;
|
||||
m_red_check_goal = NULL;
|
||||
m_blue_check_goal = NULL;
|
||||
m_goal_target = race_manager->getMaxGoal();
|
||||
m_goal_sound = SFXManager::get()->createSoundSource("goal_scored");
|
||||
initGoal();
|
||||
|
||||
} // init
|
||||
|
||||
@ -129,8 +133,7 @@ void SoccerWorld::reset()
|
||||
}
|
||||
|
||||
initKartList();
|
||||
resetAllNodes();
|
||||
initGoalNodes();
|
||||
resetAllPosition();
|
||||
resetBall();
|
||||
|
||||
} // reset
|
||||
@ -355,22 +358,10 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
|
||||
|
||||
if (kart_type == RaceManager::KT_AI)
|
||||
{
|
||||
if (race_manager->getNumPlayers() == 1)
|
||||
{
|
||||
// Make AI even when single player choose a different team
|
||||
if (race_manager->getKartInfo(0).getSoccerTeam() == SOCCER_TEAM_RED)
|
||||
{
|
||||
team = (index % 2 == 0 ? SOCCER_TEAM_BLUE : SOCCER_TEAM_RED);
|
||||
}
|
||||
else
|
||||
{
|
||||
team = (index % 2 == 0 ? SOCCER_TEAM_RED : SOCCER_TEAM_BLUE);
|
||||
}
|
||||
}
|
||||
if (index < m_red_ai)
|
||||
team = SOCCER_TEAM_RED;
|
||||
else
|
||||
{
|
||||
team = (index % 2 == 0 ? SOCCER_TEAM_BLUE : SOCCER_TEAM_RED);
|
||||
}
|
||||
team = SOCCER_TEAM_BLUE;
|
||||
m_kart_team_map[index] = team;
|
||||
}
|
||||
else
|
||||
@ -484,9 +475,7 @@ void SoccerWorld::updateBallPosition(float dt)
|
||||
} // updateBallPosition
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Localize two goals on the navigation mesh.
|
||||
*/
|
||||
void SoccerWorld::initGoalNodes()
|
||||
void SoccerWorld::initGoal()
|
||||
{
|
||||
if (!m_track->hasNavMesh()) return;
|
||||
|
||||
@ -500,20 +489,18 @@ void SoccerWorld::initGoalNodes()
|
||||
{
|
||||
if (goal->getTeam())
|
||||
{
|
||||
m_blue_goal_node = BattleGraph::get()->pointToNode(m_blue_goal_node,
|
||||
goal->convertTo3DCenter(), true/*ignore_vertical*/);
|
||||
m_blue_check_goal = goal;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_red_goal_node = BattleGraph::get()->pointToNode(m_red_goal_node,
|
||||
goal->convertTo3DCenter(), true/*ignore_vertical*/);
|
||||
m_red_check_goal = goal;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // initGoalNodes
|
||||
} // initGoal
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SoccerWorld::resetAllNodes()
|
||||
void SoccerWorld::resetAllPosition()
|
||||
{
|
||||
m_kart_on_node.clear();
|
||||
m_kart_on_node.resize(m_karts.size());
|
||||
@ -521,9 +508,7 @@ void SoccerWorld::resetAllNodes()
|
||||
m_kart_on_node[n] = BattleGraph::UNKNOWN_POLY;
|
||||
m_ball_on_node = BattleGraph::UNKNOWN_POLY;
|
||||
m_ball_position = Vec3(0, 0, 0);
|
||||
m_red_goal_node = BattleGraph::UNKNOWN_POLY;
|
||||
m_blue_goal_node = BattleGraph::UNKNOWN_POLY;
|
||||
} // resetAllNodes
|
||||
} // resetAllPosition
|
||||
//-----------------------------------------------------------------------------
|
||||
SoccerTeam SoccerWorld::getKartTeam(unsigned int kart_id) const
|
||||
{
|
||||
@ -571,9 +556,8 @@ void SoccerWorld::updateDefenders()
|
||||
getKartTeam(m_karts[i]->getWorldKartId()) != SOCCER_TEAM_RED)
|
||||
continue;
|
||||
|
||||
Vec3 d = NavMesh::get()->getNavPoly(this
|
||||
->getGoalNode(SOCCER_TEAM_RED)).getCenter()
|
||||
- m_karts[i]->getXYZ();
|
||||
Vec3 d = this->getGoalLocation(SOCCER_TEAM_RED,
|
||||
CheckGoal::POINT_CENTER) - m_karts[i]->getXYZ();
|
||||
|
||||
if (d.length_2d() <= distance)
|
||||
{
|
||||
@ -593,9 +577,8 @@ void SoccerWorld::updateDefenders()
|
||||
getKartTeam(m_karts[i]->getWorldKartId()) != SOCCER_TEAM_BLUE)
|
||||
continue;
|
||||
|
||||
Vec3 d = NavMesh::get()->getNavPoly(this
|
||||
->getGoalNode(SOCCER_TEAM_BLUE)).getCenter()
|
||||
- m_karts[i]->getXYZ();
|
||||
Vec3 d = this->getGoalLocation(SOCCER_TEAM_BLUE,
|
||||
CheckGoal::POINT_CENTER) - m_karts[i]->getXYZ();
|
||||
|
||||
if (d.length_2d() <= distance)
|
||||
{
|
||||
@ -642,3 +625,52 @@ void SoccerWorld::resetBall()
|
||||
m_ball->reset();
|
||||
m_ball->getPhysicalObject()->reset();
|
||||
} // resetBall
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SoccerWorld::setAITeam()
|
||||
{
|
||||
const int total_player = race_manager->getNumPlayers();
|
||||
const int total_karts = race_manager->getNumberOfKarts();
|
||||
|
||||
// No AI
|
||||
if ((total_karts - total_player) == 0) return;
|
||||
|
||||
int red_player = 0;
|
||||
int blue_player = 0;
|
||||
for (int i = 0; i < total_player; i++)
|
||||
{
|
||||
SoccerTeam team = race_manager->getKartInfo(i).getSoccerTeam();
|
||||
assert(team != SOCCER_TEAM_NONE);
|
||||
team == SOCCER_TEAM_BLUE ? blue_player++ : red_player++;
|
||||
}
|
||||
|
||||
int available_ai = total_karts - red_player - blue_player;
|
||||
while (available_ai > 0)
|
||||
{
|
||||
if ((m_red_ai + red_player) > (m_blue_ai + blue_player))
|
||||
{
|
||||
m_blue_ai++;
|
||||
available_ai--;
|
||||
}
|
||||
else if ((m_blue_ai + blue_player) > (m_red_ai + red_player))
|
||||
{
|
||||
m_red_ai++;
|
||||
available_ai--;
|
||||
}
|
||||
else if ((m_blue_ai + blue_player) == (m_red_ai + red_player))
|
||||
{
|
||||
blue_player > red_player ? m_red_ai++ : m_blue_ai++;
|
||||
available_ai--;
|
||||
}
|
||||
}
|
||||
Log::debug("SoccerWorld","blue AI: %d red AI: %d", m_blue_ai, m_red_ai);
|
||||
|
||||
} // setAITeam
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const Vec3& SoccerWorld::getGoalLocation(SoccerTeam team,
|
||||
CheckGoal::PointLocation point) const
|
||||
{
|
||||
return (team == SOCCER_TEAM_BLUE ? m_blue_check_goal->getPoint(point) :
|
||||
m_red_check_goal->getPoint(point));
|
||||
} // getGoalLocation
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "modes/world_with_rank.hpp"
|
||||
#include "states_screens/race_gui_base.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "tracks/check_goal.hpp"
|
||||
|
||||
#include <IMesh.h>
|
||||
#include <string>
|
||||
@ -85,22 +86,26 @@ private:
|
||||
std::vector<int> m_kart_on_node;
|
||||
int m_ball_on_node;
|
||||
Vec3 m_ball_position;
|
||||
int m_red_goal_node;
|
||||
int m_blue_goal_node;
|
||||
|
||||
CheckGoal* m_red_check_goal;
|
||||
CheckGoal* m_blue_check_goal;
|
||||
|
||||
int m_red_defender;
|
||||
int m_blue_defender;
|
||||
|
||||
int m_red_ai;
|
||||
int m_blue_ai;
|
||||
|
||||
/** Set the team for the karts */
|
||||
void initKartList();
|
||||
/** Function to init the locations of two goals on the polygon map */
|
||||
void initGoalNodes();
|
||||
/** Function to save check goal for the getting of coordinate */
|
||||
void initGoal();
|
||||
/** Function to update the locations of all karts on the polygon map */
|
||||
void updateKartNodes();
|
||||
/** Function to update the location the ball on the polygon map */
|
||||
void updateBallPosition(float dt);
|
||||
/** Clean up */
|
||||
void resetAllNodes();
|
||||
void resetAllPosition();
|
||||
/** Reset the ball to original starting position. */
|
||||
void resetBall();
|
||||
/** Function to update the AI which is the closest to its goal to defend. */
|
||||
@ -166,17 +171,18 @@ public:
|
||||
const Vec3& getBallPosition() const
|
||||
{ return m_ball_position; }
|
||||
// ------------------------------------------------------------------------
|
||||
const int getGoalNode(SoccerTeam team) const
|
||||
{
|
||||
return (team == SOCCER_TEAM_BLUE ? m_blue_goal_node : m_red_goal_node);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
bool isCorrectGoal(unsigned int kart_id, bool first_goal) const;
|
||||
// ------------------------------------------------------------------------
|
||||
const int getDefender(SoccerTeam team) const
|
||||
{
|
||||
return (team == SOCCER_TEAM_BLUE ? m_blue_defender : m_red_defender);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void setAITeam();
|
||||
// ------------------------------------------------------------------------
|
||||
const Vec3& getGoalLocation(SoccerTeam team,
|
||||
CheckGoal::PointLocation point) const;
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
}; // SoccerWorld
|
||||
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "modes/overworld.hpp"
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "modes/soccer_world.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "physics/btKart.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
@ -191,6 +192,11 @@ void World::init()
|
||||
m_karts.push_back(ReplayPlay::get()->getGhostKart(k));
|
||||
}
|
||||
|
||||
// Assign team of AIs for soccer mode before createKart
|
||||
SoccerWorld* sw = dynamic_cast<SoccerWorld*>(this);
|
||||
if (sw)
|
||||
sw->setAITeam();
|
||||
|
||||
for(unsigned int i=0; i<num_karts; i++)
|
||||
{
|
||||
if (race_manager->getKartType(i) == RaceManager::KT_GHOST) continue;
|
||||
|
@ -329,7 +329,7 @@ void GrandPrixData::reload()
|
||||
throw std::runtime_error("Missing track id");
|
||||
}
|
||||
|
||||
if (number_of_laps < 1)
|
||||
if (number_of_laps < 1 && !UserConfigParams::m_artist_debug_mode)
|
||||
{
|
||||
Log::error("GrandPrixData",
|
||||
"Track '%s' in the Grand Prix file '%s' should be raced "
|
||||
|
@ -148,8 +148,6 @@ EventPropagation FocusDispatcher::focused(const int player_id)
|
||||
return GUIEngine::EVENT_LET;
|
||||
} // focused
|
||||
|
||||
static FocusDispatcher *g_dispatcher = NULL;
|
||||
|
||||
#if 0
|
||||
#pragma mark -
|
||||
#pragma mark KartHoverListener
|
||||
@ -229,6 +227,7 @@ bool sameKart(const PlayerKartWidget& player1, const PlayerKartWidget& player2)
|
||||
|
||||
KartSelectionScreen::KartSelectionScreen(const char* filename) : Screen(filename)
|
||||
{
|
||||
m_dispatcher = NULL;
|
||||
m_removed_widget = NULL;
|
||||
m_multiplayer_message = NULL;
|
||||
m_from_overworld = false;
|
||||
@ -246,8 +245,8 @@ KartSelectionScreen* KartSelectionScreen::getRunningInstance()
|
||||
|
||||
void KartSelectionScreen::loadedFromFile()
|
||||
{
|
||||
g_dispatcher = new FocusDispatcher(this);
|
||||
m_first_widget = g_dispatcher;
|
||||
m_dispatcher = new FocusDispatcher(this);
|
||||
m_first_widget = m_dispatcher;
|
||||
m_game_master_confirmed = false;
|
||||
m_multiplayer_message = NULL;
|
||||
// Dynamically add tabs
|
||||
@ -305,6 +304,7 @@ void KartSelectionScreen::beforeAddingWidget()
|
||||
|
||||
void KartSelectionScreen::init()
|
||||
{
|
||||
m_instance_ptr = this;
|
||||
Screen::init();
|
||||
m_must_delete_on_back = false;
|
||||
|
||||
@ -318,17 +318,17 @@ void KartSelectionScreen::init()
|
||||
|
||||
// FIXME : The reserved id value is -1 when we switch from KSS to NKSS and vice-versa
|
||||
|
||||
g_dispatcher->setRootID(placeholder->m_reserved_id);
|
||||
m_dispatcher->setRootID(placeholder->m_reserved_id);
|
||||
|
||||
g_root_id = placeholder->m_reserved_id;
|
||||
if (!m_widgets.contains(g_dispatcher))
|
||||
if (!m_widgets.contains(m_dispatcher))
|
||||
{
|
||||
m_widgets.push_back(g_dispatcher);
|
||||
m_widgets.push_back(m_dispatcher);
|
||||
|
||||
// this is only needed if the dispatcher wasn't already in
|
||||
// the list of widgets. If it already was, it was added along
|
||||
// other widgets.
|
||||
g_dispatcher->add();
|
||||
m_dispatcher->add();
|
||||
}
|
||||
|
||||
m_game_master_confirmed = false;
|
||||
@ -426,7 +426,7 @@ void KartSelectionScreen::tearDown()
|
||||
void KartSelectionScreen::unloaded()
|
||||
{
|
||||
// these pointer is no more valid (have been deleted along other widgets)
|
||||
g_dispatcher = NULL;
|
||||
m_dispatcher = NULL;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -439,7 +439,7 @@ bool KartSelectionScreen::joinPlayer(InputDevice* device)
|
||||
Log::info("KartSelectionScreen", "joinPlayer() invoked");
|
||||
if (!m_multiplayer && !first_player) return false;
|
||||
|
||||
assert (g_dispatcher != NULL);
|
||||
assert (m_dispatcher != NULL);
|
||||
|
||||
DynamicRibbonWidget* w = getWidget<DynamicRibbonWidget>("karts");
|
||||
if (w == NULL)
|
||||
|
@ -36,6 +36,7 @@ namespace Online
|
||||
class OnlineProfile;
|
||||
}
|
||||
|
||||
class FocusDispatcher;
|
||||
class InputDevice;
|
||||
class KartHoverListener;
|
||||
|
||||
@ -79,6 +80,8 @@ protected:
|
||||
/** Message shown in multiplayer mode */
|
||||
GUIEngine::BubbleWidget* m_multiplayer_message;
|
||||
|
||||
FocusDispatcher *m_dispatcher;
|
||||
|
||||
KartSelectionScreen(const char* filename);
|
||||
|
||||
/** Called when all players selected their kart */
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "modes/cutscene_world.hpp"
|
||||
#include "modes/overworld.hpp"
|
||||
#include "modes/demo_world.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "online/request_manager.hpp"
|
||||
#include "states_screens/addons_screen.hpp"
|
||||
#include "states_screens/credits.hpp"
|
||||
@ -385,7 +386,8 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name,
|
||||
#endif
|
||||
if (selection == "new")
|
||||
{
|
||||
KartSelectionScreen* s = OfflineKartSelectionScreen::getInstance(); //FIXME : that was for tests
|
||||
NetworkConfig::get()->unsetNetworking();
|
||||
KartSelectionScreen* s = OfflineKartSelectionScreen::getInstance();
|
||||
s->setMultiplayer(false);
|
||||
s->setFromOverworld(false);
|
||||
s->push();
|
||||
@ -393,6 +395,7 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name,
|
||||
else if (selection == "multiplayer")
|
||||
{
|
||||
KartSelectionScreen* s = OfflineKartSelectionScreen::getInstance();
|
||||
NetworkConfig::get()->unsetNetworking();
|
||||
s->setMultiplayer(true);
|
||||
s->setFromOverworld(false);
|
||||
s->push();
|
||||
|
@ -44,7 +44,6 @@ DEFINE_SCREEN_SINGLETON( NetworkKartSelectionScreen );
|
||||
NetworkKartSelectionScreen::NetworkKartSelectionScreen()
|
||||
: KartSelectionScreen("karts_online.stkgui")
|
||||
{
|
||||
KartSelectionScreen::m_instance_ptr = this;
|
||||
} // NetworkKartSelectionScreen
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -21,7 +21,6 @@ DEFINE_SCREEN_SINGLETON( OfflineKartSelectionScreen );
|
||||
|
||||
OfflineKartSelectionScreen::OfflineKartSelectionScreen() : KartSelectionScreen("karts.stkgui")
|
||||
{
|
||||
KartSelectionScreen::m_instance_ptr = this;
|
||||
}
|
||||
|
||||
OfflineKartSelectionScreen::~OfflineKartSelectionScreen()
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include "io/file_manager.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "karts/controller/end_controller.hpp"
|
||||
#include "karts/controller/local_player_controller.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "modes/cutscene_world.hpp"
|
||||
@ -384,10 +386,6 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
|
||||
{
|
||||
race_manager->exitRace();
|
||||
race_manager->setAIKartOverride("");
|
||||
// FIXME: why is this call necessary here? tearDown should be
|
||||
// automatically called when the screen is left. Note that the
|
||||
// NetworkKartSelectionScreen::getInstance()->tearDown(); caused #1347
|
||||
KartSelectionScreen::getRunningInstance()->tearDown();
|
||||
Screen* newStack[] = { MainMenuScreen::getInstance(),
|
||||
RaceSetupScreen::getInstance(),
|
||||
NULL };
|
||||
@ -401,11 +399,6 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
|
||||
{
|
||||
race_manager->exitRace();
|
||||
race_manager->setAIKartOverride("");
|
||||
// FIXME: why is this call necessary here? tearDown should be
|
||||
// automatically called when the screen is left. Note that the
|
||||
// NetworkKartSelectionScreen::getInstance()->tearDown(); caused #1347
|
||||
//if (KartSelectionScreen::getRunningInstance() != NULL)
|
||||
// KartSelectionScreen::getRunningInstance()->tearDown();
|
||||
StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
|
||||
|
||||
if (race_manager->raceWasStartedFromOverworld())
|
||||
@ -492,15 +485,7 @@ void RaceResultGUI::backToLobby()
|
||||
// Save a pointer to the current row_info entry
|
||||
RowInfo *ri = &(m_all_row_infos[position - first_position]);
|
||||
ri->m_is_player_kart = kart->getController()->isLocalPlayerController();
|
||||
|
||||
// Identify Human player, if so display real name other than kart name
|
||||
const int rm_id = kart->getWorldKartId() -
|
||||
(race_manager->getNumberOfKarts() - race_manager->getNumPlayers());
|
||||
|
||||
if (rm_id >= 0 && !race_manager->isWatchingReplay())
|
||||
ri->m_kart_name = race_manager->getKartInfo(rm_id).getPlayerName();
|
||||
else
|
||||
ri->m_kart_name = translations->fribidize(kart->getName());
|
||||
ri->m_kart_name = getKartDisplayName(kart);
|
||||
|
||||
video::ITexture *icon =
|
||||
kart->getKartProperties()->getIconMaterial()->getTexture();
|
||||
@ -865,16 +850,8 @@ void RaceResultGUI::backToLobby()
|
||||
RowInfo *ri = &(m_all_row_infos[rank]);
|
||||
ri->m_kart_icon =
|
||||
kart->getKartProperties()->getIconMaterial()->getTexture();
|
||||
|
||||
const int rm_id = kart_id -
|
||||
(race_manager->getNumberOfKarts() - race_manager->getNumPlayers());
|
||||
|
||||
if (rm_id >= 0 && !race_manager->isWatchingReplay())
|
||||
ri->m_kart_name = race_manager->getKartInfo(rm_id).getPlayerName();
|
||||
else
|
||||
ri->m_kart_name = translations->fribidize(kart->getName());
|
||||
|
||||
ri->m_is_player_kart = kart->getController()->isLocalPlayerController();
|
||||
ri->m_kart_name = getKartDisplayName(kart);
|
||||
|
||||
// In FTL karts do have a time, which is shown even when the kart
|
||||
// is eliminated
|
||||
@ -925,6 +902,29 @@ void RaceResultGUI::backToLobby()
|
||||
} // i < num_karts
|
||||
} // determineGPLayout
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns a string to display next to a kart. For a player that's the name
|
||||
* of the player, for an AI kart it's the name of the driver.
|
||||
*/
|
||||
core::stringw RaceResultGUI::getKartDisplayName(const AbstractKart *kart) const
|
||||
{
|
||||
const EndController *ec =
|
||||
dynamic_cast<const EndController*>(kart->getController());
|
||||
// If the race was given up, there is no end controller for the
|
||||
// players, so this case needs to be handled separately
|
||||
if(ec && ec->isLocalPlayerController())
|
||||
return ec->getName();
|
||||
else
|
||||
{
|
||||
// No end controller, check explicitely for a player controller
|
||||
const PlayerController *pc =
|
||||
dynamic_cast<const PlayerController*>(kart->getController());
|
||||
// Check if the kart is a player controller to get the real name
|
||||
if(pc) return pc->getName();
|
||||
}
|
||||
return translations->fribidize(kart->getName());
|
||||
} // getKartDisplayName
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Displays the race results for a single kart.
|
||||
* \param n Index of the kart to be displayed.
|
||||
@ -1102,6 +1102,7 @@ void RaceResultGUI::backToLobby()
|
||||
if (own_goal)
|
||||
{
|
||||
result_text.append(" ");
|
||||
//I18N: indicates a player that scored in their own goal in result screen
|
||||
result_text.append(_("(Own Goal)"));
|
||||
}
|
||||
|
||||
|
@ -194,6 +194,7 @@ private:
|
||||
void displayHighScores();
|
||||
void displaySoccerResults();
|
||||
void displayScreenShots();
|
||||
irr::core::stringw getKartDisplayName(const AbstractKart *kart) const;
|
||||
|
||||
int getFontHeight () const;
|
||||
|
||||
|
@ -37,12 +37,12 @@ CheckGoal::CheckGoal(const XMLNode &node, unsigned int index)
|
||||
m_first_goal = false;
|
||||
node.get("first_goal", &m_first_goal);
|
||||
|
||||
Vec3 p1, p2;
|
||||
node.get("p1", &p1);
|
||||
node.get("p2", &p2);
|
||||
node.get("p1", &m_p1);
|
||||
node.get("p2", &m_p3);
|
||||
|
||||
m_line.setLine( core::vector2df(p1.getX(), p1.getZ()),
|
||||
core::vector2df(p2.getX(), p2.getZ()) );
|
||||
m_line.setLine( core::vector2df(m_p1.getX(), m_p1.getZ()),
|
||||
core::vector2df(m_p3.getX(), m_p3.getZ()) );
|
||||
m_p2 = (m_p1 + m_p3) / 2;
|
||||
} // CheckGoal
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -113,11 +113,3 @@ void CheckGoal::reset(const Track &track)
|
||||
}
|
||||
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
Vec3 CheckGoal::convertTo3DCenter() const
|
||||
{
|
||||
float x = m_line.getMiddle().X;
|
||||
float y = m_line.getMiddle().Y;
|
||||
return Vec3(x, 0, y);
|
||||
}
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include <line2d.h>
|
||||
using namespace irr;
|
||||
|
||||
class CheckManager;
|
||||
class XMLNode;
|
||||
class Track;
|
||||
class Vec3;
|
||||
@ -37,6 +36,14 @@ class Vec3;
|
||||
*/
|
||||
class CheckGoal : public CheckStructure
|
||||
{
|
||||
public:
|
||||
/** Used by AIs to test whether the ball is likely to goal. */
|
||||
enum PointLocation
|
||||
{
|
||||
POINT_FIRST,
|
||||
POINT_CENTER,
|
||||
POINT_LAST
|
||||
};
|
||||
private:
|
||||
/** Previois ball position. */
|
||||
Vec3 m_previous_ball_position;
|
||||
@ -47,6 +54,11 @@ private:
|
||||
/** The line that is tested for being crossed. */
|
||||
core::line2df m_line;
|
||||
|
||||
/** Used by AIs to test whether the ball is likely to goal. */
|
||||
Vec3 m_p1;
|
||||
Vec3 m_p2;
|
||||
Vec3 m_p3;
|
||||
|
||||
public:
|
||||
CheckGoal(const XMLNode &node, unsigned int index);
|
||||
virtual ~CheckGoal() {}
|
||||
@ -59,7 +71,11 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
bool getTeam() const { return m_first_goal; }
|
||||
// ------------------------------------------------------------------------
|
||||
Vec3 convertTo3DCenter() const;
|
||||
}; // CheckLine
|
||||
const Vec3& getPoint(PointLocation point) const
|
||||
{
|
||||
return (point == POINT_LAST ? m_p3 :
|
||||
(point == POINT_CENTER ? m_p2 : m_p1));
|
||||
}
|
||||
}; // CheckGoal
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user