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, 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. 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. 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. false-start-probability: Probability of a false start.
min/max-start-delay: Minimum and maximum start delay. min/max-start-delay: Minimum and maximum start delay.
See http://www.humanbenchmark.com/tests/reactiontime/stats.php See http://www.humanbenchmark.com/tests/reactiontime/stats.php
@ -316,6 +318,7 @@
straight-length-for-zipper="35" straight-length-for-zipper="35"
use-slipstream="false" use-slipstream="false"
disable-slipstream-usage="true" disable-slipstream-usage="true"
shield-incoming-radius="0"
false-start-probability="0.08" false-start-probability="0.08"
min-start-delay="0.3" max-start-delay="0.5" min-start-delay="0.3" max-start-delay="0.5"
nitro-usage="none" nitro-usage="none"
@ -333,6 +336,7 @@
straight-length-for-zipper="35" straight-length-for-zipper="35"
use-slipstream="false" use-slipstream="false"
disable-slipstream-usage="false" disable-slipstream-usage="false"
shield-incoming-radius="10"
false-start-probability="0.04" false-start-probability="0.04"
min-start-delay="0.25" max-start-delay="0.4" min-start-delay="0.25" max-start-delay="0.4"
nitro-usage="some" nitro-usage="some"
@ -350,6 +354,7 @@
straight-length-for-zipper="35" straight-length-for-zipper="35"
use-slipstream="true" use-slipstream="true"
disable-slipstream-usage="false" disable-slipstream-usage="false"
shield-incoming-radius="10"
false-start-probability="0.01" false-start-probability="0.01"
min-start-delay="0.15" max-start-delay="0.28" min-start-delay="0.15" max-start-delay="0.28"
nitro-usage="all" nitro-usage="all"
@ -367,6 +372,7 @@
straight-length-for-zipper="35" straight-length-for-zipper="35"
use-slipstream="true" use-slipstream="true"
disable-slipstream-usage="false" disable-slipstream-usage="false"
shield-incoming-radius="10"
false-start-probability="0.0" false-start-probability="0.0"
min-start-delay="0.15" max-start-delay="0.2" min-start-delay="0.15" max-start-delay="0.2"
nitro-usage="all" nitro-usage="all"

View File

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

View File

