Merged bubble bum branch into trunk. The new bubble gum

shield is still work in progress.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@13444 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2013-08-08 03:11:03 +00:00
parent 72a2b69695
commit df9d90b342
27 changed files with 372 additions and 90 deletions

View File

@ -74,6 +74,9 @@
* rubber_ball-icon, plunger icon, cake icon, bowling ball texture and icon * rubber_ball-icon, plunger icon, cake icon, bowling ball texture and icon
by Totoplus62, released under CC-BY-SA 3.0 by Totoplus62, released under CC-BY-SA 3.0
* shield-icon
by tuxfan, release under CC-BY-SA 3.0
Others are GPL, by the original (super)TuxKart team Others are GPL, by the original (super)TuxKart team

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
data/models/shield-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -114,8 +114,10 @@
nolok-bubble-gum, easter egg --> nolok-bubble-gum, easter egg -->
<switch time="5" items="1 0 4 4 2 5 2 7"/> <switch time="5" items="1 0 4 4 2 5 2 7"/>
<!-- How often bubblegum get driven over before it disappears. --> <!-- disappear-counter: How often bubblegum gets driven over before it disappears.
<bubblegum disappear-counter="1"/> shield-time: How long the bubblegum shield lasts
restrict-weapons: If true, using weapons will destroy the user's shield -->
<bubblegum disappear-counter="1" shield-time="10.0" restrict-weapons="false"/>
<!-- explosion-impulse-objects is the impulse that pushes physical objects <!-- explosion-impulse-objects is the impulse that pushes physical objects
away if there is an explosion. --> away if there is an explosion. -->

View File

@ -118,6 +118,7 @@ void STKConfig::load(const std::string &filename)
CHECK_NEG(m_anvil_weight, "anvil-weight" ); CHECK_NEG(m_anvil_weight, "anvil-weight" );
CHECK_NEG(m_item_switch_time, "item-switch-time" ); CHECK_NEG(m_item_switch_time, "item-switch-time" );
CHECK_NEG(m_bubblegum_counter, "bubblegum disappear counter"); CHECK_NEG(m_bubblegum_counter, "bubblegum disappear counter");
CHECK_NEG(m_bubblegum_shield_time, "bubblegum shield-time" );
CHECK_NEG(m_explosion_impulse_objects, "explosion-impulse-objects" ); CHECK_NEG(m_explosion_impulse_objects, "explosion-impulse-objects" );
CHECK_NEG(m_max_history, "max-history" ); CHECK_NEG(m_max_history, "max-history" );
CHECK_NEG(m_max_skidmarks, "max-skidmarks" ); CHECK_NEG(m_max_skidmarks, "max-skidmarks" );
@ -159,6 +160,8 @@ void STKConfig::init_defaults()
m_smooth_angle_limit = m_smooth_angle_limit =
m_penalty_time = m_explosion_impulse_objects = UNDEFINED; m_penalty_time = m_explosion_impulse_objects = UNDEFINED;
m_bubblegum_counter = -100; m_bubblegum_counter = -100;
m_bubblegum_shield_time = -100;
m_shield_restrict_weapos = false;
m_max_karts = -100; m_max_karts = -100;
m_max_history = -100; m_max_history = -100;
m_max_skidmarks = -100; m_max_skidmarks = -100;
@ -335,7 +338,9 @@ void STKConfig::getAllData(const XMLNode * root)
if(const XMLNode *bubblegum_node= root->getNode("bubblegum")) if(const XMLNode *bubblegum_node= root->getNode("bubblegum"))
{ {
bubblegum_node->get("disappear-counter", &m_bubblegum_counter); bubblegum_node->get("disappear-counter", &m_bubblegum_counter );
bubblegum_node->get("shield-time", &m_bubblegum_shield_time );
bubblegum_node->get("restrict-weapons", &m_shield_restrict_weapos);
} }
if(const XMLNode *explosion_node= root->getNode("explosion")) if(const XMLNode *explosion_node= root->getNode("explosion"))

View File

@ -74,8 +74,10 @@ public:
passed on. */ passed on. */
float m_anvil_time; /**<Time an anvil is active. */ float m_anvil_time; /**<Time an anvil is active. */
float m_item_switch_time; /**< Time items will be switched. */ float m_item_switch_time; /**< Time items will be switched. */
int m_bubblegum_counter; /**< How many times bananas must be eaten int m_bubblegum_counter; /**< How many times bubble gums must be
before they disappear. */ driven over before they disappear. */
float m_bubblegum_shield_time; /**<How long a bubble gum shield lasts. */
bool m_shield_restrict_weapos; /**<Wether weapon usage is punished. */
float m_explosion_impulse_objects;/**<Impulse of explosion on moving float m_explosion_impulse_objects;/**<Impulse of explosion on moving
objects, e.g. road cones, ... */ objects, e.g. road cones, ... */
float m_penalty_time; /**< Penalty time when starting too float m_penalty_time; /**< Penalty time when starting too

View File

@ -36,7 +36,8 @@
#include "network/race_state.hpp" #include "network/race_state.hpp"
#include "network/network_manager.hpp" #include "network/network_manager.hpp"
#include "utils/constants.hpp" #include "utils/constants.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done
// Log::verbose("attachment", "Decreasing shield \n");
/** Initialises the attachment each kart has. /** Initialises the attachment each kart has.
*/ */
Attachment::Attachment(AbstractKart* kart) Attachment::Attachment(AbstractKart* kart)
@ -92,7 +93,7 @@ void Attachment::set(AttachmentType type, float time,
{ {
bool was_bomb = (m_type == ATTACH_BOMB); bool was_bomb = (m_type == ATTACH_BOMB);
scene::ISceneNode* bomb_scene_node = NULL; scene::ISceneNode* bomb_scene_node = NULL;
if (was_bomb && type == ATTACH_SWATTER) if (was_bomb && type == ATTACH_SWATTER) //What about ATTACH_NOLOKS_SWATTER ??
{ {
// let's keep the bomb node, and create a new one for // let's keep the bomb node, and create a new one for
// the new attachment // the new attachment
@ -206,6 +207,13 @@ void Attachment::clear()
*/ */
void Attachment::hitBanana(Item *item, int new_attachment) void Attachment::hitBanana(Item *item, int new_attachment)
{ {
//Bubble gum shield effect:
if(m_type == ATTACH_BUBBLEGUM_SHIELD)
{
m_time_left -= stk_config->m_bubblegum_shield_time;
return;
}
float leftover_time = 0.0f; float leftover_time = 0.0f;
bool add_a_new_item = true; bool add_a_new_item = true;
@ -414,6 +422,18 @@ void Attachment::update(float dt)
case ATTACH_TINYTUX: case ATTACH_TINYTUX:
// Nothing to do for tinytux, this is all handled in EmergencyAnimation // Nothing to do for tinytux, this is all handled in EmergencyAnimation
break; break;
case ATTACH_BUBBLEGUM_SHIELD:
if(!m_kart->isShielded())
{
m_time_left = 0.0f;
if (m_kart->m_bubble_drop)
{
Log::verbose("Attachment", "Drop a small bubble gum. \n");;
//TODO: drop a bubble gum item on the track
}
}
break;
} // switch } // switch
// Detach attachment if its time is up. // Detach attachment if its time is up.

View File

@ -59,6 +59,7 @@ public:
ATTACH_SWATTER, ATTACH_SWATTER,
ATTACH_NOLOKS_SWATTER, ATTACH_NOLOKS_SWATTER,
ATTACH_TINYTUX, ATTACH_TINYTUX,
ATTACH_BUBBLEGUM_SHIELD,
ATTACH_MAX, ATTACH_MAX,
ATTACH_NOTHING ATTACH_NOTHING
}; };

View File

@ -47,13 +47,14 @@ struct initAttachmentType {Attachment::AttachmentType attachment;
static const initAttachmentType iat[]= static const initAttachmentType iat[]=
{ {
{Attachment::ATTACH_PARACHUTE, "parachute.b3d", "parachute-attach-icon.png"}, {Attachment::ATTACH_PARACHUTE, "parachute.b3d", "parachute-attach-icon.png" },
{Attachment::ATTACH_BOMB, "bomb.b3d", "bomb-attach-icon.png" }, {Attachment::ATTACH_BOMB, "bomb.b3d", "bomb-attach-icon.png" },
{Attachment::ATTACH_ANVIL, "anchor.b3d", "anchor-attach-icon.png" }, {Attachment::ATTACH_ANVIL, "anchor.b3d", "anchor-attach-icon.png" },
{Attachment::ATTACH_SWATTER, "swatter.b3d", "swatter-icon.png" }, {Attachment::ATTACH_SWATTER, "swatter.b3d", "swatter-icon.png" },
{Attachment::ATTACH_NOLOKS_SWATTER, "swatter_nolok.b3d","swatter-icon.png" }, {Attachment::ATTACH_NOLOKS_SWATTER, "swatter_nolok.b3d", "swatter-icon.png" },
{Attachment::ATTACH_TINYTUX, "reset-button.b3d", "reset-attach-icon.png" }, {Attachment::ATTACH_TINYTUX, "reset-button.b3d", "reset-attach-icon.png" },
{Attachment::ATTACH_MAX, "", "" }, {Attachment::ATTACH_BUBBLEGUM_SHIELD, "bubblegum_shield.b3d", "shield-icon.png" },
{Attachment::ATTACH_MAX, "", "" },
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -24,6 +24,8 @@
#include "karts/abstract_kart.hpp" #include "karts/abstract_kart.hpp"
#include "utils/random_generator.hpp" #include "utils/random_generator.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done
float Bowling::m_st_max_distance; // maximum distance for a bowling ball to be attracted float Bowling::m_st_max_distance; // maximum distance for a bowling ball to be attracted
float Bowling::m_st_max_distance_squared; float Bowling::m_st_max_distance_squared;
float Bowling::m_st_force_to_target; float Bowling::m_st_force_to_target;
@ -213,11 +215,21 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj)
bool was_real_hit = Flyable::hit(kart, obj); bool was_real_hit = Flyable::hit(kart, obj);
if(was_real_hit) if(was_real_hit)
{ {
m_has_hit_kart = kart != NULL; if(kart && kart->isShielded())
explode(kart, obj, /*hit_secondary*/false); {
kart->decreaseShieldTime(0.0f); //Decreasing the shield time by the default value.
Log::verbose("Bowling", "Decreasing shield!");
return true;
}
else
{
m_has_hit_kart = kart != NULL;
explode(kart, obj, /*hit_secondary*/false);
}
} }
return was_real_hit; return was_real_hit;
} // hit } // hit
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Returns the hit effect object to use when this objects hits something. /** Returns the hit effect object to use when this objects hits something.
* \returns The hit effect object, or NULL if no hit effect should be played. * \returns The hit effect object, or NULL if no hit effect should be played.

View File

@ -26,6 +26,8 @@
#include "utils/constants.hpp" #include "utils/constants.hpp"
#include "utils/random_generator.hpp" #include "utils/random_generator.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done
float Cake::m_st_max_distance_squared; float Cake::m_st_max_distance_squared;
float Cake::m_gravity; float Cake::m_gravity;
@ -168,7 +170,15 @@ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj)
{ {
bool was_real_hit = Flyable::hit(kart, obj); bool was_real_hit = Flyable::hit(kart, obj);
if(was_real_hit) if(was_real_hit)
{
if(kart && kart->isShielded())
{
kart->decreaseShieldTime(0.0f); //Decreasing the shield time by the default value.
Log::verbose("Cake", "Decreasing shield! \n");
return false; //Not sure if a shield hit is a real hit.
}
explode(kart, obj); explode(kart, obj);
}
return was_real_hit; return was_real_hit;
} // hit } // hit

View File

@ -425,7 +425,7 @@ void Flyable::updateFromServer(const FlyableInfo &f, float dt)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Returns true if the item hit the kart who shot it (to avoid that an item /** Returns true if the item hit the kart who shot it (to avoid that an item
* that's too close to the shoter hits the shoter). * that's too close to the shooter hits the shooter).
* \param kart Kart who was hit. * \param kart Kart who was hit.
*/ */
bool Flyable::isOwnerImmunity(const AbstractKart* kart_hit) const bool Flyable::isOwnerImmunity(const AbstractKart* kart_hit) const
@ -448,7 +448,7 @@ bool Flyable::hit(AbstractKart *kart_hit, PhysicalObject* object)
if(isOwnerImmunity(kart_hit)) return false; if(isOwnerImmunity(kart_hit)) return false;
if (kart_hit != NULL) if (kart_hit != NULL)
{ { //TODO: reduce shield time; add other string ?
RaceGUIBase* gui = World::getWorld()->getRaceGUI(); RaceGUIBase* gui = World::getWorld()->getRaceGUI();
irr::core::stringw hit_message = irr::core::stringw hit_message =
StringUtils::insertValues(getHitString(kart_hit), StringUtils::insertValues(getHitString(kart_hit),

View File

@ -278,6 +278,10 @@ Item* ItemManager::newItem(const Vec3& xyz, float distance,
void ItemManager::collectedItem(Item *item, AbstractKart *kart, int add_info) void ItemManager::collectedItem(Item *item, AbstractKart *kart, int add_info)
{ {
assert(item); assert(item);
if((item->getType() == Item::ITEM_BUBBLEGUM || item->getType() == Item::ITEM_BUBBLEGUM_NOLOK) && kart->isShielded())
{// shielded karts can simply drive over bubble gums without any effect.
return;
}
item->collected(kart); item->collected(kart);
kart->collectedItem(item, add_info); kart->collectedItem(item, add_info);
} // collectedItem } // collectedItem

View File

@ -34,7 +34,7 @@
#include "utils/constants.hpp" #include "utils/constants.hpp"
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
Plunger::Plunger(AbstractKart *kart) Plunger::Plunger(AbstractKart *kart)
@ -180,6 +180,13 @@ bool Plunger::hit(AbstractKart *kart, PhysicalObject *obj)
{ {
if(isOwnerImmunity(kart)) return false; if(isOwnerImmunity(kart)) return false;
/*if(kart && kart->isShielded())
{
//kart->decreaseShieldTime(0.0f); //Decreasing the shield time by the default value.
Log::verbose("Plunger", "Almost Decreasing shield! \n");
return false; //Not sure if a shield hit is a real hit.
}*/
RaceGUIBase* gui = World::getWorld()->getRaceGUI(); RaceGUIBase* gui = World::getWorld()->getRaceGUI();
irr::core::stringw hit_message; irr::core::stringw hit_message;

View File

@ -34,7 +34,7 @@
#include "physics/triangle_mesh.hpp" #include "physics/triangle_mesh.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done
const wchar_t* getAnchorString() const wchar_t* getAnchorString()
{ {
@ -164,7 +164,7 @@ void Powerup::set(PowerupManager::PowerupType type, int n)
break; break;
case PowerupManager::POWERUP_BUBBLEGUM: case PowerupManager::POWERUP_BUBBLEGUM:
m_sound_use = sfx_manager->createSoundSource("goo"); m_sound_use = sfx_manager->createSoundSource("goo");
break ; break ;
case PowerupManager::POWERUP_SWITCH: case PowerupManager::POWERUP_SWITCH:
@ -192,12 +192,38 @@ Material *Powerup::getIcon() const
return powerup_manager->getIcon(m_type); return powerup_manager->getIcon(m_type);
} }
//-----------------------------------------------------------------------------
/** Does the sound configuration.
*/
void Powerup::adjustSound()
{
m_sound_use->position(m_owner->getXYZ());
// in multiplayer mode, sounds are NOT positional (because we have multiple listeners)
// so the sounds of all AIs are constantly heard. So reduce volume of sounds.
if (race_manager->getNumLocalPlayers() > 1)
{
// player karts played at full volume; AI karts much dimmer
if (m_owner->getController()->isPlayerController())
{
m_sound_use->volume( 1.0f );
}
else
{
m_sound_use->volume( std::min(0.5f, 1.0f / race_manager->getNumberOfKarts()) );
}
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Use (fire) this powerup. /** Use (fire) this powerup.
*/ */
void Powerup::use() void Powerup::use()
{ {
// Play custom kart sound when collectible is used // Play custom kart sound when collectible is used //TODO: what about the bubble gum?
if (m_type != PowerupManager::POWERUP_NOTHING && if (m_type != PowerupManager::POWERUP_NOTHING &&
m_type != PowerupManager::POWERUP_SWATTER && m_type != PowerupManager::POWERUP_SWATTER &&
m_type != PowerupManager::POWERUP_ZIPPER) m_type != PowerupManager::POWERUP_ZIPPER)
@ -233,26 +259,11 @@ void Powerup::use()
case PowerupManager::POWERUP_RUBBERBALL: case PowerupManager::POWERUP_RUBBERBALL:
case PowerupManager::POWERUP_BOWLING: case PowerupManager::POWERUP_BOWLING:
case PowerupManager::POWERUP_PLUNGER: case PowerupManager::POWERUP_PLUNGER:
if(stk_config->m_shield_restrict_weapos)
m_sound_use->position(m_owner->getXYZ()); m_owner->setShieldTime(0.0f); // make weapon usage destroy the shield
Powerup::adjustSound();
// in multiplayer mode, sounds are NOT positional (because we have multiple listeners)
// so the sounds of all AIs are constantly heard. So reduce volume of sounds.
if (race_manager->getNumLocalPlayers() > 1)
{
// player karts played at full volume; AI karts much dimmer
if (m_owner->getController()->isPlayerController())
{
m_sound_use->volume( 1.0f );
}
else
{
m_sound_use->volume( std::min(0.5f, 1.0f / race_manager->getNumberOfKarts()) );
}
}
m_sound_use->play(); m_sound_use->play();
projectile_manager->newProjectile(m_owner, world->getTrack(), m_type); projectile_manager->newProjectile(m_owner, world->getTrack(), m_type);
break ; break ;
@ -261,51 +272,55 @@ void Powerup::use()
->set(Attachment::ATTACH_SWATTER, ->set(Attachment::ATTACH_SWATTER,
m_owner->getKartProperties()->getSwatterDuration()); m_owner->getKartProperties()->getSwatterDuration());
break; break;
case PowerupManager::POWERUP_BUBBLEGUM: case PowerupManager::POWERUP_BUBBLEGUM:
// use the bubble gum the traditional way, if the kart is looking back
if (m_owner->getControls().m_look_back)
{ {
Vec3 hit_point; Vec3 hit_point;
Vec3 normal; Vec3 normal;
const Material* material_hit; const Material* material_hit;
Vec3 pos = m_owner->getXYZ(); Vec3 pos = m_owner->getXYZ();
Vec3 to=pos+Vec3(0, -10000, 0); Vec3 to=pos+Vec3(0, -10000, 0);
world->getTrack()->getTriangleMesh().castRay(pos, to, &hit_point, world->getTrack()->getTriangleMesh().castRay(pos, to, &hit_point,
&material_hit, &normal); &material_hit, &normal);
// This can happen if the kart is 'over nothing' when dropping // This can happen if the kart is 'over nothing' when dropping
// the bubble gum // the bubble gum
if(!material_hit) if(!material_hit)
return; return;
normal.normalize(); normal.normalize();
// in multiplayer mode, sounds are NOT positional (because we have multiple listeners) Powerup::adjustSound();
// so the sounds of all AIs are constantly heard. So reduce volume of sounds. m_sound_use->play();
if (race_manager->getNumLocalPlayers() > 1)
pos.setY(hit_point.getY()-0.05f);
ItemManager::get()->newItem(Item::ITEM_BUBBLEGUM, pos, normal, m_owner);
}
else // if the kart is looking forward, use the bubblegum as a shield
{ {
const int np = race_manager->getNumLocalPlayers();
const int nai = race_manager->getNumberOfKarts() - np;
// player karts played at full volume; AI karts much dimmer if(!m_owner->isShielded()) //if the previous shield had been used up.
if (m_owner->getController()->isPlayerController())
{ {
m_sound_use->volume( 1.0f ); m_owner->getAttachment()->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
stk_config->m_bubblegum_shield_time);
} }
else else // using a bubble gum while still having a shield
{ {
m_sound_use->volume( 1.0f / nai ); m_owner->getAttachment()->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
stk_config->m_bubblegum_shield_time + m_owner->getShieldTime());
} }
}
m_sound_use->position(m_owner->getXYZ()); m_sound_use = sfx_manager->createSoundSource("inflate");//Extraordinary. Usually sounds are set in Powerup::set()
m_sound_use->play(); //In this case this is a workaround, since the bubblegum item has two different sounds.
pos.setY(hit_point.getY()-0.05f); Powerup::adjustSound();
m_sound_use->play();
ItemManager::get()->newItem(Item::ITEM_BUBBLEGUM, pos, normal, m_owner); } // end of PowerupManager::POWERUP_BUBBLEGUM
}
break; break;
case PowerupManager::POWERUP_ANVIL: case PowerupManager::POWERUP_ANVIL:
//Attach an anvil(twice as good as the one given //Attach an anvil(twice as good as the one given
//by the bananas) to the kart in the 1st position. //by the bananas) to the kart in the 1st position.
for(unsigned int i = 0 ; i < world->getNumKarts(); ++i) for(unsigned int i = 0 ; i < world->getNumKarts(); ++i)
@ -351,6 +366,12 @@ void Powerup::use()
{ {
AbstractKart *kart=world->getKart(i); AbstractKart *kart=world->getKart(i);
if(kart->isEliminated() || kart== m_owner) continue; if(kart->isEliminated() || kart== m_owner) continue;
if(kart->isShielded())
{
kart->decreaseShieldTime(stk_config->m_bubblegum_shield_time);
Log::verbose("Powerup", "Decreasing shield \n");
continue;
}
if(m_owner->getPosition() > kart->getPosition()) if(m_owner->getPosition() > kart->getPosition())
{ {
kart->getAttachment() kart->getAttachment()

View File

@ -56,8 +56,9 @@ public:
void set (PowerupManager::PowerupType _type, int n=1); void set (PowerupManager::PowerupType _type, int n=1);
void reset (); void reset ();
Material* getIcon () const; Material* getIcon () const;
void adjustSound ();
void use (); void use ();
void hitBonusBox (const Item &item, int newC=-1); void hitBonusBox (const Item &item, int newC=-1);
/** Returns the number of powerups. */ /** Returns the number of powerups. */
int getNum () const {return m_number;} int getNum () const {return m_number;}

View File

@ -20,6 +20,7 @@
#include "audio/sfx_base.hpp" #include "audio/sfx_base.hpp"
#include "audio/sfx_manager.hpp" #include "audio/sfx_manager.hpp"
#include "config/stk_config.hpp"
#include "items/attachment.hpp" #include "items/attachment.hpp"
#include "items/projectile_manager.hpp" #include "items/projectile_manager.hpp"
#include "karts/abstract_kart.hpp" #include "karts/abstract_kart.hpp"
@ -28,6 +29,8 @@
#include "physics/triangle_mesh.hpp" #include "physics/triangle_mesh.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done
float RubberBall::m_st_interval; float RubberBall::m_st_interval;
float RubberBall::m_st_min_interpolation_distance; float RubberBall::m_st_min_interpolation_distance;
float RubberBall::m_st_squash_duration; float RubberBall::m_st_squash_duration;
@ -717,6 +720,21 @@ bool RubberBall::hit(AbstractKart* kart, PhysicalObject* object)
} }
bool was_real_hit = Flyable::hit(kart, object); bool was_real_hit = Flyable::hit(kart, object);
if(was_real_hit) if(was_real_hit)
explode(kart, object); {
/*if(kart && kart->isShielded() && kart->getShieldTime() > stk_config->m_bubblegum_shield_time )
{ //remove twice the default shield time
kart->decreaseShieldTime(stk_config->m_bubblegum_shield_time * 2);
Log::verbose("rubber_ball", "Decreasing shield 1! \n");
}
else */if(kart && kart->isShielded())
{
kart->decreaseShieldTime(stk_config->m_bubblegum_shield_time);
//kart->getAttachment()->update(0.0f);
//kart->setSquash(m_st_squash_duration, m_st_squash_slowdown);
Log::verbose("rubber_ball", "Decreasing shield 2! \n");
}
else
explode(kart, object);
}
return was_real_hit; return was_real_hit;
} // hit } // hit

View File

@ -32,6 +32,8 @@
#include "race/race_manager.hpp" #include "race/race_manager.hpp"
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done
#include <IMesh.h> #include <IMesh.h>
const wchar_t* getPlungerString() const wchar_t* getPlungerString()
@ -135,7 +137,7 @@ void RubberBand::updatePosition()
*/ */
void RubberBand::update(float dt) void RubberBand::update(float dt)
{ {
if(m_owner->isEliminated()) if(m_owner->isEliminated() || m_owner->isShielded())
{ {
// Rubber band snaps // Rubber band snaps
m_plunger->hit(NULL); m_plunger->hit(NULL);
@ -238,10 +240,20 @@ void RubberBand::hit(AbstractKart *kart_hit, const Vec3 *track_xyz)
// a hit as well as the bullet physics. // a hit as well as the bullet physics.
if(m_attached_state!=RB_TO_PLUNGER) return; if(m_attached_state!=RB_TO_PLUNGER) return;
// A kart was hit // A kart was hit
// ============== // ==============
if(kart_hit) if(kart_hit)
{ {
if(kart_hit->isShielded())
{
kart_hit->decreaseShieldTime(0.0f); //Decreasing the shield time by the default value.
m_plunger->setKeepAlive(0.0f);
Log::verbose("rubber_band", "Decreasing shield! \n");
return;
}
m_hit_kart = kart_hit; m_hit_kart = kart_hit;
m_attached_state = RB_TO_KART; m_attached_state = RB_TO_KART;

View File

@ -378,6 +378,18 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual void setInvulnerableTime(float t) = 0; virtual void setInvulnerableTime(float t) = 0;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns if the kart is protected by a shield. */
virtual bool isShielded() const = 0;
// ------------------------------------------------------------------------
virtual void setShieldTime(float t) = 0;
// ------------------------------------------------------------------------
virtual float getShieldTime() const = 0;
// ------------------------------------------------------------------------
/** Decreases the kart's shield time. */
//Hard coded shield decrease time
virtual void decreaseShieldTime(float t) = 0;
// ------------------------------------------------------------------------
/** Shows the star effect for a certain time. */ /** Shows the star effect for a certain time. */
virtual void showStarEffect(float t) = 0; virtual void showStarEffect(float t) = 0;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -403,6 +415,9 @@ public:
/** Set a text that is displayed on top of a kart. /** Set a text that is displayed on top of a kart.
*/ */
virtual void setOnScreenText(const wchar_t *text) = 0; virtual void setOnScreenText(const wchar_t *text) = 0;
/** Whether an unused bubble gum shield becomes a bubble gum on the ground.
* */
bool m_bubble_drop;
}; // AbstractKart }; // AbstractKart

View File

@ -1149,6 +1149,10 @@ void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle,
* better job on higher level AI - e.g. aiming at karts ahead/behind, wait an * better job on higher level AI - e.g. aiming at karts ahead/behind, wait an
* appropriate time before using multiple items etc. * appropriate time before using multiple items etc.
* \param dt Time step size. * \param dt Time step size.
* TODO: Implications of Bubble-Shield for AI's powerup-handling
* STATE: shield on -> avoid usage of offensive items (with certain tolerance)
* STATE: swatter on -> avoid usage of shield
*/ */
void SkiddingAI::handleItems(const float dt) void SkiddingAI::handleItems(const float dt)
{ {
@ -1192,11 +1196,13 @@ void SkiddingAI::handleItems(const float dt)
// Tactic 2: calculate // Tactic 2: calculate
// ------------------- // -------------------
float min_bubble_time = 2.0f;
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 // Avoid dropping all bubble gums one after another
if( m_time_since_last_shot <3.0f) break; if( m_time_since_last_shot < 3.0f) break;
// Either use the bubble gum after 10 seconds, or if the next kart // 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 // behind is 'close' but not too close (too close likely means that the
@ -1205,16 +1211,30 @@ void SkiddingAI::handleItems(const float dt)
// kart as well? I.e. only drop if the kart behind is faster? Otoh // kart as well? I.e. only drop if the kart behind is faster? Otoh
// this approach helps preventing an overtaken kart to overtake us // this approach helps preventing an overtaken kart to overtake us
// again. // again.
m_controls->m_look_back = true; //handle traditinal usage as bubble gum
m_controls->m_fire = (m_distance_behind < 15.0f && m_controls->m_fire = (m_distance_behind < 15.0f &&
m_distance_behind > 3.0f ); m_distance_behind > 3.0f );//TODO: is this criteria sufficient to hit another kart with a high probability
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;
break; // POWERUP_BUBBLEGUM 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:
{ {
// Do not destroy your own shield
if(m_kart->getShieldTime() > min_bubble_time) // if the kart has a shield, do not break it by using a swatter.
break;
// Leave some time between shots // Leave some time between shots
if(m_time_since_last_shot<3.0f) break; if(m_time_since_last_shot<3.0f) break;
//TODO: do not fire if the kart is driving too slow
// Since cakes can be fired all around, just use a sane distance // Since cakes can be fired all around, just use a sane distance
// with a bit of extra for backwards, as enemy will go towards cake // with a bit of extra for backwards, as enemy will go towards cake
bool fire_backwards = (m_kart_behind && m_kart_ahead && bool fire_backwards = (m_kart_behind && m_kart_ahead &&
@ -1231,6 +1251,9 @@ void SkiddingAI::handleItems(const float dt)
case PowerupManager::POWERUP_BOWLING: case PowerupManager::POWERUP_BOWLING:
{ {
// Do not destroy your own shield
if(m_kart->getShieldTime() > min_bubble_time) // if the kart has a shield, do not break it by using a swatter.
break;
// Leave more time between bowling balls, since they are // Leave more time between bowling balls, since they are
// slower, so it should take longer to hit something which // slower, so it should take longer to hit something which
// can result in changing our target. // can result in changing our target.
@ -1258,6 +1281,10 @@ void SkiddingAI::handleItems(const float dt)
case PowerupManager::POWERUP_PLUNGER: case PowerupManager::POWERUP_PLUNGER:
{ {
// Do not destroy your own shield
if(m_kart->getShieldTime() > min_bubble_time) // if the kart has a shield, do not break it by using a swatter.
break;
// Leave more time after a plunger, since it will take some // Leave more time after a plunger, since it will take some
// time before a plunger effect becomes obvious. // time before a plunger effect becomes obvious.
if(m_time_since_last_shot < 5.0f) break; if(m_time_since_last_shot < 5.0f) break;
@ -1311,6 +1338,9 @@ void SkiddingAI::handleItems(const float dt)
{ {
// Squared distance for which the swatter works // Squared distance for which the swatter works
float d2 = m_kart->getKartProperties()->getSwatterDistance2(); float d2 = m_kart->getKartProperties()->getSwatterDistance2();
// if the kart has a shield, do not break it by using a swatter.
if(m_kart->getShieldTime() > min_bubble_time)
break;
// Fire if the closest kart ahead or to the back is not already // Fire if the closest kart ahead or to the back is not already
// squashed and close enough. // squashed and close enough.
// FIXME: this can be improved on, since more than one kart might // FIXME: this can be improved on, since more than one kart might
@ -1325,6 +1355,9 @@ void SkiddingAI::handleItems(const float dt)
break; break;
} }
case PowerupManager::POWERUP_RUBBERBALL: case PowerupManager::POWERUP_RUBBERBALL:
// Do not destroy your own shield
if(m_kart->getShieldTime() > min_bubble_time) // if the kart has a shield, do not break it by using a swatter.
break;
// Perhaps some more sophisticated algorithm might be useful. // Perhaps some more sophisticated algorithm might be useful.
// For now: fire if there is a kart ahead (which means that // For now: fire if there is a kart ahead (which means that
// this kart is certainly not the first kart) // this kart is certainly not the first kart)

View File

@ -24,6 +24,7 @@
#include "karts/kart_properties.hpp" #include "karts/kart_properties.hpp"
#include "modes/world.hpp" #include "modes/world.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done
/** A static create function that does only create an explosion if /** A static create function that does only create an explosion if
* the explosion happens to be close enough to affect the kart. * the explosion happens to be close enough to affect the kart.
@ -37,7 +38,12 @@ ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart,
bool direct_hit) bool direct_hit)
{ {
if(kart->isInvulnerable()) return NULL; if(kart->isInvulnerable()) return NULL;
/*else if(kart->isShielded() && !direct_hit) //How can I test this code ??
{
kart->decreaseShieldTime(0.0f); //Decreasing the shield time by the default value.
Log::verbose("ExlosionAnimation", "Decreasing shield \n");
return NULL;
}*/
float r = kart->getKartProperties()->getExplosionRadius(); float r = kart->getKartProperties()->getExplosionRadius();
// Ignore explosion that are too far away. // Ignore explosion that are too far away.
@ -53,6 +59,12 @@ ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart,
ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart) ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart)
{ {
if(kart->isInvulnerable()) return NULL; if(kart->isInvulnerable()) return NULL;
else if(kart->isShielded())
{
kart->decreaseShieldTime(0.0f) ; //decreasing the shieldtime by the default amount
Log::verbose("ExplosionAnimation", "Decreasing shield 2\n");
return NULL;
}
return new ExplosionAnimation(kart, kart->getXYZ(), /*direct hit*/true); return new ExplosionAnimation(kart, kart->getXYZ(), /*direct hit*/true);
} // create } // create

View File

@ -32,6 +32,7 @@
#include "challenges/unlock_manager.hpp" #include "challenges/unlock_manager.hpp"
#include "config/user_config.hpp" #include "config/user_config.hpp"
#include "graphics/camera.hpp" #include "graphics/camera.hpp"
#include "graphics/explosion.hpp"
#include "graphics/material_manager.hpp" #include "graphics/material_manager.hpp"
#include "graphics/particle_emitter.hpp" #include "graphics/particle_emitter.hpp"
#include "graphics/particle_kind.hpp" #include "graphics/particle_kind.hpp"
@ -67,8 +68,9 @@
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "tracks/track_manager.hpp" #include "tracks/track_manager.hpp"
#include "utils/constants.hpp" #include "utils/constants.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done
#include "graphics/explosion.hpp"
#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) #if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
// Disable warning for using 'this' in base member initializer list // Disable warning for using 'this' in base member initializer list
@ -511,7 +513,23 @@ void Kart::setPosition(int p)
} // setPosition } // setPosition
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
/** Sets that the view is blocked by a plunger. The duration depends on
* the difficulty, see KartPorperties getPlungerInFaceTime.
*/
void Kart::blockViewWithPlunger()
{
// Avoid that a plunger extends the plunger time
if(m_view_blocked_by_plunger<=0 && !isShielded())
m_view_blocked_by_plunger =
m_kart_properties->getPlungerInFaceTime();
if(isShielded())
{
decreaseShieldTime(0.0f); //decrease the default amount of time
Log::verbose("Kart", "Decreasing shield, because of removing the plunger. \n");
}
} // blockViewWithPlunger
// -----------------------------------------------------------------------------
/** Returns a transform that will align an object with the kart: the heading /** Returns a transform that will align an object with the kart: the heading
* and the pitch will be set appropriately. A custom pitch value can be * and the pitch will be set appropriately. A custom pitch value can be
* specified in order to overwrite the terrain pitch (which would be used * specified in order to overwrite the terrain pitch (which would be used
@ -942,6 +960,67 @@ bool Kart::isNearGround() const
< stk_config->m_near_ground); < stk_config->m_near_ground);
} // isNearGround } // isNearGround
// ------------------------------------------------------------------------
/**
* Enables a kart shield protection for a certain amount of time.
*/
void Kart::setShieldTime(float t)
{
if(this->isShielded())
{
this->getAttachment()->setTimeLeft(t);
}
}
// ------------------------------------------------------------------------
/**
* Returns true if the kart is protected by a shield.
*/
bool Kart::isShielded() const
{
if(getAttachment() != NULL)
return getAttachment()->getType() == Attachment::ATTACH_BUBBLEGUM_SHIELD;
else
return false;
}
// ------------------------------------------------------------------------
/**
*Returns the remaining time the kart is protected by a shield.
*/
float Kart::getShieldTime() const
{
if(isShielded())
return getAttachment()->getTimeLeft();
else
return 0.0f;
}
// ------------------------------------------------------------------------
/**
* Decreases the kart's shield time.
* \param t The time substracted from the shield timer. If t == 0.0f, the default amout of time is substracted.
*/
void Kart::decreaseShieldTime(float t)
{
if(this->isShielded())
{
getAttachment()->setTimeLeft( getAttachment()->getTimeLeft() - t );
if(t == 0.0f)
{
getAttachment()->setTimeLeft( getAttachment()->getTimeLeft()
- stk_config->m_bubblegum_shield_time);
}
}
//Let the kart drop a bubble gum, if the shield was not damaged.
//This is the default, whenever a powerup is used by a kart.
//It is turned off, if the shield was reduced below zero by a hit. (Or by intently damaging the shield.)
if(!this->isShielded())
m_bubble_drop = false;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Shows the star effect for a certain time. /** Shows the star effect for a certain time.
* \param t Time to show the star effect for. * \param t Time to show the star effect for.
@ -1009,7 +1088,9 @@ void Kart::update(float dt)
// if its view is blocked by plunger, decrease remaining time // if its view is blocked by plunger, decrease remaining time
if(m_view_blocked_by_plunger > 0) m_view_blocked_by_plunger -= dt; if(m_view_blocked_by_plunger > 0) m_view_blocked_by_plunger -= dt;
//unblock the view if kart just became shielded
if(isShielded())
m_view_blocked_by_plunger = 0.0f;
// Decrease remaining invulnerability time // Decrease remaining invulnerability time
if(m_invulnerable_time>0) if(m_invulnerable_time>0)
{ {
@ -1085,6 +1166,7 @@ void Kart::update(float dt)
// since use() can test if something needs to be switched on/off. // since use() can test if something needs to be switched on/off.
m_powerup->use() ; m_powerup->use() ;
World::getWorld()->onFirePressed(getController()); World::getWorld()->onFirePressed(getController());
m_bubble_drop = true;
} }
// Reset the fire button // Reset the fire button
m_controls.m_fire = 0; m_controls.m_fire = 0;
@ -1268,6 +1350,13 @@ void Kart::setSquash(float time, float slowdown)
{ {
if (isInvulnerable()) return; if (isInvulnerable()) return;
if (isShielded())
{
decreaseShieldTime(stk_config->m_bubblegum_shield_time/2.0f);
Log::verbose("Kart", "Decreasing shield \n");
return;
}
if(m_attachment->getType()==Attachment::ATTACH_BOMB && time>0) if(m_attachment->getType()==Attachment::ATTACH_BOMB && time>0)
{ {
ExplosionAnimation::create(this); ExplosionAnimation::create(this);

View File

@ -136,6 +136,8 @@ private:
/** The torque to apply after hitting a bubble gum. */ /** The torque to apply after hitting a bubble gum. */
float m_bubblegum_torque; float m_bubblegum_torque;
// Bullet physics parameters // Bullet physics parameters
// ------------------------- // -------------------------
btCompoundShape m_kart_chassis; btCompoundShape m_kart_chassis;
@ -310,13 +312,7 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Sets that the view is blocked by a plunger. The duration depends on /** Sets that the view is blocked by a plunger. The duration depends on
* the difficulty, see KartPorperties getPlungerInFaceTime. */ * the difficulty, see KartPorperties getPlungerInFaceTime. */
virtual void blockViewWithPlunger() virtual void blockViewWithPlunger();
{
// Avoid that a plunger extends the plunger time
if(m_view_blocked_by_plunger<=0)
m_view_blocked_by_plunger =
m_kart_properties->getPlungerInFaceTime();
} // blockViewWithPlunger
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
/** Returns a bullet transform object located at the kart's position /** Returns a bullet transform object located at the kart's position
and oriented in the direction the kart is going. Can be useful and oriented in the direction the kart is going. Can be useful
@ -395,11 +391,25 @@ public:
virtual void eliminate(); virtual void eliminate();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Makes a kart invulnerable for a certain amount of time. */ /** Makes a kart invulnerable for a certain amount of time. */
virtual void setInvulnerableTime(float t) { m_invulnerable_time = t; }; virtual void setInvulnerableTime(float t) { m_invulnerable_time = t; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns if the kart is invulnerable. */ /** Returns if the kart is invulnerable. */
virtual bool isInvulnerable() const { return m_invulnerable_time > 0; } virtual bool isInvulnerable() const { return m_invulnerable_time > 0; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Enables a kart shield protection for a certain amount of time. */
virtual void setShieldTime(float t);
// ------------------------------------------------------------------------
/** Returns if the kart is protected by a shield. */
virtual bool isShielded() const;
// ------------------------------------------------------------------------
/** Returns the remaining time the kart is protected by a shield. */
virtual float getShieldTime() const;
// ------------------------------------------------------------------------
/** Decreases the kart's shield time. */
//If t = 0.0f: decrease shield time by the default amount.
virtual void decreaseShieldTime(float t);
// ------------------------------------------------------------------------
/** Sets the energy the kart has collected. */ /** Sets the energy the kart has collected. */
virtual void setEnergy(float val) { m_collected_energy = val; } virtual void setEnergy(float val) { m_collected_energy = val; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -76,7 +76,7 @@ void KartWithStats::update(float dt)
*/ */
void KartWithStats::setKartAnimation(AbstractKartAnimation *ka) void KartWithStats::setKartAnimation(AbstractKartAnimation *ka)
{ {
bool is_new = !getKartAnimation() && !isInvulnerable(); bool is_new = !getKartAnimation() && !isInvulnerable() && !isShielded();
Kart::setKartAnimation(ka); Kart::setKartAnimation(ka);
// Nothing to count if it's not a new animation // Nothing to count if it's not a new animation
if(!is_new) return; if(!is_new) return;

View File

@ -223,11 +223,15 @@ void Physics::update(float dt)
// -------------------- // --------------------
// Only explode a bowling ball if the target is // Only explode a bowling ball if the target is
// not invulnerable // not invulnerable
AbstractKart* target_kart = p->getUserPointer(1)->getPointerKart();
if(p->getUserPointer(0)->getPointerFlyable()->getType() if(p->getUserPointer(0)->getPointerFlyable()->getType()
!=PowerupManager::POWERUP_BOWLING || !=PowerupManager::POWERUP_BOWLING ||
!p->getUserPointer(1)->getPointerKart()->isInvulnerable() ) !target_kart->isInvulnerable() )
{
p->getUserPointer(0)->getPointerFlyable() p->getUserPointer(0)->getPointerFlyable()
->hit(p->getUserPointer(1)->getPointerKart()); ->hit(target_kart);
}
} }
else else
{ {