Make the AI handle bubblegum better (esp. using shield).

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@14274 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2013-10-17 05:58:56 +00:00
parent c6fa95d262
commit 2da9ab0845
7 changed files with 91 additions and 27 deletions

View File

@ -253,6 +253,8 @@
disable-slipstream-usage: even if the AI is not trying to use slipstream,
it can get a lot of bonus, esp. on easy since the AI creates trains.
Set this to true to make sure AI does not get any slipstream bonus.
shield-incoming-radius: Radius at which projectiles will be detected and
trigger a shield usage.
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
@ -316,6 +318,7 @@
straight-length-for-zipper="35"
use-slipstream="false"
disable-slipstream-usage="true"
shield-incoming-radius="0"
false-start-probability="0.08"
min-start-delay="0.3" max-start-delay="0.5"
nitro-usage="none"
@ -333,6 +336,7 @@
straight-length-for-zipper="35"
use-slipstream="false"
disable-slipstream-usage="false"
shield-incoming-radius="10"
false-start-probability="0.04"
min-start-delay="0.25" max-start-delay="0.4"
nitro-usage="some"
@ -350,6 +354,7 @@
straight-length-for-zipper="35"
use-slipstream="true"
disable-slipstream-usage="false"
shield-incoming-radius="10"
false-start-probability="0.01"
min-start-delay="0.15" max-start-delay="0.28"
nitro-usage="all"
@ -367,6 +372,7 @@
straight-length-for-zipper="35"
use-slipstream="true"
disable-slipstream-usage="false"
shield-incoming-radius="10"
false-start-probability="0.0"
min-start-delay="0.15" max-start-delay="0.2"
nitro-usage="all"

View File

@ -264,7 +264,7 @@ void Powerup::use()
Powerup::adjustSound();
m_sound_use->play();
projectile_manager->newProjectile(m_owner, world->getTrack(), m_type);
projectile_manager->newProjectile(m_owner, m_type);
break ;
case PowerupManager::POWERUP_SWATTER:

View File