@ -156,8 +156,13 @@ void ProjectileManager::updateClient(float dt)
} // for i in m_active_projectiles } // for i in m_active_projectiles
} // updateClient } // 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) PowerupManager::PowerupType type)
{ {
Flyable *f; Flyable *f;
@ -173,3 +178,22 @@ Flyable *ProjectileManager::newProjectile(AbstractKart *kart, Track* track,
m_active_projectiles.push_back(f); m_active_projectiles.push_back(f);
return f; return f;
} // newProjectile } // 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 loadData ();
void cleanup (); void cleanup ();
void update (float dt); void update (float dt);
Flyable* newProjectile (AbstractKart *kart, Track* track, Flyable* newProjectile (AbstractKart *kart,
PowerupManager::PowerupType type); PowerupManager::PowerupType type);
void Deactivate (Flyable *p) {} void Deactivate (Flyable *p) {}
void removeTextures (); void removeTextures ();
bool projectileIsClose(const AbstractKart * const kart,
float radius);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Adds a special hit effect to be shown. /** Adds a special hit effect to be shown.
* \param hit_effect The hit effect to be added. */ * \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_skidding_threshold = UNDEFINED;
m_min_start_delay = UNDEFINED; m_min_start_delay = UNDEFINED;
m_max_start_delay = UNDEFINED; m_max_start_delay = UNDEFINED;
m_shield_incoming_radius = UNDEFINED;
m_false_start_probability = UNDEFINED; m_false_start_probability = UNDEFINED;
m_make_use_of_slipstream = false; m_make_use_of_slipstream = false;
m_collect_avoid_items = 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("collect-avoid-items", &m_collect_avoid_items );
ai_node->get("handle-bomb", &m_handle_bomb ); ai_node->get("handle-bomb", &m_handle_bomb );
ai_node->get("skidding-threshold", &m_skidding_threshold ); 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("false-start-probability", &m_false_start_probability );
ai_node->get("min-start-delay", &m_min_start_delay ); ai_node->get("min-start-delay", &m_min_start_delay );
ai_node->get("max-start-delay", &m_max_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_bad_item_closeness_2, "bad-item-closeness" );
CHECK_NEG(m_straight_length_for_zipper,"straight-length-for-zipper"); CHECK_NEG(m_straight_length_for_zipper,"straight-length-for-zipper");
CHECK_NEG(m_skidding_threshold, "skidding-threshold" ); 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_false_start_probability, "false-start-probability" );
CHECK_NEG(m_min_start_delay, "min-start-delay" ); CHECK_NEG(m_min_start_delay, "min-start-delay" );
CHECK_NEG(m_max_start_delay, "max-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. */ /** To determine the probability of selecting an item. */
InterpolationArray m_collect_item_probability; 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 /** Probability of a false start. Note that Nolok in boss battle will never
* have a false start. */ * have a false start. */
float m_false_start_probability; float m_false_start_probability;

View File

@ -41,6 +41,10 @@
#endif #endif
#include "graphics/show_curve.hpp" #include "graphics/show_curve.hpp"
#include "graphics/slip_stream.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/abstract_kart.hpp"
#include "karts/controller/kart_control.hpp" #include "karts/controller/kart_control.hpp"
#include "karts/controller/ai_properties.hpp" #include "karts/controller/ai_properties.hpp"
@ -49,9 +53,6 @@
#include "karts/rescue_animation.hpp" #include "karts/rescue_animation.hpp"
#include "karts/skidding.hpp" #include "karts/skidding.hpp"
#include "karts/skidding_properties.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/linear_world.hpp"
#include "modes/profile_world.hpp" #include "modes/profile_world.hpp"
#include "network/network_manager.hpp" #include "network/network_manager.hpp"
@ -1169,7 +1170,7 @@ void SkiddingAI::handleItems(const float dt)
if( m_time_since_last_shot > 3.0f ) 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) if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_SWATTER)
m_time_since_last_shot = 3.0f; m_time_since_last_shot = 3.0f;
else else
@ -1201,29 +1202,54 @@ void SkiddingAI::handleItems(const float dt)
switch( m_kart->getPowerup()->getType() ) switch( m_kart->getPowerup()->getType() )
{ {
case PowerupManager::POWERUP_BUBBLEGUM: 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 // Check if a flyable (cake, ...) is close. If so, use bubblegum
// behind is 'close' but not too close (too close likely means that the // as shield
// kart is not behind but more to the side of this kart and so won't if( !m_kart->isShielded() &&
// be hit by the bubble gum anyway). Should we check the speed of the projectile_manager->projectileIsClose(m_kart,
// kart as well? I.e. only drop if the kart behind is faster? Otoh m_ai_properties->m_shield_incoming_radius) )
// this approach helps preventing an overtaken kart to overtake us {
// again. m_controls->m_fire = true;
m_controls->m_look_back = true; //handle traditinal usage as bubble gum m_controls->m_look_back = false;
m_controls->m_fire = (m_distance_behind < 15.0f && break;
m_distance_behind > 3.0f );//TODO: is this criteria sufficient to hit another kart with a high probability }
m_controls->m_look_back = false; // Avoid dropping all bubble gums one after another
//Do not use a shield, when you still have a swatter if( m_time_since_last_shot < 3.0f) break;
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;
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 // All the thrown/fired items might be improved by considering the angle
// towards m_kart_ahead. // towards m_kart_ahead.
case PowerupManager::POWERUP_CAKE: case PowerupManager::POWERUP_CAKE: