stk-code_catmod/src/items/plunger.cpp
auria 68fdb1b971 Another step to make STK more lively in the audio department : add a sound when receiving a plunger in the face
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@11740 178a84e3-b1eb-0310-8ba1-8eac791a3b58
2012-10-23 00:19:58 +00:00

253 lines
8.8 KiB
C++

//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2007 Joerg Henrichs
//
// Physics improvements and linear intersection algorithm by
// by David Mikos. Copyright (C) 2009.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "items/plunger.hpp"
#include "graphics/irr_driver.hpp"
#include "io/xml_node.hpp"
#include "items/rubber_band.hpp"
#include "items/projectile_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/kart_properties.hpp"
#include "modes/world.hpp"
#include "physics/physical_object.hpp"
#include "physics/physics.hpp"
#include "tracks/track.hpp"
#include "utils/constants.hpp"
#include "utils/string_utils.hpp"
// -----------------------------------------------------------------------------
Plunger::Plunger(AbstractKart *kart)
: Flyable(kart, PowerupManager::POWERUP_PLUNGER)
{
const float gravity = 0.0f;
float forward_offset = 0.5f*kart->getKartLength()+0.5f*m_extend.getZ();
float up_velocity = 0.0f;
float plunger_speed = 2 * m_speed;
// if the kart is looking backwards, release from the back
m_reverse_mode = kart->getControls().m_look_back;
// find closest kart in front of the current one
const AbstractKart *closest_kart=0;
Vec3 direction;
float kart_dist_2;
getClosestKart(&closest_kart, &kart_dist_2, &direction,
kart /* search in front of this kart */, m_reverse_mode);
btTransform kart_transform = kart->getAlignedTransform();
btMatrix3x3 kart_rotation = kart_transform.getBasis();
// The current forward vector is rotation*(0,0,1), or:
btVector3 forward(kart_rotation.getColumn(2));
float heading =kart->getHeading();
float pitch = kart->getTerrainPitch(heading);
// aim at this kart if it's not too far
if(closest_kart != NULL && kart_dist_2 < 30*30)
{
float fire_angle = 0.0f;
getLinearKartItemIntersection (kart->getXYZ(), closest_kart,
plunger_speed, gravity, forward_offset,
&fire_angle, &up_velocity);
btTransform trans = kart->getTrans();
trans.setRotation(btQuaternion(btVector3(0, 1, 0), fire_angle));
m_initial_velocity = btVector3(0.0f, up_velocity, plunger_speed);
createPhysics(forward_offset, m_initial_velocity,
new btCylinderShape(0.5f*m_extend),
0.5f /* restitution */ , gravity,
/* rotates */false , /*turn around*/false, &trans);
}
else
{
createPhysics(forward_offset, btVector3(pitch, 0.0f, plunger_speed),
new btCylinderShape(0.5f*m_extend),
0.5f /* restitution */, gravity,
false /* rotates */, m_reverse_mode, &kart_transform);
}
//adjust height according to terrain
setAdjustUpVelocity(false);
// pulling back makes no sense in battle mode, since this mode is not a race.
// so in battle mode, always hide view
if( m_reverse_mode || race_manager->isBattleMode() )
m_rubber_band = NULL;
else
{
m_rubber_band = new RubberBand(this, kart);
}
m_keep_alive = -1;
} // Plunger
// ----------------------------------------------------------------------------
Plunger::~Plunger()
{
if(m_rubber_band)
delete m_rubber_band;
} // ~Plunger
// ----------------------------------------------------------------------------
void Plunger::init(const XMLNode &node, scene::IMesh *plunger_model)
{
Flyable::init(node, plunger_model, PowerupManager::POWERUP_PLUNGER);
} // init
// ----------------------------------------------------------------------------
/** Picks a random message to be displayed when a kart is hit by a plunger.
* \param The kart that was hit (ignored here).
* \returns The string to display.
*/
const core::stringw Plunger::getHitString(const AbstractKart *kart) const
{
const int PLUNGER_IN_FACE_STRINGS_AMOUNT = 2;
RandomGenerator r;
switch (r.get(PLUNGER_IN_FACE_STRINGS_AMOUNT))
{
//I18N: shown when a player receives a plunger in his face
case 0: return _LTR("%0 gets a fancy mask from %1");
//I18N: shown when a player receives a plunger in his face
case 1: return _LTR("%1 merges %0's face with a plunger");
default:assert(false); return L""; // avoid compiler warning
}
} // getHitString
// ----------------------------------------------------------------------------
/** Updates the bowling ball ineach frame. If this function returns true, the
* object will be removed by the projectile manager.
* \param dt Time step size.
* \returns True of this object should be removed.
*/
bool Plunger::updateAndDelete(float dt)
{
// In keep-alive mode, just update the rubber band
if(m_keep_alive >= 0)
{
m_keep_alive -= dt;
if(m_keep_alive<=0)
{
setHasHit();
return true;
}
if(m_rubber_band != NULL) m_rubber_band->update(dt);
return false;
}
// Else: update the flyable and rubber band
bool ret = Flyable::updateAndDelete(dt);
if(m_rubber_band != NULL) m_rubber_band->update(dt);
return ret;
} // updateAndDelete
// -----------------------------------------------------------------------------
/** Virtual function called when the plunger hits something.
* The plunger is special in that it is not deleted when hitting an object.
* Instead it stays around (though not as a graphical or physical object)
* till the rubber band expires.
* \param kart Pointer to the kart hit (NULL if not a kart).
* \param obj Pointer to PhysicalObject object if hit (NULL otherwise).
* \returns True if there was actually a hit (i.e. not owner, and target is
* not immune), false otherwise.
*/
bool Plunger::hit(AbstractKart *kart, PhysicalObject *obj)
{
if(isOwnerImmunity(kart)) return false;
RaceGUIBase* gui = World::getWorld()->getRaceGUI();
irr::core::stringw hit_message;
// pulling back makes no sense in battle mode, since this mode is not a race.
// so in battle mode, always hide view
if( m_reverse_mode || race_manager->isBattleMode() )
{
if(kart)
{
kart->blockViewWithPlunger();
if (kart->getController()->isPlayerController())
sfx_manager->quickSound("plunger");
hit_message += StringUtils::insertValues(getHitString(kart),
core::stringw(kart->getName()),
core::stringw(m_owner->getName())
).c_str();
gui->addMessage(translations->fribidize(hit_message), NULL, 3.0f,
video::SColor(255, 255, 255, 255), false);
}
m_keep_alive = 0;
// Make this object invisible.
getNode()->setVisible(false);
World::getWorld()->getPhysics()->removeBody(getBody());
}
else
{
m_keep_alive = m_owner->getKartProperties()->getRubberBandDuration();
// Make this object invisible by placing it faaar down. Not that if this
// objects is simply removed from the scene graph, it might be auto-deleted
// because the ref count reaches zero.
scene::ISceneNode *node = getNode();
if(node)
{
node->setVisible(false);
}
World::getWorld()->getPhysics()->removeBody(getBody());
if(kart)
{
m_rubber_band->hit(kart);
return false;
}
else if(obj)
{
Vec3 pos(obj->getBody()->getWorldTransform().getOrigin());
m_rubber_band->hit(NULL, &pos);
}
else
{
m_rubber_band->hit(NULL, &(getXYZ()));
}
}
// Rubber band attached.
return false;
} // hit
// -----------------------------------------------------------------------------
/** Called when the plunger hits the track. In this case, notify the rubber
* band, and remove the plunger (but keep it alive).
*/
void Plunger::hitTrack()
{
hit(NULL, NULL);
} // hitTrack
// -----------------------------------------------------------------------------