@ -156,8 +156,13 @@ void ProjectileManager::updateClient(float dt)
} // for i in m_active_projectiles
} // updateClient
// -----------------------------------------------------------------------------
Flyable *ProjectileManager::newProjectile(AbstractKart *kart, Track* track,
/** Creates a new projectile of the given type.
* \param kart The kart which shoots the projectile.
* \param type Type of projectile.
*/
Flyable *ProjectileManager::newProjectile(AbstractKart *kart,
PowerupManager::PowerupType type)
{
Flyable *f;
@ -173,3 +178,22 @@ Flyable *ProjectileManager::newProjectile(AbstractKart *kart, Track* track,
m_active_projectiles.push_back(f);
return f;
} // newProjectile
// -----------------------------------------------------------------------------
/** Returns true if a projectile is within the given distance of the specified
* kart.
* \param kart The kart for which the test is done.
* \param radius Distance within which the projectile must be.
*/
bool ProjectileManager::projectileIsClose(const AbstractKart * const kart,
float radius)
{
float r2 = radius*radius;
for(Projectiles::iterator i = m_active_projectiles.begin();
i != m_active_projectiles.end(); i++)
{
float dist2 = (*i)->getXYZ().distance2(kart->getXYZ());
if(dist2<r2) return true;
}
return false;
} // projectileIsClose

View File

@ -61,10 +61,12 @@ public:
void loadData ();
void cleanup ();
void update (float dt);
Flyable* newProjectile (AbstractKart *kart, Track* track,
Flyable* newProjectile (AbstractKart *kart,
PowerupManager::PowerupType type);
void Deactivate (Flyable *p) {}
void removeTextures ();
bool projectileIsClose(const AbstractKart * const kart,
float radius);
// ------------------------------------------------------------------------
/** Adds a special hit effect to be shown.
* \param hit_effect The hit effect to be added. */

View File

@ -38,6 +38,7 @@ AIProperties::AIProperties(RaceManager::Difficulty difficulty)
m_skidding_threshold = UNDEFINED;
m_min_start_delay = UNDEFINED;
m_max_start_delay = UNDEFINED;
m_shield_incoming_radius = UNDEFINED;
m_false_start_probability = UNDEFINED;
m_make_use_of_slipstream = false;
m_collect_avoid_items = false;
@ -68,6 +69,7 @@ void AIProperties::load(const XMLNode *ai_node)
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("shield-incoming-radius", &m_shield_incoming_radius );
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 );
@ -109,6 +111,7 @@ void AIProperties::checkAllSet(const std::string &filename) const
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_shield_incoming_radius, "shield-incoming-radius" );
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" );

View File

@ -79,7 +79,10 @@ protected:
/** To determine the probability of selecting an item. */
InterpolationArray m_collect_item_probability;
/** Distance at which a detected projectile triggers a shield. */
float m_shield_incoming_radius;
/** Probability of a false start. Note that Nolok in boss battle will never
* have a false start. */
float m_false_start_probability;

View File

@ -41,6 +41,10 @@
#endif
#include "graphics/show_curve.hpp"
#include "graphics/slip_stream.hpp"
#include "items/attachment.hpp"
#include "items/item_manager.hpp"
#include "items/powerup.hpp"
#include "items/projectile_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/controller/kart_control.hpp"
#include "karts/controller/ai_properties.hpp"
@ -49,9 +53,6 @@
#include "karts/rescue_animation.hpp"
#include "karts/skidding.hpp"
#include "karts/skidding_properties.hpp"
#include "items/attachment.hpp"
#include "items/item_manager.hpp"
#include "items/powerup.hpp"
#include "modes/linear_world.hpp"
#include "modes/profile_world.hpp"
#include "network/network_manager.hpp"
@ -1169,7 +1170,7 @@ void SkiddingAI::handleItems(const float dt)
if( m_time_since_last_shot > 3.0f )
{
m_controls->m_fire = true;
m_controls->m_fire = true;
if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_SWATTER)
m_time_since_last_shot = 3.0f;
else
@ -1201,29 +1202,54 @@ void SkiddingAI::handleItems(const float dt)
switch( m_kart->getPowerup()->getType() )
{
case PowerupManager::POWERUP_BUBBLEGUM:
// Avoid dropping all bubble gums one after another
if( m_time_since_last_shot < 3.0f) break;
{
Attachment::AttachmentType type = m_kart->getAttachment()->getType();
// Don't use shield when we have a swatter.
if( type == Attachment::ATTACH_SWATTER ||
type == Attachment::ATTACH_NOLOKS_SWATTER )
break;
// Either use the bubble gum after 10 seconds, or if the next kart
// behind is 'close' but not too close (too close likely means that the
// kart is not behind but more to the side of this kart and so won't
// be hit by the bubble gum anyway). Should we check the speed of the
// kart as well? I.e. only drop if the kart behind is faster? Otoh
// this approach helps preventing an overtaken kart to overtake us
// again.
m_controls->m_look_back = true; //handle traditinal usage as bubble gum
m_controls->m_fire = (m_distance_behind < 15.0f &&
m_distance_behind > 3.0f );//TODO: is this criteria sufficient to hit another kart with a high probability
// Check if a flyable (cake, ...) is close. If so, use bubblegum
// as shield
if( !m_kart->isShielded() &&
projectile_manager->projectileIsClose(m_kart,
m_ai_properties->m_shield_incoming_radius) )
{
m_controls->m_fire = true;
m_controls->m_look_back = false;
break;
}
m_controls->m_look_back = false;
//Do not use a shield, when you still have a swatter
if (m_kart->getAttachment()->getType() == Attachment::ATTACH_SWATTER || m_kart->getAttachment()->getType() == Attachment::ATTACH_NOLOKS_SWATTER)
break;
//else there are no objections not to use a shield
m_controls->m_fire = true;
// Avoid dropping all bubble gums one after another
if( m_time_since_last_shot < 3.0f) break;
break; // POWERUP_BUBBLEGUM
// Use bubblegum if the next kart behind is 'close' but not too close
// (too close likely means that the kart is not behind but more to the
// side of this kart and so won't be hit by the bubble gum anyway).
// Should we check the speed of the kart as well? I.e. only drop if
// the kart behind is faster? Otoh this approach helps preventing an
// overtaken kart to overtake us again.
if(m_distance_behind < 15.0f && m_distance_behind > 3.0f )
{
m_controls->m_fire = true;
m_controls->m_look_back = true;
break;
}
// If this kart is in its last lap, drop bubble gums at every
// opportunity, since this kart won't envounter them anymore.
LinearWorld *lin_world = dynamic_cast<LinearWorld*>(World::getWorld());
if(m_time_since_last_shot > 3.0f &&
lin_world &&
lin_world->getKartLaps(m_kart->getWorldKartId())
== race_manager->getNumLaps()-1)
{
m_controls->m_fire = true;
m_controls->m_look_back = true;
break;
}
break; // POWERUP_BUBBLEGUM
}
// All the thrown/fired items might be improved by considering the angle
// towards m_kart_ahead.
case PowerupManager::POWERUP_CAKE: