Allow changing the various levels of AI mostly using

the stk_config file.
Note at this stage no tuning of easy or medium level was
done, this version should behave the same as the hard-coded
version.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@11736 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2012-10-22 21:51:05 +00:00
parent 6058c3bcfc
commit ecc1212c11
12 changed files with 225 additions and 196 deletions

View File

@ -215,6 +215,23 @@
reduce-turn-min="0.2" reduce-turn-max="0.8"/>
<!-- Kart-specific settings used by the AI.
use-slipstream: if the AI should try to overtake karts using slipstream.
false-start-probability: Probability of a false start.
min/max-start-delay: Minimum and maximum start delay.
See http://www.humanbenchmark.com/tests/reactiontime/stats.php
Average reaction time is around 0.215 s.
nitro-usage: "none", "some", "all": if nitro should be used, and
how much the AI should try to use it good.
non-random-item-usage: If true, use items in a sophisticated way,
otherwise use items randomly.
collect-avoid-items: if the AI should collect and avoid items,
or just ignore them.
handle-bomb: If the AI should actively try to pass on a bomb.
skidding-threshold: only for old-style skidding: when sharp turn
should be triggered. Smaller values means it will sharp turn
earlier, resulting in better driving in thight curves.
max-item-angle: Items that would need more than this change in
direction are not considered for collection.
time-full-steer is the time for the AI to go from neutral steering to
@ -254,13 +271,50 @@
Note that setting this to a value >1 does NOT increase
the speed the kart can drive at!
-->
<ai max-item-angle="0.7" max-item-angle-high-speed="0.3"
<ai>
<easy use-slipstream="false"
false-start-probability="0.08"
min-start-delay="0.3" max-start-delay="0.5"
nitro-usage="none"
non-random-item-usage="false"
collect-avoid-items="false"
handle-bomb="false"
skidding-threshold="4.0"
max-item-angle="0.7" max-item-angle-high-speed="0.3"
time-full-steer="0.1"
bad-item-closeness="6"
straight-length-for-zipper="35"
rb-skid-probability="-50:1.0 -20:0.7 20:0.2 50:0.0"
speed-cap="10:1.0 50:0.8"/>
<medium use-slipstream="false"
false-start-probability="0.04"
min-start-delay="0.25" max-start-delay="0.4"
nitro-usage="some"
non-random-item-usage="false"
collect-avoid-items="true"
handle-bomb="false"
skidding-threshold="3.0"
max-item-angle="0.7" max-item-angle-high-speed="0.3"
time-full-steer="0.1"
bad-item-closeness="6"
straight-length-for-zipper="35"
rb-skid-probability="-50:1.0 -20:0.7 20:0.2 50:0.0"
speed-cap="10:1.0 50:0.8"/>
<hard use-slipstream="true"
false-start-probability="0.01"
min-start-delay="0.15" max-start-delay="0.28"
nitro-usage="all"
non-random-item-usage="false"
collect-avoid-items="true"
handle-bomb="true"
skidding-threshold="2.0"
max-item-angle="0.7" max-item-angle-high-speed="0.3"
time-full-steer="0.1"
bad-item-closeness="6"
straight-length-for-zipper="35"
rb-skid-probability="-50:1.0 -20:0.7 20:0.2 50:0.0"
speed-cap="10:1.0 50:0.8"/>
</ai>
<!-- Slipstream: length: How far behind a kart slipstream works
collect-time: How many seconds of sstream give maximum benefit
use-time: How long the benefit will last.

View File

@ -38,7 +38,8 @@ AIBaseController::AIBaseController(AbstractKart *kart,
m_kart = kart;
m_kart_length = m_kart->getKartLength();
m_kart_width = m_kart->getKartWidth();
m_ai_properties = m_kart->getKartProperties()->getAIProperties();
m_ai_properties =
m_kart->getKartProperties()->getAIPropertiesForDifficulty();
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES)
{
@ -283,19 +284,6 @@ float AIBaseController::steerToAngle(const unsigned int sector,
return steer_angle;
} // steerToAngle
//-----------------------------------------------------------------------------
/** Sets when skidding will be used: when the ratio of steering angle to
* maximumn steering angle is larger than the fraction set here,
* skidding will be used. This is used to set more aggressive skidding
* for higher level AIs.
* \param f Fraction with which steering angle / max steering angle is
* compared to determine if skidding is used.
*/
void AIBaseController::setSkiddingFraction(float f)
{
m_skidding_threshold = f;
} // setSkiddingFactor
//-----------------------------------------------------------------------------
/** Computes the steering angle to reach a certain point. The function will
* request steering by setting the steering angle to maximum steer angle
@ -331,9 +319,11 @@ float AIBaseController::steerToPoint(const Vec3 &point)
// steer function will request skidding. 0.1 is added in case
// of floating point errors.
if(lc.getX()>0)
return m_kart->getMaxSteerAngle()*m_skidding_threshold+0.1f;
return m_kart->getMaxSteerAngle()
*m_ai_properties->m_skidding_threshold+0.1f;
else
return -m_kart->getMaxSteerAngle()*m_skidding_threshold-0.1f;
return -m_kart->getMaxSteerAngle()
*m_ai_properties->m_skidding_threshold-0.1f;
}
// Now compute the nexessary radius for the turn. After getting the
@ -354,9 +344,11 @@ float AIBaseController::steerToPoint(const Vec3 &point)
// If the wheel base is too long (i.e. the minimum radius is too large
// to actually reach the target), make sure that skidding is used
if(sin_steer_angle <= -1.0f)
return -m_kart->getMaxSteerAngle()*m_skidding_threshold-0.1f;
return -m_kart->getMaxSteerAngle()
*m_ai_properties->m_skidding_threshold-0.1f;
if(sin_steer_angle >= 1.0f)
return m_kart->getMaxSteerAngle()*m_skidding_threshold+0.1f;
return m_kart->getMaxSteerAngle()
*m_ai_properties->m_skidding_threshold+0.1f;
float steer_angle = asin(sin_steer_angle);
// After doing the exact computation, we now return an 'oversteered'
@ -456,5 +448,5 @@ bool AIBaseController::doSkid(float steer_fraction)
// Otherwise return if we need a sharp turn (which is
// for the old skidding implementation).
return fabsf(steer_fraction)>=m_skidding_threshold;
return fabsf(steer_fraction)>=m_ai_properties->m_skidding_threshold;
} // doSkid

View File

@ -34,12 +34,6 @@ class Vec3;
class AIBaseController : public Controller
{
private:
/** The minimum steering angle at which the AI adds skidding. Lower values
* tend to improve the line the AI is driving. This is used to adjust for
* different AI levels.
*/
float m_skidding_threshold;
/** Stores the last N times when a collision happened. This is used
* to detect when the AI is stuck, i.e. N collisions happened in
* a certain period of time. */
@ -91,7 +85,6 @@ protected:
float steerToAngle (const unsigned int sector, const float angle);
float steerToPoint (const Vec3 &point);
float normalizeAngle(float angle);
void setSkiddingFraction(float f);
void computePath();
virtual bool doSkid(float steer_fraction);
// ------------------------------------------------------------------------

View File

@ -25,15 +25,33 @@ float AIProperties::UNDEFINED = -99.9f;
/** Constructor. Sets all properties to the special UNDEFINED value.
*/
AIProperties::AIProperties()
AIProperties::AIProperties(RaceManager::Difficulty difficulty)
: m_skid_probability(/*decreasing*/false)
, m_speed_cap(/*decreasing*/true)
{
switch(difficulty)
{
case RaceManager::DIFFICULTY_EASY: m_ident="easy"; break;
case RaceManager::DIFFICULTY_MEDIUM: m_ident="medium"; break;
case RaceManager::DIFFICULTY_HARD: m_ident="hard"; break;
default: m_ident=""; break;
}
m_max_item_angle = UNDEFINED;
m_max_item_angle_high_speed = UNDEFINED;
m_time_full_steer = UNDEFINED;
m_bad_item_closeness_2 = UNDEFINED;
m_straight_length_for_zipper = UNDEFINED;
m_skidding_threshold = UNDEFINED;
m_min_start_delay = UNDEFINED;
m_max_start_delay = UNDEFINED;
m_false_start_probability = UNDEFINED;
m_make_use_of_slipstream = false;
m_collect_avoid_items = false;
m_handle_bomb = false;
m_item_usage_non_random = false;
m_nitro_usage = NITRO_NONE;
} // AIProperties
// ----------------------------------------------------------------------------
@ -42,6 +60,7 @@ AIProperties::AIProperties()
*/
void AIProperties::load(const XMLNode *ai_node)
{
ai_node->get("use-slipstream", &m_make_use_of_slipstream );
ai_node->get("max-item-angle", &m_max_item_angle );
ai_node->get("max-item-angle-high-speed", &m_max_item_angle_high_speed );
ai_node->get("time-full-steer", &m_time_full_steer );
@ -49,7 +68,28 @@ void AIProperties::load(const XMLNode *ai_node)
ai_node->get("straight-length-for-zipper",&m_straight_length_for_zipper);
ai_node->get("rb-skid-probability", &m_skid_probability );
ai_node->get("speed-cap", &m_speed_cap );
ai_node->get("non-random-item-usage", &m_item_usage_non_random );
ai_node->get("collect-avoid-items", &m_collect_avoid_items );
ai_node->get("handle-bomb", &m_handle_bomb );
ai_node->get("skidding-threshold", &m_skidding_threshold );
ai_node->get("false-start-probability", &m_false_start_probability );
ai_node->get("min-start-delay", &m_min_start_delay );
ai_node->get("max-start-delay", &m_max_start_delay );
std::string s;
ai_node->get("nitro-usage", &s);
if(s=="none")
m_nitro_usage = NITRO_NONE;
else if(s=="some")
m_nitro_usage = NITRO_SOME;
else if(s=="all")
m_nitro_usage = NITRO_ALL;
else
{
printf("Incorrect nitro-usage '%s' in AI '%s'.\n",s.c_str(),
m_ident.c_str());
exit(-1);
}
// We actually need the square of the distance later
m_bad_item_closeness_2 *= m_bad_item_closeness_2;
@ -63,14 +103,20 @@ void AIProperties::load(const XMLNode *ai_node)
void AIProperties::checkAllSet(const std::string &filename) const
{
#define CHECK_NEG( a,str_a) if(a<=UNDEFINED) { \
fprintf(stderr,"Missing default value for '%s' in '%s'.\n", \
str_a,filename.c_str());exit(-1); \
fprintf(stderr,"Missing default value for '%s' in '%s' " \
"'for AI '%s'.\n", \
str_a,filename.c_str(), \
m_ident.c_str());exit(-1); \
}
CHECK_NEG(m_max_item_angle, "max-item-angle" );
CHECK_NEG(m_max_item_angle_high_speed, "max-item-angle-high-speed" );
CHECK_NEG(m_time_full_steer, "time-full-steer" );
CHECK_NEG(m_bad_item_closeness_2, "bad-item-closeness" );
CHECK_NEG(m_straight_length_for_zipper,"straight-length-for-zipper");
CHECK_NEG(m_skidding_threshold, "skidding-threshold" );
CHECK_NEG(m_false_start_probability, "false-start-probability" );
CHECK_NEG(m_min_start_delay, "min-start-delay" );
CHECK_NEG(m_max_start_delay, "max-start-delay" );
if(m_skid_probability.size()==0)
{

View File

@ -19,6 +19,7 @@
#ifndef HEADER_AI_PROPERTIES_HPP
#define HEADER_AI_PROPERTIES_HPP
#include "race/race_manager.hpp"
#include "utils/interpolation_array.hpp"
#include <string>
@ -76,9 +77,44 @@ protected:
/** To cap maximum speed if the kart is ahead of the player. */
InterpolationArray m_speed_cap;
/** Probability of a false start. Note that Nolok in boss battle will never
* have a false start. */
float m_false_start_probability;
/** Minimum start delay. */
float m_min_start_delay;
/** Maximum start delay. */
float m_max_start_delay;
/** True if the AI should avtively try to make use of slipstream. */
bool m_make_use_of_slipstream;
/** Actively collect and avoid items. */
bool m_collect_avoid_items;
/** If the AI should actively try to pass on a bomb. */
bool m_handle_bomb;
/** True if items should be used better (i.e. non random). */
bool m_item_usage_non_random;
/** How the AI uses nitro. */
enum {NITRO_NONE, NITRO_SOME, NITRO_ALL} m_nitro_usage;
/** TODO: ONLY USE FOR OLD SKIDDING! CAN BE REMOVED once the new skidding
* works as expected.
* The minimum steering angle at which the AI adds skidding. Lower values
* tend to improve the line the AI is driving. This is used to adjust for
* different AI levels. */
float m_skidding_threshold;
/** An identifier like 'easy', 'medium' or 'hard' for this data set. */
std::string m_ident;
public:
AIProperties();
AIProperties(RaceManager::Difficulty difficulty);
void load(const XMLNode *skid_node);
void checkAllSet(const std::string &filename) const;
// ------------------------------------------------------------------------

View File

@ -71,7 +71,6 @@ DefaultAIController::DefaultAIController(AbstractKart *kart)
m_min_steps = 1;
m_nitro_level = NITRO_NONE;
m_handle_bomb = false;
setSkiddingFraction(4.0f);
break;
case RaceManager::DIFFICULTY_MEDIUM:
m_wait_for_players = true;
@ -84,7 +83,6 @@ DefaultAIController::DefaultAIController(AbstractKart *kart)
m_min_steps = 1;
m_nitro_level = NITRO_SOME;
m_handle_bomb = true;
setSkiddingFraction(3.0f);
break;
case RaceManager::DIFFICULTY_HARD:
m_wait_for_players = false;
@ -100,7 +98,6 @@ DefaultAIController::DefaultAIController(AbstractKart *kart)
m_min_steps = 2;
m_nitro_level = NITRO_ALL;
m_handle_bomb = true;
setSkiddingFraction(2.0f);
break;
case RaceManager::DIFFICULTY_COUNT:
assert(0); // keep the compiler happy

View File

@ -97,7 +97,6 @@ EndController::EndController(AbstractKart *kart, StateManager::ActivePlayer *pla
m_max_handicap_accel = 1.0f;
m_min_steps = 2;
setSkiddingFraction(1.3f);
#ifdef AI_DEBUG
m_debug_sphere = irr_driver->getSceneManager()->addSphereSceneNode(1);

View File

@ -74,7 +74,6 @@ PresentAI::PresentAI(AbstractKart *kart)
m_min_steps = 1;
m_nitro_level = NITRO_NONE;
m_handle_bomb = false;
setSkiddingFraction(4.0f);
break;
case RaceManager::DIFFICULTY_MEDIUM:
m_wait_for_players = true;
@ -87,7 +86,6 @@ PresentAI::PresentAI(AbstractKart *kart)
m_min_steps = 1;
m_nitro_level = NITRO_SOME;
m_handle_bomb = true;
setSkiddingFraction(3.0f);
break;
case RaceManager::DIFFICULTY_HARD:
m_wait_for_players = false;
@ -103,7 +101,6 @@ PresentAI::PresentAI(AbstractKart *kart)
m_min_steps = 2;
m_nitro_level = NITRO_ALL;
m_handle_bomb = true;
setSkiddingFraction(2.0f);
break;
case RaceManager::DIFFICULTY_COUNT:
assert(0); // keep the compiler happy

View File

@ -81,56 +81,8 @@ SkiddingAI::SkiddingAI(AbstractKart *kart)
{
reset();
switch( race_manager->getDifficulty())
{
case RaceManager::DIFFICULTY_EASY:
m_wait_for_players = true;
m_make_use_of_slipstream = false;
m_max_handicap_speed = 0.9f;
m_false_start_probability = 0.08f;
m_min_start_delay = 0.3f;
m_max_start_delay = 0.5f;
m_min_steps = 1;
m_item_tactic = IT_TEN_SECONDS;
m_nitro_level = NITRO_NONE;
m_item_behaviour = ITEM_COLLECT_NONE;
m_handle_bomb = false;
setSkiddingFraction(4.0f);
break;
case RaceManager::DIFFICULTY_MEDIUM:
m_wait_for_players = true;
m_make_use_of_slipstream = false;
m_max_handicap_speed = 0.95f;
m_false_start_probability = 0.04f;
m_min_start_delay = 0.25f;
m_max_start_delay = 0.4f;
m_min_steps = 1;
m_item_tactic = IT_CALCULATE;
m_nitro_level = NITRO_SOME;
m_item_behaviour = ITEM_COLLECT_NONE;
m_handle_bomb = true;
setSkiddingFraction(3.0f);
break;
case RaceManager::DIFFICULTY_HARD:
m_wait_for_players = false;
m_make_use_of_slipstream = true;
m_max_handicap_speed = 1.0f;
m_item_tactic = IT_CALCULATE;
m_false_start_probability = 0.01f;
// See http://www.humanbenchmark.com/tests/reactiontime/stats.php
// Average reaction time is around 0.215 s, so using .15 as minimum
// gives an AI average slightly above the human average
m_min_start_delay = 0.15f;
m_max_start_delay = 0.28f;
m_min_steps = 2;
m_nitro_level = NITRO_ALL;
m_item_behaviour = ITEM_COLLECT_PRIORITY;
m_handle_bomb = true;
setSkiddingFraction(2.0f);
break;
case RaceManager::DIFFICULTY_COUNT:
assert(0); // keep the compiler happy
}
m_superpower = race_manager->getAISuperPower();
m_point_selection_algorithm = PSA_DEFAULT;
setControllerName("Skidding");
@ -149,11 +101,6 @@ SkiddingAI::SkiddingAI(AbstractKart *kart)
setControllerName(name);
#endif
m_superpower = race_manager->getAISuperPower();
if (m_superpower == RaceManager::SUPERPOWER_NOLOK_BOSS)
{
m_false_start_probability = 0.0f;
}
#ifdef AI_DEBUG
for(unsigned int i=0; i<4; i++)
{
@ -183,10 +130,7 @@ SkiddingAI::SkiddingAI(AbstractKart *kart)
#endif
#ifdef AI_DEBUG_KART_HEADING
irr::video::SColor c;
if(m_item_behaviour == ITEM_COLLECT_PRIORITY)
c = irr::video::SColor(128, 0, 0, 128);
else
c = irr::video::SColor(128, 0, 128, 0);
m_curve[CURVE_KART] = new ShowCurve(0.5f, 0.5f, c);
#endif
#ifdef AI_DEBUG_NEW_FIND_NON_CRASHING
@ -199,10 +143,7 @@ SkiddingAI::SkiddingAI(AbstractKart *kart)
video::SColor(128, 0, 128, 0));
#ifdef AI_DEBUG_KART_AIM
irr::video::SColor c1;
if(m_item_behaviour == ITEM_COLLECT_PRIORITY)
c1 = irr::video::SColor(128, 0, 0, 128);
else
c1 = irr::video::SColor(128, 0, 128, 0);
m_curve[CURVE_AIM] = new ShowCurve(0.5f, 0.5f, c1);
#endif
@ -370,7 +311,7 @@ void SkiddingAI::update(float dt)
// Special behaviour if we have a bomb attach: try to hit the kart ahead
// of us.
bool commands_set = false;
if(m_handle_bomb &&
if(m_ai_properties->m_handle_bomb &&
m_kart->getAttachment()->getType()==Attachment::ATTACH_BOMB &&
m_kart_ahead )
{
@ -595,7 +536,7 @@ void SkiddingAI::handleSteering(float dt)
// Potentially adjust the point to aim for in order to either
// aim to collect item, or steer to avoid a bad item.
if(m_item_behaviour!=ITEM_COLLECT_NONE)
if(m_ai_properties->m_collect_avoid_items)
handleItemCollectionAndAvoidance(&aim_point, last_node);
steer_angle = steerToPoint(aim_point);
@ -1176,7 +1117,7 @@ void SkiddingAI::handleItems(const float dt)
// Tactic 1: wait ten seconds, then use item
// -----------------------------------------
if(m_item_tactic==IT_TEN_SECONDS)
if(!m_ai_properties->m_item_usage_non_random)
{
if( m_time_since_last_shot > 10.0f )
{
@ -1424,18 +1365,6 @@ void SkiddingAI::handleAcceleration( const float dt)
}
m_controls->m_accel = stk_config->m_ai_acceleration;
if(!m_wait_for_players)
return;
//Find if any player is ahead of this kart
for(unsigned int i = 0; i < race_manager->getNumPlayers(); ++i )
{
if( m_kart->getPosition() > m_world->getPlayerKart(i)->getPosition() )
{
m_controls->m_accel = m_max_handicap_speed;
return;
}
}
} // handleAcceleration
@ -1446,11 +1375,17 @@ void SkiddingAI::handleRaceStart()
{
// Each kart starts at a different, random time, and the time is
// smaller depending on the difficulty.
m_start_delay = m_min_start_delay
+ (float) rand() / RAND_MAX * (m_max_start_delay-m_min_start_delay);
m_start_delay = m_ai_properties->m_min_start_delay
+ (float) rand() / RAND_MAX
* (m_ai_properties->m_max_start_delay -
m_ai_properties->m_min_start_delay);
float false_start_probability =
m_superpower == RaceManager::SUPERPOWER_NOLOK_BOSS
? 0.0f : m_ai_properties->m_false_start_probability;
// Now check for a false start. If so, add 1 second penalty time.
if(rand() < RAND_MAX * m_false_start_probability)
if(rand() < RAND_MAX * false_start_probability)
{
m_start_delay+=stk_config->m_penalty_time;
return;
@ -1499,15 +1434,17 @@ void SkiddingAI::handleNitroAndZipper()
// Don't compute nitro usage if we don't have nitro or are not supposed
// to use it, and we don't have a zipper or are not supposed to use
// it (calculated).
if( (m_kart->getEnergy()==0 || m_nitro_level==NITRO_NONE) &&
if( (m_kart->getEnergy()==0 ||
m_ai_properties->m_nitro_usage==AIProperties::NITRO_NONE) &&
(m_kart->getPowerup()->getType()!=PowerupManager::POWERUP_ZIPPER ||
m_item_tactic==IT_TEN_SECONDS ) )
!m_ai_properties->m_item_usage_non_random ) )
return;
// If there are items to avoid close, and we only have zippers, don't
// use them (since this make it harder to avoid items).
if(m_avoid_item_close &&
(m_kart->getEnergy()==0|| m_nitro_level==NITRO_NONE) )
(m_kart->getEnergy()==0 ||
m_ai_properties->m_nitro_usage==AIProperties::NITRO_NONE) )
return;
// If a parachute or anvil is attached, the nitro doesn't give much
// benefit. Better wait till later.
@ -1538,10 +1475,12 @@ void SkiddingAI::handleNitroAndZipper()
// anyway. Since the kart is faster with nitro, estimate a 50% time
// decrease (additionally some nitro will be saved when top speed
// is reached).
if(m_world->getLapForKart(m_kart->getWorldKartId())==race_manager->getNumLaps()-1 &&
m_nitro_level == NITRO_ALL)
if(m_world->getLapForKart(m_kart->getWorldKartId())
==race_manager->getNumLaps()-1 &&
m_ai_properties->m_nitro_usage == AIProperties::NITRO_ALL)
{
float finish = m_world->getEstimatedFinishTime(m_kart->getWorldKartId());
float finish =
m_world->getEstimatedFinishTime(m_kart->getWorldKartId());
if( 1.5f*m_kart->getEnergy() >= finish - m_world->getTime() )
{
m_controls->m_nitro = true;
@ -1569,7 +1508,8 @@ void SkiddingAI::handleNitroAndZipper()
m_kart_behind->getSpeed() > m_kart->getSpeed() )
{
// Only prevent overtaking on highest level
m_controls->m_nitro = m_nitro_level==NITRO_ALL;
m_controls->m_nitro = m_ai_properties->m_nitro_usage
== AIProperties::NITRO_ALL;
return;
}
@ -1597,7 +1537,7 @@ void SkiddingAI::handleNitroAndZipper()
void SkiddingAI::checkCrashes(const Vec3& pos )
{
int steps = int( m_kart->getVelocityLC().getZ() / m_kart_length );
if( steps < m_min_steps ) steps = m_min_steps;
if( steps < 2 ) steps = 2;
// The AI drives significantly better with more steps, so for now
// add 5 additional steps.
@ -1613,7 +1553,8 @@ void SkiddingAI::checkCrashes(const Vec3& pos )
// If slipstream should be handled actively, trigger overtaking the
// kart which gives us slipstream if slipstream is ready
const SlipStream *slip=m_kart->getSlipstream();
if(m_make_use_of_slipstream && slip->isSlipstreamReady() &&
if(m_ai_properties->m_make_use_of_slipstream &&
slip->isSlipstreamReady() &&
slip->getSlipstreamTarget())
{
//printf("%s overtaking %s\n", m_kart->getIdent().c_str(),

View File

@ -46,21 +46,6 @@ namespace irr
class SkiddingAI : public AIBaseController
{
private:
/** How the AI uses nitro. */
enum {NITRO_NONE, NITRO_SOME, NITRO_ALL} m_nitro_level;
/** Determines if the AI should prefer collecting items over avoiding
* items, or avoiding over collecting. */
enum {ITEM_COLLECT_NONE, ITEM_COLLECT_PRIORITY, ITEM_AVOID_PRIORITY}
m_item_behaviour;
enum ItemTactic
{
IT_TEN_SECONDS, //Fire after 10 seconds have passed, since the item
//was grabbed.
IT_CALCULATE //Aim carefully, check for enough space for boosters,
//and that other conditions are meet before firing.
};
class CrashTypes
{
@ -74,37 +59,6 @@ private:
RaceManager::AISuperPower m_superpower;
/*Difficulty handling variables*/
/** Chance of a false start. */
float m_false_start_probability;
/** The minimum delay time before a AI kart starts. */
float m_min_start_delay;
/** The maximum delay time before an AI kart starts. */
float m_max_start_delay;
/** The actual start delay used. */
float m_start_delay;
/** Minimum number of steps to check. If 0, the AI doesn't even has check
* around the kart, if 1, it checks around the kart always, and more
* than that will check the remaining number of steps in front of the
* kart, always. */
int m_min_steps;
/** If true, the acceleration is decreased when the AI is in a better
* position than all the human players. */
bool m_wait_for_players;
/** The allowed maximum speed in percent of the kart's maximum speed. */
float m_max_handicap_speed;
/** How are items going to be used? */
ItemTactic m_item_tactic;
/** True if the kart should try to pass on a bomb to another kart. */
bool m_handle_bomb;
/** True if the AI should avtively try to make use of slipstream. */
bool m_make_use_of_slipstream;
/*General purpose variables*/
/** Pointer to the closest kart ahead of this kart. NULL if this
@ -121,6 +75,9 @@ private:
/** Distance to the kard behind. */
float m_distance_behind;
/** The actual start delay used. */
float m_start_delay;
/** Time an item has been collected and not used. */
float m_time_since_last_shot;

View File

@ -106,13 +106,15 @@ KartProperties::KartProperties(const std::string &filename)
if (filename != "")
{
m_skidding_properties = NULL;
m_ai_properties = NULL;
for(unsigned int i=0; i<RaceManager::DIFFICULTY_COUNT; i++)
m_ai_properties[i]= NULL;
load(filename, "kart");
}
else
{
m_skidding_properties = new SkiddingProperties();
m_ai_properties = new AIProperties();
for(unsigned int i=0; i<RaceManager::DIFFICULTY_COUNT; i++)
m_ai_properties[i]= new AIProperties((RaceManager::Difficulty)i);
}
} // KartProperties
@ -123,8 +125,9 @@ KartProperties::~KartProperties()
delete m_kart_model;
if(m_skidding_properties)
delete m_skidding_properties;
if(m_ai_properties)
delete m_ai_properties;
for(unsigned int i=0; i<RaceManager::DIFFICULTY_COUNT; i++)
if(m_ai_properties[i])
delete m_ai_properties[i];
} // ~KartProperties
//-----------------------------------------------------------------------------
@ -138,14 +141,18 @@ void KartProperties::copyFrom(const KartProperties *source)
{
*this = *source;
// After the memcpy the two skidding properties will share pointers.
// After the memcpy any pointers will be shared.
// So all pointer variables need to be separately allocated and assigned.
m_skidding_properties = new SkiddingProperties();
assert(m_skidding_properties);
m_ai_properties = new AIProperties();
assert(m_ai_properties);
*m_skidding_properties = *source->m_skidding_properties;
*m_ai_properties = *source->m_ai_properties;
for(unsigned int i=0; i<RaceManager::DIFFICULTY_COUNT; i++)
{
m_ai_properties[i] = new AIProperties((RaceManager::Difficulty)i);
assert(m_ai_properties);
*m_ai_properties[i] = *source->m_ai_properties[i];
}
} // copyFrom
//-----------------------------------------------------------------------------
@ -317,7 +324,12 @@ void KartProperties::getAllData(const XMLNode * root)
if(const XMLNode *ai_node = root->getNode("ai"))
{
m_ai_properties->load(ai_node);
const XMLNode *easy = ai_node->getNode("easy");
m_ai_properties[RaceManager::DIFFICULTY_EASY]->load(easy);
const XMLNode *medium = ai_node->getNode("medium");
m_ai_properties[RaceManager::DIFFICULTY_MEDIUM]->load(medium);
const XMLNode *hard = ai_node->getNode("hard");
m_ai_properties[RaceManager::DIFFICULTY_HARD]->load(hard);
}
if(const XMLNode *slipstream_node = root->getNode("slipstream"))
@ -649,7 +661,8 @@ void KartProperties::checkAllSet(const std::string &filename)
CHECK_NEG(m_explosion_radius, "explosion radius" );
m_skidding_properties->checkAllSet(filename);
m_ai_properties->checkAllSet(filename);
for(unsigned int i=0; i<RaceManager::DIFFICULTY_COUNT; i++)
m_ai_properties[i]->checkAllSet(filename);
} // checkAllSet
// ----------------------------------------------------------------------------

View File

@ -65,8 +65,9 @@ private:
/** AI Properties for this kart, as a separate object in order to
* reduce dependencies (and therefore compile time) when changing
* any AI property. */
AIProperties *m_ai_properties;
* any AI property. There is one separate object for each
* difficulty. */
AIProperties *m_ai_properties[RaceManager::DIFFICULTY_COUNT];
/** The absolute path of the icon texture to use. */
Material *m_icon_material;
@ -632,7 +633,10 @@ public:
{ return m_skidding_properties; }
/** Returns a pointer to the AI properties. */
const AIProperties *getAIProperties() const { return m_ai_properties; }
const AIProperties *getAIPropertiesForDifficulty() const
{
return m_ai_properties[race_manager->getDifficulty()];
} // getAIProperties
/** Returns ratio of current speed to max speed at which the gear will
* change (for our simualated gears = simple change of engine power). */