Clean up the firing of flyables in network
This commit is contained in:
@@ -37,50 +37,9 @@ Bowling::Bowling(AbstractKart *kart)
|
||||
: Flyable(kart, PowerupManager::POWERUP_BOWLING, 50.0f /* mass */)
|
||||
{
|
||||
m_has_hit_kart = false;
|
||||
float y_offset = 0.5f*kart->getKartLength() + m_extend.getZ()*0.5f;
|
||||
|
||||
// if the kart is looking backwards, release from the back
|
||||
if( kart->getControls().getLookBack())
|
||||
{
|
||||
y_offset = -y_offset;
|
||||
m_speed = -m_speed*2;
|
||||
}
|
||||
else
|
||||
{
|
||||
float min_speed = m_speed*4.0f;
|
||||
/* make it go faster when throwing forward
|
||||
so the player doesn't catch up with the ball
|
||||
and explode by touching it */
|
||||
m_speed = kart->getSpeed() + m_speed;
|
||||
if(m_speed < min_speed) m_speed = min_speed;
|
||||
}
|
||||
|
||||
const Vec3& normal = kart->getNormal();
|
||||
createPhysics(y_offset, btVector3(0.0f, 0.0f, m_speed*2),
|
||||
new btSphereShape(0.5f*m_extend.getY()),
|
||||
0.4f /*restitution*/,
|
||||
-70.0f*normal /*gravity*/,
|
||||
true /*rotates*/);
|
||||
// Even if the ball is fired backwards, m_speed must be positive,
|
||||
// otherwise the ball can start to vibrate when energy is added.
|
||||
m_speed = fabsf(m_speed);
|
||||
// Do not adjust the up velociy depending on height above terrain, since
|
||||
// this would disable gravity.
|
||||
setAdjustUpVelocity(false);
|
||||
|
||||
// unset no_contact_response flags, so that the ball
|
||||
// will bounce off the track
|
||||
int flag = getBody()->getCollisionFlags();
|
||||
flag = flag & (~ btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
||||
getBody()->setCollisionFlags(flag);
|
||||
|
||||
// should not live forever, auto-destruct after 20 seconds
|
||||
m_max_lifespan = stk_config->time2Ticks(20);
|
||||
|
||||
m_roll_sfx = SFXManager::get()->createSoundSource("bowling_roll");
|
||||
m_roll_sfx->play();
|
||||
m_roll_sfx->setLoop(true);
|
||||
|
||||
} // Bowling
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -89,9 +48,7 @@ Bowling::Bowling(AbstractKart *kart)
|
||||
Bowling::~Bowling()
|
||||
{
|
||||
// This will stop the sfx and delete the object.
|
||||
if (m_roll_sfx)
|
||||
m_roll_sfx->deleteSFX();
|
||||
|
||||
removeRollSfx();
|
||||
} // ~RubberBall
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -121,8 +78,11 @@ void Bowling::init(const XMLNode &node, scene::IMesh *bowling)
|
||||
bool Bowling::updateAndDelete(int ticks)
|
||||
{
|
||||
bool can_be_deleted = Flyable::updateAndDelete(ticks);
|
||||
if(can_be_deleted)
|
||||
if (can_be_deleted)
|
||||
{
|
||||
removeRollSfx();
|
||||
return true;
|
||||
}
|
||||
|
||||
const AbstractKart *kart=0;
|
||||
Vec3 direction;
|
||||
@@ -153,6 +113,7 @@ bool Bowling::updateAndDelete(int ticks)
|
||||
if(!material || material->isDriveReset())
|
||||
{
|
||||
hit(NULL);
|
||||
removeRollSfx();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -172,6 +133,7 @@ bool Bowling::updateAndDelete(int ticks)
|
||||
if(vlen<0.1)
|
||||
{
|
||||
hit(NULL);
|
||||
removeRollSfx();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -180,6 +142,7 @@ bool Bowling::updateAndDelete(int ticks)
|
||||
|
||||
return false;
|
||||
} // updateAndDelete
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Callback from the physics in case that a kart or physical object is hit.
|
||||
* The bowling ball triggers an explosion when hit.
|
||||
@@ -208,15 +171,14 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj)
|
||||
} // hit
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Bowling::hideNodeWhenUndoDestruction()
|
||||
void Bowling::removeRollSfx()
|
||||
{
|
||||
Flyable::hideNodeWhenUndoDestruction();
|
||||
if (m_roll_sfx)
|
||||
{
|
||||
m_roll_sfx->deleteSFX();
|
||||
m_roll_sfx = NULL;
|
||||
}
|
||||
} // hideNodeWhenUndoDestruction
|
||||
} // removeRollSfx
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns the hit effect object to use when this objects hits something.
|
||||
@@ -224,8 +186,57 @@ void Bowling::hideNodeWhenUndoDestruction()
|
||||
*/
|
||||
HitEffect* Bowling::getHitEffect() const
|
||||
{
|
||||
if (m_deleted_once)
|
||||
return NULL;
|
||||
if(m_has_hit_kart)
|
||||
return new HitSFX(getXYZ(), "strike");
|
||||
else
|
||||
return new HitSFX(getXYZ(), "crash");
|
||||
} // getHitEffect
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Bowling::onFireFlyable()
|
||||
{
|
||||
Flyable::onFireFlyable();
|
||||
|
||||
m_has_hit_kart = false;
|
||||
float y_offset = 0.5f*m_owner->getKartLength() + m_extend.getZ()*0.5f;
|
||||
|
||||
// if the kart is looking backwards, release from the back
|
||||
if( m_owner->getControls().getLookBack())
|
||||
{
|
||||
y_offset = -y_offset;
|
||||
m_speed = -m_speed*2;
|
||||
}
|
||||
else
|
||||
{
|
||||
float min_speed = m_speed*4.0f;
|
||||
/* make it go faster when throwing forward
|
||||
so the player doesn't catch up with the ball
|
||||
and explode by touching it */
|
||||
m_speed = m_owner->getSpeed() + m_speed;
|
||||
if(m_speed < min_speed) m_speed = min_speed;
|
||||
}
|
||||
|
||||
const Vec3& normal = m_owner->getNormal();
|
||||
createPhysics(y_offset, btVector3(0.0f, 0.0f, m_speed*2),
|
||||
new btSphereShape(0.5f*m_extend.getY()),
|
||||
0.4f /*restitution*/,
|
||||
-70.0f*normal /*gravity*/,
|
||||
true /*rotates*/);
|
||||
// Even if the ball is fired backwards, m_speed must be positive,
|
||||
// otherwise the ball can start to vibrate when energy is added.
|
||||
m_speed = fabsf(m_speed);
|
||||
// Do not adjust the up velociy depending on height above terrain, since
|
||||
// this would disable gravity.
|
||||
setAdjustUpVelocity(false);
|
||||
|
||||
// unset no_contact_response flags, so that the ball
|
||||
// will bounce off the track
|
||||
int flag = getBody()->getCollisionFlags();
|
||||
flag = flag & (~ btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
||||
getBody()->setCollisionFlags(flag);
|
||||
|
||||
// should not live forever, auto-destruct after 20 seconds
|
||||
m_max_lifespan = stk_config->time2Ticks(20);
|
||||
} // onFireFlyable
|
||||
|
||||
@@ -48,7 +48,7 @@ private:
|
||||
|
||||
/** A sound effect for rolling ball. */
|
||||
SFXBase *m_roll_sfx;
|
||||
virtual void hideNodeWhenUndoDestruction() OVERRIDE;
|
||||
void removeRollSfx();
|
||||
|
||||
public:
|
||||
Bowling(AbstractKart* kart);
|
||||
@@ -57,7 +57,8 @@ public:
|
||||
virtual bool updateAndDelete(int ticks) OVERRIDE;
|
||||
virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL) OVERRIDE;
|
||||
virtual HitEffect *getHitEffect() const OVERRIDE;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void onFireFlyable() OVERRIDE;
|
||||
|
||||
}; // Bowling
|
||||
|
||||
|
||||
@@ -34,92 +34,6 @@ float Cake::m_gravity;
|
||||
Cake::Cake (AbstractKart *kart) : Flyable(kart, PowerupManager::POWERUP_CAKE)
|
||||
{
|
||||
m_target = NULL;
|
||||
|
||||
setDoTerrainInfo(false);
|
||||
|
||||
btVector3 gravity_vector;
|
||||
btQuaternion q = kart->getTrans().getRotation();
|
||||
gravity_vector = Vec3(0, -1, 0).rotate(q.getAxis(), q.getAngle());
|
||||
gravity_vector = gravity_vector.normalize() * m_gravity;
|
||||
// A bit of a hack: the mass of this kinematic object is still 1.0
|
||||
// (see flyable), which enables collisions. I tried setting
|
||||
// collisionFilterGroup/mask, but still couldn't get this object to
|
||||
// collide with the track. By setting the mass to 1, collisions happen.
|
||||
// (if bullet is compiled with _DEBUG, a warning will be printed the first
|
||||
// time a homing-track collision happens).
|
||||
float forward_offset=kart->getKartLength()/2.0f + m_extend.getZ()/2.0f;
|
||||
|
||||
float up_velocity = m_speed/7.0f;
|
||||
|
||||
// give a speed proportional to kart speed. m_speed is defined in flyable
|
||||
m_speed *= kart->getSpeed() / 23.0f;
|
||||
|
||||
//when going backwards, decrease speed of cake by less
|
||||
if (kart->getSpeed() < 0) m_speed /= 3.6f;
|
||||
|
||||
m_speed += 16.0f;
|
||||
|
||||
if (m_speed < 1.0f) m_speed = 1.0f;
|
||||
|
||||
btTransform trans = kart->getTrans();
|
||||
|
||||
float heading=kart->getHeading();
|
||||
float pitch = kart->getTerrainPitch(heading);
|
||||
|
||||
// Find closest kart in front of the current one
|
||||
const bool backwards = kart->getControls().getLookBack();
|
||||
const AbstractKart *closest_kart=NULL;
|
||||
Vec3 direction;
|
||||
float kart_dist_squared;
|
||||
getClosestKart(&closest_kart, &kart_dist_squared, &direction,
|
||||
kart /* search in front of this kart */, backwards);
|
||||
|
||||
// aim at this kart if 1) it's not too far, 2) if the aimed kart's speed
|
||||
// allows the projectile to catch up with it
|
||||
//
|
||||
// this code finds the correct angle and upwards velocity to hit an opponents'
|
||||
// vehicle if they were to continue travelling in the same direction and same speed
|
||||
// (barring any obstacles in the way of course)
|
||||
if(closest_kart != NULL && kart_dist_squared < m_st_max_distance_squared &&
|
||||
m_speed>closest_kart->getSpeed())
|
||||
{
|
||||
m_target = (AbstractKart*)closest_kart;
|
||||
|
||||
float fire_angle = 0.0f;
|
||||
getLinearKartItemIntersection (kart->getXYZ(), closest_kart,
|
||||
m_speed, m_gravity, forward_offset,
|
||||
&fire_angle, &up_velocity);
|
||||
|
||||
// apply transformation to the bullet object (without pitch)
|
||||
btQuaternion q;
|
||||
q = trans.getRotation() * btQuaternion(btVector3(0, 1, 0), fire_angle);
|
||||
trans.setRotation(q);
|
||||
m_initial_velocity = Vec3(0.0f, up_velocity, m_speed);
|
||||
|
||||
createPhysics(forward_offset, m_initial_velocity,
|
||||
new btCylinderShape(0.5f*m_extend),
|
||||
0.5f /* restitution */, gravity_vector,
|
||||
true /* rotation */, false /* backwards */, &trans);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_target = NULL;
|
||||
// kart is too far to be hit. so throw the projectile in a generic way,
|
||||
// straight ahead, without trying to hit anything in particular
|
||||
trans = kart->getAlignedTransform(pitch);
|
||||
|
||||
m_initial_velocity = Vec3(0.0f, up_velocity, m_speed);
|
||||
|
||||
createPhysics(forward_offset, m_initial_velocity,
|
||||
new btCylinderShape(0.5f*m_extend),
|
||||
0.5f /* restitution */, gravity_vector,
|
||||
true /* rotation */, backwards, &trans);
|
||||
}
|
||||
|
||||
|
||||
//do not adjust height according to terrain
|
||||
setAdjustUpVelocity(false);
|
||||
additionalPhysicsProperties();
|
||||
} // Cake
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -162,3 +76,95 @@ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj)
|
||||
|
||||
return was_real_hit;
|
||||
} // hit
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Cake::onFireFlyable()
|
||||
{
|
||||
Flyable::onFireFlyable();
|
||||
setDoTerrainInfo(false);
|
||||
|
||||
btVector3 gravity_vector;
|
||||
btQuaternion q = m_owner->getTrans().getRotation();
|
||||
gravity_vector = Vec3(0, -1, 0).rotate(q.getAxis(), q.getAngle());
|
||||
gravity_vector = gravity_vector.normalize() * m_gravity;
|
||||
// A bit of a hack: the mass of this kinematic object is still 1.0
|
||||
// (see flyable), which enables collisions. I tried setting
|
||||
// collisionFilterGroup/mask, but still couldn't get this object to
|
||||
// collide with the track. By setting the mass to 1, collisions happen.
|
||||
// (if bullet is compiled with _DEBUG, a warning will be printed the first
|
||||
// time a homing-track collision happens).
|
||||
float forward_offset=m_owner->getKartLength()/2.0f + m_extend.getZ()/2.0f;
|
||||
|
||||
float up_velocity = m_speed/7.0f;
|
||||
|
||||
// give a speed proportional to kart speed. m_speed is defined in flyable
|
||||
m_speed *= m_owner->getSpeed() / 23.0f;
|
||||
|
||||
//when going backwards, decrease speed of cake by less
|
||||
if (m_owner->getSpeed() < 0) m_speed /= 3.6f;
|
||||
|
||||
m_speed += 16.0f;
|
||||
|
||||
if (m_speed < 1.0f) m_speed = 1.0f;
|
||||
|
||||
btTransform trans = m_owner->getTrans();
|
||||
|
||||
float heading=m_owner->getHeading();
|
||||
float pitch = m_owner->getTerrainPitch(heading);
|
||||
|
||||
// Find closest kart in front of the current one
|
||||
const bool backwards = m_owner->getControls().getLookBack();
|
||||
const AbstractKart *closest_kart=NULL;
|
||||
Vec3 direction;
|
||||
float kart_dist_squared;
|
||||
getClosestKart(&closest_kart, &kart_dist_squared, &direction,
|
||||
m_owner /* search in front of this kart */, backwards);
|
||||
|
||||
// aim at this kart if 1) it's not too far, 2) if the aimed kart's speed
|
||||
// allows the projectile to catch up with it
|
||||
//
|
||||
// this code finds the correct angle and upwards velocity to hit an opponents'
|
||||
// vehicle if they were to continue travelling in the same direction and same speed
|
||||
// (barring any obstacles in the way of course)
|
||||
if(closest_kart != NULL && kart_dist_squared < m_st_max_distance_squared &&
|
||||
m_speed>closest_kart->getSpeed())
|
||||
{
|
||||
m_target = (AbstractKart*)closest_kart;
|
||||
|
||||
float fire_angle = 0.0f;
|
||||
getLinearKartItemIntersection (m_owner->getXYZ(), closest_kart,
|
||||
m_speed, m_gravity, forward_offset,
|
||||
&fire_angle, &up_velocity);
|
||||
|
||||
// apply transformation to the bullet object (without pitch)
|
||||
btQuaternion q;
|
||||
q = trans.getRotation() * btQuaternion(btVector3(0, 1, 0), fire_angle);
|
||||
trans.setRotation(q);
|
||||
m_initial_velocity = Vec3(0.0f, up_velocity, m_speed);
|
||||
|
||||
createPhysics(forward_offset, m_initial_velocity,
|
||||
new btCylinderShape(0.5f*m_extend),
|
||||
0.5f /* restitution */, gravity_vector,
|
||||
true /* rotation */, false /* backwards */, &trans);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_target = NULL;
|
||||
// kart is too far to be hit. so throw the projectile in a generic way,
|
||||
// straight ahead, without trying to hit anything in particular
|
||||
trans = m_owner->getAlignedTransform(pitch);
|
||||
|
||||
m_initial_velocity = Vec3(0.0f, up_velocity, m_speed);
|
||||
|
||||
createPhysics(forward_offset, m_initial_velocity,
|
||||
new btCylinderShape(0.5f*m_extend),
|
||||
0.5f /* restitution */, gravity_vector,
|
||||
true /* rotation */, backwards, &trans);
|
||||
}
|
||||
|
||||
//do not adjust height according to terrain
|
||||
setAdjustUpVelocity(false);
|
||||
m_body->setActivationState(DISABLE_DEACTIVATION);
|
||||
m_body->clearForces();
|
||||
m_body->applyTorque(btVector3(5.0f, -3.0f, 7.0f));
|
||||
} // onFireFlyable
|
||||
|
||||
@@ -47,20 +47,17 @@ private:
|
||||
/** Which kart is targeted by this projectile (NULL if none). */
|
||||
Moveable* m_target;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void additionalPhysicsProperties() OVERRIDE
|
||||
{
|
||||
m_body->setActivationState(DISABLE_DEACTIVATION);
|
||||
m_body->clearForces();
|
||||
m_body->applyTorque(btVector3(5.0f, -3.0f, 7.0f));
|
||||
}
|
||||
|
||||
public:
|
||||
Cake (AbstractKart *kart);
|
||||
static void init (const XMLNode &node, scene::IMesh *cake_model);
|
||||
virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL) OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void hitTrack () OVERRIDE { hit(NULL); }
|
||||
virtual void hitTrack () OVERRIDE
|
||||
{
|
||||
if (!m_has_server_state)
|
||||
return;
|
||||
hit(NULL);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Kinematic objects are not allowed to have a velocity (assertion in
|
||||
* bullet), so we have to do our own velocity handling here. This
|
||||
@@ -75,7 +72,8 @@ public:
|
||||
*/
|
||||
virtual void setVelocity(const btVector3& v) OVERRIDE
|
||||
{ m_initial_velocity = v; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void onFireFlyable() OVERRIDE;
|
||||
}; // Cake
|
||||
|
||||
#endif
|
||||
|
||||
@@ -40,9 +40,7 @@
|
||||
#include "karts/explosion_animation.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "network/compress_network_body.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_string.hpp"
|
||||
#include "network/rewind_info.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
@@ -61,7 +59,7 @@ Vec3 Flyable::m_st_extend [PowerupManager::POWERUP_MAX];
|
||||
|
||||
Flyable::Flyable(AbstractKart *kart, PowerupManager::PowerupType type,
|
||||
float mass)
|
||||
: Moveable(), TerrainInfo()
|
||||
: Moveable(), TerrainInfo(), m_mass(mass)
|
||||
{
|
||||
// get the appropriate data from the static fields
|
||||
m_speed = m_st_speed[type];
|
||||
@@ -75,17 +73,16 @@ Flyable::Flyable(AbstractKart *kart, PowerupManager::PowerupType type,
|
||||
m_has_hit_something = false;
|
||||
m_shape = NULL;
|
||||
m_animation = NULL;
|
||||
m_mass = mass;
|
||||
m_adjust_up_velocity = true;
|
||||
m_ticks_since_thrown = 0;
|
||||
m_position_offset = Vec3(0,0,0);
|
||||
m_owner_has_temporary_immunity = true;
|
||||
m_do_terrain_info = true;
|
||||
m_deleted_once = false;
|
||||
m_max_lifespan = -1;
|
||||
m_undo_creation = false;
|
||||
m_has_undone_destruction = false;
|
||||
m_has_server_state = false;
|
||||
m_check_created_ticks = -1;
|
||||
// It will be reset for each state restore
|
||||
m_has_server_state = true;
|
||||
m_last_deleted_ticks = -1;
|
||||
|
||||
// Add the graphical model
|
||||
#ifndef SERVER_ONLY
|
||||
@@ -96,6 +93,9 @@ Flyable::Flyable(AbstractKart *kart, PowerupManager::PowerupType type,
|
||||
getNode()->setName(debug_name.c_str());
|
||||
#endif
|
||||
#endif
|
||||
// Smooth network body for flyable doesn't seem to be needed, most of the
|
||||
// time it rewinds almost the same
|
||||
SmoothNetworkBody::setEnable(false);
|
||||
} // Flyable
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -118,6 +118,8 @@ void Flyable::createPhysics(float forw_offset, const Vec3 &velocity,
|
||||
const bool rotates, const bool turn_around,
|
||||
const btTransform* custom_direction)
|
||||
{
|
||||
// Remove previously physics data if any
|
||||
removePhysics();
|
||||
// Get Kart heading direction
|
||||
btTransform trans = ( !custom_direction ? m_owner->getAlignedTransform()
|
||||
: *custom_direction );
|
||||
@@ -170,11 +172,6 @@ void Flyable::createPhysics(float forw_offset, const Vec3 &velocity,
|
||||
}
|
||||
m_body->setCollisionFlags(m_body->getCollisionFlags() |
|
||||
btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
||||
|
||||
m_saved_transform = getTrans();
|
||||
m_saved_lv = m_body->getLinearVelocity();
|
||||
m_saved_av = m_body->getAngularVelocity();
|
||||
m_saved_gravity = gravity;
|
||||
} // createPhysics
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -206,10 +203,25 @@ void Flyable::init(const XMLNode &node, scene::IMesh *model,
|
||||
//-----------------------------------------------------------------------------
|
||||
Flyable::~Flyable()
|
||||
{
|
||||
if(m_shape) delete m_shape;
|
||||
Physics::getInstance()->removeBody(getBody());
|
||||
removePhysics();
|
||||
} // ~Flyable
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/* Called when delete this flyable or re-firing during rewind. */
|
||||
void Flyable::removePhysics()
|
||||
{
|
||||
if (m_shape)
|
||||
{
|
||||
delete m_shape;
|
||||
m_shape = NULL;
|
||||
}
|
||||
if (m_body.get())
|
||||
{
|
||||
Physics::getInstance()->removeBody(m_body.get());
|
||||
m_body.reset();
|
||||
}
|
||||
} // removePhysics
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns information on what is the closest kart and at what distance it is.
|
||||
* All 3 parameters first are of type 'out'. 'inFrontOf' can be set if you
|
||||
@@ -395,16 +407,13 @@ void Flyable::updateGraphics(float dt)
|
||||
*/
|
||||
bool Flyable::updateAndDelete(int ticks)
|
||||
{
|
||||
if (m_undo_creation)
|
||||
if (!m_has_server_state)
|
||||
return false;
|
||||
|
||||
if (hasAnimation())
|
||||
{
|
||||
if (!RewindManager::get()->isRewinding())
|
||||
{
|
||||
m_animation->update(ticks);
|
||||
Moveable::update(ticks);
|
||||
}
|
||||
m_animation->update(ticks);
|
||||
Moveable::update(ticks);
|
||||
return false;
|
||||
} // if animation
|
||||
|
||||
@@ -513,7 +522,7 @@ bool Flyable::isOwnerImmunity(const AbstractKart* kart_hit) const
|
||||
*/
|
||||
bool Flyable::hit(AbstractKart *kart_hit, PhysicalObject* object)
|
||||
{
|
||||
if (m_undo_creation)
|
||||
if (!m_has_server_state)
|
||||
return false;
|
||||
// the owner of this flyable should not be hit by his own flyable
|
||||
if(isOwnerImmunity(kart_hit)) return false;
|
||||
@@ -586,7 +595,8 @@ void Flyable::explode(AbstractKart *kart_hit, PhysicalObject *object,
|
||||
*/
|
||||
HitEffect* Flyable::getHitEffect() const
|
||||
{
|
||||
return new Explosion(getXYZ(), "explosion", "explosion_cake.xml");
|
||||
return m_deleted_once ? NULL :
|
||||
new Explosion(getXYZ(), "explosion", "explosion_cake.xml");
|
||||
} // getHitEffect
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -596,15 +606,24 @@ unsigned int Flyable::getOwnerId()
|
||||
} // getOwnerId
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Flyable::moveToInfinity()
|
||||
/** It's called when undoing the creation or destruction of flyables, so that
|
||||
* it will not affected the current game, and it will be deleted in
|
||||
* computeError.
|
||||
* \param set_moveable_trans If true, set m_transform in moveable, so the
|
||||
* graphical node will have the same transform, otherwise only the physical
|
||||
* body will be moved to infinity
|
||||
*/
|
||||
void Flyable::moveToInfinity(bool set_moveable_trans)
|
||||
{
|
||||
const Vec3 *min, *max;
|
||||
Track::getCurrentTrack()->getAABB(&min, &max);
|
||||
btTransform t = m_body->getWorldTransform();
|
||||
t.setOrigin(*max * 2.0f);
|
||||
m_body->setWorldTransform(t);
|
||||
m_motion_state->setWorldTransform(t);
|
||||
m_body->setInterpolationWorldTransform(t);
|
||||
m_body->proceedToTransform(t);
|
||||
if (set_moveable_trans)
|
||||
setTrans(t);
|
||||
else
|
||||
m_motion_state->setWorldTransform(t);
|
||||
} // moveToInfinity
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -622,20 +641,6 @@ BareNetworkString* Flyable::saveState(std::vector<std::string>* ru)
|
||||
return buffer;
|
||||
} // saveState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
std::function<void()> Flyable::getLocalStateRestoreFunction()
|
||||
{
|
||||
// Avoid circular reference
|
||||
std::weak_ptr<Flyable> fw = getShared<Flyable>();
|
||||
return [fw]()
|
||||
{
|
||||
std::shared_ptr<Flyable> f = fw.lock();
|
||||
if (!f || f->m_has_undone_destruction)
|
||||
return;
|
||||
f->m_has_server_state = false;
|
||||
};
|
||||
} // getLocalStateRestoreFunction
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Flyable::restoreState(BareNetworkString *buffer, int count)
|
||||
{
|
||||
@@ -643,120 +648,78 @@ void Flyable::restoreState(BareNetworkString *buffer, int count)
|
||||
Vec3 lv, av;
|
||||
CompressNetworkBody::decompress(buffer, &t, &lv, &av);
|
||||
|
||||
if (!hasAnimation())
|
||||
{
|
||||
m_body->setWorldTransform(t);
|
||||
m_motion_state->setWorldTransform(t);
|
||||
m_body->setInterpolationWorldTransform(t);
|
||||
m_body->setLinearVelocity(lv);
|
||||
m_body->setAngularVelocity(av);
|
||||
m_body->setInterpolationLinearVelocity(lv);
|
||||
m_body->setInterpolationAngularVelocity(av);
|
||||
setTrans(t);
|
||||
}
|
||||
m_body->setLinearVelocity(lv);
|
||||
m_body->setAngularVelocity(av);
|
||||
m_body->proceedToTransform(t);
|
||||
setTrans(t);
|
||||
m_ticks_since_thrown = buffer->getUInt16();
|
||||
m_has_server_state = true;
|
||||
m_has_hit_something = false;
|
||||
} // restoreState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Flyable::addForRewind(const std::string& uid)
|
||||
{
|
||||
SmoothNetworkBody::setEnable(true);
|
||||
SmoothNetworkBody::setSmoothRotation(false);
|
||||
SmoothNetworkBody::setAdjustVerticalOffset(false);
|
||||
Rewinder::setUniqueIdentity(uid);
|
||||
Rewinder::rewinderAdd();
|
||||
} // addForRewind
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Flyable::addRewindInfoEventFunctionAfterFiring()
|
||||
void Flyable::saveTransform()
|
||||
{
|
||||
if (!NetworkConfig::get()->isNetworking() ||
|
||||
NetworkConfig::get()->isServer())
|
||||
return;
|
||||
|
||||
std::shared_ptr<Flyable> f = getShared<Flyable>();
|
||||
RewindManager::get()->addRewindInfoEventFunction(new
|
||||
RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(),
|
||||
/*undo_function*/[f]()
|
||||
{
|
||||
f->m_undo_creation = true;
|
||||
// Move it to infinity, avoiding affecting current rewinding
|
||||
f->moveToInfinity();
|
||||
f->m_body->setGravity(Vec3(0.0f));
|
||||
},
|
||||
/*replay_function*/[f]()
|
||||
{
|
||||
f->m_undo_creation = false;
|
||||
f->m_body->setWorldTransform(f->m_saved_transform);
|
||||
f->m_motion_state->setWorldTransform(f->m_saved_transform);
|
||||
f->m_body->setInterpolationWorldTransform(f->m_saved_transform);
|
||||
f->m_body->setLinearVelocity(f->m_saved_lv);
|
||||
f->m_body->setAngularVelocity(f->m_saved_av);
|
||||
f->m_body->setInterpolationLinearVelocity(f->m_saved_lv);
|
||||
f->m_body->setInterpolationAngularVelocity(f->m_saved_av);
|
||||
f->m_body->setGravity(f->m_saved_gravity);
|
||||
f->m_ticks_since_thrown = 0;
|
||||
f->m_has_hit_something = false;
|
||||
f->additionalPhysicsProperties();
|
||||
},
|
||||
/*delete_function*/[f]()
|
||||
{
|
||||
f->m_check_created_ticks = World::getWorld()->getTicksSinceStart();
|
||||
}));
|
||||
} // addRewindInfoEventFunctionAfterFiring
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Flyable::hideNodeWhenUndoDestruction()
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
m_node->setVisible(false);
|
||||
#endif
|
||||
// It will be overwritten in restoreState (so it's confirmed by server) or
|
||||
// onFireFlyable (before the game state all flyables are assumed to be
|
||||
// sucessfully created)
|
||||
moveToInfinity();
|
||||
} // hideNodeWhenUndoDestruction
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Flyable::handleUndoDestruction()
|
||||
{
|
||||
if (!NetworkConfig::get()->isNetworking() ||
|
||||
NetworkConfig::get()->isServer() ||
|
||||
m_has_undone_destruction)
|
||||
return;
|
||||
|
||||
m_has_undone_destruction = true;
|
||||
|
||||
// We don't bother seeing the mesh during rewinding
|
||||
hideNodeWhenUndoDestruction();
|
||||
std::shared_ptr<Flyable> f = getShared<Flyable>();
|
||||
std::string uid = f->getUniqueIdentity();
|
||||
projectile_manager->addDeletedUID(uid);
|
||||
RewindManager::get()->addRewindInfoEventFunction(new
|
||||
RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(),
|
||||
/*undo_function*/[f, uid]()
|
||||
{
|
||||
f->m_has_hit_something = false;
|
||||
projectile_manager->addByUID(uid, f);
|
||||
},
|
||||
/*replay_function*/[f, uid]()
|
||||
{
|
||||
f->m_has_hit_something = true;
|
||||
projectile_manager->removeByUID(uid);
|
||||
f->moveToInfinity();
|
||||
}));
|
||||
} // handleUndoDestruction
|
||||
m_has_server_state = false;
|
||||
m_last_deleted_ticks = -1;
|
||||
} // saveTransform
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Flyable::computeError()
|
||||
{
|
||||
Moveable::checkSmoothing();
|
||||
if (!m_has_server_state && m_check_created_ticks != -1 &&
|
||||
World::getWorld()->getTicksSinceStart() > m_check_created_ticks)
|
||||
// Remove the flyable if it doesn't exist or failed to create on server
|
||||
// For each saveTransform it will call moveToInfinity so the invalid
|
||||
// flyables won't affect the current game
|
||||
const int state_ticks = RewindManager::get()->getLatestConfirmedState();
|
||||
if (!m_has_server_state && (m_last_deleted_ticks == -1 ||
|
||||
state_ticks > m_last_deleted_ticks))
|
||||
{
|
||||
const std::string& uid = getUniqueIdentity();
|
||||
Log::warn("Flyable", "Item %s doesn't exist on server, "
|
||||
"remove it locally.", uid.c_str());
|
||||
Log::debug("Flyable", "Item %s doesn't exist on server, "
|
||||
"remove it.", uid.c_str());
|
||||
projectile_manager->removeByUID(uid);
|
||||
}
|
||||
} // computeError
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Call when the item is (re-)fired (during rewind if needed) by
|
||||
* projectile_manager. */
|
||||
void Flyable::onFireFlyable()
|
||||
{
|
||||
m_ticks_since_thrown = 0;
|
||||
m_has_hit_something = false;
|
||||
m_has_server_state = true;
|
||||
m_deleted_once = false;
|
||||
m_last_deleted_ticks = -1;
|
||||
// Reset the speed each time for (re-)firing, so subclass access with same
|
||||
// initial value
|
||||
m_speed = m_st_speed[m_type];
|
||||
m_extend = m_st_extend[m_type];
|
||||
m_max_height = m_st_max_height[m_type];
|
||||
m_min_height = m_st_min_height[m_type];
|
||||
m_average_height = (m_min_height + m_max_height) / 2.0f;
|
||||
m_force_updown = m_st_force_updown[m_type];
|
||||
} // onFireFlyable
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/* Call when deleting the flyable locally and save the deleted world ticks. */
|
||||
void Flyable::onDeleteFlyable()
|
||||
{
|
||||
m_deleted_once = true;
|
||||
m_last_deleted_ticks = World::getWorld()->getTicksSinceStart();
|
||||
m_has_server_state = false;
|
||||
moveToInfinity();
|
||||
} // onDeleteFlyable
|
||||
|
||||
/* EOF */
|
||||
|
||||
@@ -47,7 +47,6 @@ class XMLNode;
|
||||
class Flyable : public Moveable, public TerrainInfo,
|
||||
public Rewinder
|
||||
{
|
||||
public:
|
||||
private:
|
||||
bool m_has_hit_something;
|
||||
|
||||
@@ -100,15 +99,32 @@ protected:
|
||||
float m_speed;
|
||||
|
||||
/** Mass of this Flyable. */
|
||||
float m_mass;
|
||||
const float m_mass;
|
||||
|
||||
/** Size of this flyable. */
|
||||
Vec3 m_extend;
|
||||
|
||||
bool m_undo_creation;
|
||||
bool m_has_undone_destruction;
|
||||
/** Time since thrown. used so a kart can't hit himself when trying
|
||||
* something, and also to put some time limit to some collectibles */
|
||||
int16_t m_ticks_since_thrown;
|
||||
|
||||
/* True if this flyable exists in server, and will trigger a rewind.
|
||||
* For each local state it will reset it to false and call moveToInfinity,
|
||||
* and for each restoreState it will set it to true. Also when re-fire the
|
||||
* flyable during rewind it will set to true too. */
|
||||
bool m_has_server_state;
|
||||
int m_check_created_ticks;
|
||||
|
||||
/** If set to true, the kart that throwns this flyable can't collide
|
||||
* with it for a short time. */
|
||||
bool m_owner_has_temporary_immunity;
|
||||
|
||||
/* Set to true once when onDeleteFlyable, this is used to create HitEffect
|
||||
* only once. */
|
||||
bool m_deleted_once;
|
||||
|
||||
/* Save the locally detected deleted ticks, if the confirmed state world
|
||||
* ticks in computeError > this, the flyable can be deleted in client. */
|
||||
int m_last_deleted_ticks;
|
||||
|
||||
// The flyable class stores the values for each flyable type, e.g.
|
||||
// speed, min_height, max_height. These variables must be static,
|
||||
@@ -133,17 +149,10 @@ protected:
|
||||
/** Size of the model. */
|
||||
static Vec3 m_st_extend[PowerupManager::POWERUP_MAX];
|
||||
|
||||
/** Time since thrown. used so a kart can't hit himself when trying
|
||||
* something, and also to put some time limit to some collectibles */
|
||||
int16_t m_ticks_since_thrown;
|
||||
|
||||
/** Set to something > -1 if this flyable should auto-destrcut after
|
||||
* that may ticks. */
|
||||
int m_max_lifespan;
|
||||
|
||||
/** If set to true, the kart that throwns this flyable can't collide
|
||||
* with it for a short time. */
|
||||
bool m_owner_has_temporary_immunity;
|
||||
|
||||
void getClosestKart(const AbstractKart **minKart,
|
||||
float *minDistSquared,
|
||||
@@ -168,14 +177,8 @@ protected:
|
||||
const bool turn_around=false,
|
||||
const btTransform* customDirection=NULL);
|
||||
|
||||
void moveToInfinity();
|
||||
/** Used when undoing creation or destruction. */
|
||||
btTransform m_saved_transform;
|
||||
Vec3 m_saved_lv, m_saved_av, m_saved_gravity;
|
||||
|
||||
virtual void additionalPhysicsProperties() {}
|
||||
virtual void hideNodeWhenUndoDestruction();
|
||||
|
||||
void moveToInfinity(bool set_moveable_trans = true);
|
||||
void removePhysics();
|
||||
public:
|
||||
|
||||
Flyable (AbstractKart* kart,
|
||||
@@ -245,7 +248,7 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void undoState(BareNetworkString *buffer) OVERRIDE {}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void saveTransform() OVERRIDE { Moveable::prepareSmoothing(); }
|
||||
virtual void saveTransform() OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void computeError() OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -254,15 +257,14 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void restoreState(BareNetworkString *buffer, int count) OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void addRewindInfoEventFunctionAfterFiring();
|
||||
/* Return true if still in game state, or otherwise can be deleted. */
|
||||
bool hasServerState() const { return m_has_server_state; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual std::function<void()> getLocalStateRestoreFunction() OVERRIDE;
|
||||
/** Call when the item is (re-)fired (during rewind if needed) by
|
||||
* projectile_manager. */
|
||||
virtual void onFireFlyable();
|
||||
// ------------------------------------------------------------------------
|
||||
bool isUndoCreation() const { return m_undo_creation; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool hasUndoneDestruction() const { return m_has_undone_destruction; }
|
||||
// ------------------------------------------------------------------------
|
||||
void handleUndoDestruction();
|
||||
virtual void onDeleteFlyable();
|
||||
|
||||
}; // Flyable
|
||||
|
||||
|
||||
@@ -40,40 +40,57 @@
|
||||
Plunger::Plunger(AbstractKart *kart)
|
||||
: Flyable(kart, PowerupManager::POWERUP_PLUNGER)
|
||||
{
|
||||
m_has_locally_played_sound = false;
|
||||
m_moved_to_infinity = false;
|
||||
m_reverse_mode = false;
|
||||
m_rubber_band = NULL;
|
||||
} // Plunger
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
Plunger::~Plunger()
|
||||
{
|
||||
if(m_rubber_band)
|
||||
delete m_rubber_band;
|
||||
} // ~Plunger
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Plunger::onFireFlyable()
|
||||
{
|
||||
Flyable::onFireFlyable();
|
||||
m_has_locally_played_sound = false;
|
||||
m_moved_to_infinity = false;
|
||||
const float gravity = 0.0f;
|
||||
|
||||
setDoTerrainInfo(false);
|
||||
|
||||
float forward_offset = 0.5f*kart->getKartLength()+0.5f*m_extend.getZ();
|
||||
float forward_offset = 0.5f*m_owner->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().getLookBack();
|
||||
m_reverse_mode = m_owner->getControls().getLookBack();
|
||||
|
||||
// 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);
|
||||
m_owner /* search in front of this kart */, m_reverse_mode);
|
||||
|
||||
btTransform kart_transform = kart->getAlignedTransform();
|
||||
btTransform kart_transform = m_owner->getAlignedTransform();
|
||||
|
||||
float heading =kart->getHeading();
|
||||
float pitch = kart->getTerrainPitch(heading);
|
||||
float heading =m_owner->getHeading();
|
||||
float pitch = m_owner->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,
|
||||
getLinearKartItemIntersection (m_owner->getXYZ(), closest_kart,
|
||||
plunger_speed, gravity, forward_offset,
|
||||
&fire_angle, &up_velocity);
|
||||
|
||||
btTransform trans = kart->getTrans();
|
||||
btTransform trans = m_owner->getTrans();
|
||||
btQuaternion q;
|
||||
q = trans.getRotation()*(btQuaternion(btVector3(0, 1, 0), fire_angle));
|
||||
trans.setRotation(q);
|
||||
@@ -96,22 +113,22 @@ Plunger::Plunger(AbstractKart *kart)
|
||||
//adjust height according to terrain
|
||||
setAdjustUpVelocity(false);
|
||||
|
||||
m_rubber_band = NULL;
|
||||
// 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()))
|
||||
const bool create_rubber_band =
|
||||
!(m_reverse_mode || race_manager->isBattleMode());
|
||||
if (create_rubber_band && !m_rubber_band)
|
||||
m_rubber_band = new RubberBand(this, m_owner);
|
||||
else if (!create_rubber_band && m_rubber_band)
|
||||
{
|
||||
m_rubber_band = new RubberBand(this, kart);
|
||||
}
|
||||
additionalPhysicsProperties();
|
||||
} // Plunger
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
Plunger::~Plunger()
|
||||
{
|
||||
if(m_rubber_band)
|
||||
delete m_rubber_band;
|
||||
} // ~Plunger
|
||||
m_rubber_band = NULL;
|
||||
}
|
||||
|
||||
if (m_rubber_band)
|
||||
m_rubber_band->reset();
|
||||
|
||||
m_keep_alive = -1;
|
||||
m_moved_to_infinity = false;
|
||||
} // onFireFlyable
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Plunger::init(const XMLNode &node, scene::IMesh *plunger_model)
|
||||
@@ -123,6 +140,13 @@ void Plunger::init(const XMLNode &node, scene::IMesh *plunger_model)
|
||||
void Plunger::updateGraphics(float dt)
|
||||
{
|
||||
Flyable::updateGraphics(dt);
|
||||
#ifndef SERVER_ONLY
|
||||
scene::ISceneNode *node = getNode();
|
||||
if (node && m_moved_to_infinity)
|
||||
node->setVisible(false);
|
||||
else if (node && !m_moved_to_infinity)
|
||||
node->setVisible(true);
|
||||
#endif
|
||||
if (m_rubber_band)
|
||||
m_rubber_band->updateGraphics(dt);
|
||||
} // updateGraphics
|
||||
@@ -155,7 +179,6 @@ bool Plunger::updateAndDelete(int ticks)
|
||||
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.
|
||||
@@ -168,7 +191,7 @@ bool Plunger::updateAndDelete(int ticks)
|
||||
*/
|
||||
bool Plunger::hit(AbstractKart *kart, PhysicalObject *obj)
|
||||
{
|
||||
if (isOwnerImmunity(kart) || m_moved_to_infinity || m_undo_creation)
|
||||
if (isOwnerImmunity(kart) || m_moved_to_infinity || !m_has_server_state)
|
||||
return false;
|
||||
|
||||
// pulling back makes no sense in battle mode, since this mode is not a race.
|
||||
@@ -187,37 +210,17 @@ bool Plunger::hit(AbstractKart *kart, PhysicalObject *obj)
|
||||
}
|
||||
|
||||
m_keep_alive = 0;
|
||||
// Make this object invisible.
|
||||
#ifndef SERVER_ONLY
|
||||
getNode()->setVisible(false);
|
||||
#endif
|
||||
// Previously removeBody will break rewind
|
||||
moveToInfinity();
|
||||
moveToInfinity(false/*set_moveable_trans*/);
|
||||
m_moved_to_infinity = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_keep_alive = stk_config->time2Ticks(m_owner->getKartProperties()
|
||||
->getPlungerBandDuration() );
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
// 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);
|
||||
}
|
||||
#endif
|
||||
// Previously removeBody will break rewind
|
||||
moveToInfinity();
|
||||
m_moved_to_infinity = true;
|
||||
|
||||
m_keep_alive = (int16_t)stk_config->time2Ticks(m_owner->getKartProperties()
|
||||
->getPlungerBandDuration());
|
||||
if(kart)
|
||||
{
|
||||
m_rubber_band->hit(kart);
|
||||
return false;
|
||||
}
|
||||
else if(obj)
|
||||
{
|
||||
@@ -228,6 +231,9 @@ bool Plunger::hit(AbstractKart *kart, PhysicalObject *obj)
|
||||
{
|
||||
m_rubber_band->hit(NULL, &(getXYZ()));
|
||||
}
|
||||
// Previously removeBody will break rewind
|
||||
moveToInfinity(false/*set_moveable_trans*/);
|
||||
m_moved_to_infinity = true;
|
||||
}
|
||||
|
||||
// Rubber band attached.
|
||||
@@ -240,17 +246,11 @@ bool Plunger::hit(AbstractKart *kart, PhysicalObject *obj)
|
||||
*/
|
||||
void Plunger::hitTrack()
|
||||
{
|
||||
if (m_moved_to_infinity || !m_has_server_state)
|
||||
return;
|
||||
hit(NULL, NULL);
|
||||
} // hitTrack
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Plunger::hideNodeWhenUndoDestruction()
|
||||
{
|
||||
Flyable::hideNodeWhenUndoDestruction();
|
||||
if (m_rubber_band)
|
||||
m_rubber_band->remove();
|
||||
} // hideNodeWhenUndoDestruction
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
BareNetworkString* Plunger::saveState(std::vector<std::string>* ru)
|
||||
{
|
||||
@@ -271,7 +271,15 @@ void Plunger::restoreState(BareNetworkString *buffer, int count)
|
||||
{
|
||||
Flyable::restoreState(buffer, count);
|
||||
m_keep_alive = buffer->getUInt16();
|
||||
m_moved_to_infinity = false;
|
||||
// Restore position base on m_keep_alive in Plunger::hit
|
||||
if (m_keep_alive == -1)
|
||||
m_moved_to_infinity = false;
|
||||
else
|
||||
{
|
||||
moveToInfinity(false/*set_moveable_trans*/);
|
||||
m_moved_to_infinity = true;
|
||||
}
|
||||
|
||||
uint8_t bit_state = buffer->getUInt8();
|
||||
if (bit_state == 255 && m_rubber_band)
|
||||
{
|
||||
@@ -289,3 +297,11 @@ void Plunger::restoreState(BareNetworkString *buffer, int count)
|
||||
if (bit_state != 255)
|
||||
m_rubber_band->set8BitState(bit_state);
|
||||
} // restoreState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Plunger::onDeleteFlyable()
|
||||
{
|
||||
Flyable::onDeleteFlyable();
|
||||
if (m_rubber_band)
|
||||
m_rubber_band->remove();
|
||||
} // onDeleteFlyable
|
||||
|
||||
@@ -48,12 +48,6 @@ private:
|
||||
|
||||
bool m_reverse_mode, m_has_locally_played_sound, m_moved_to_infinity;
|
||||
|
||||
virtual void additionalPhysicsProperties() OVERRIDE
|
||||
{
|
||||
m_keep_alive = -1;
|
||||
m_moved_to_infinity = false;
|
||||
}
|
||||
virtual void hideNodeWhenUndoDestruction() OVERRIDE;
|
||||
public:
|
||||
Plunger(AbstractKart *kart);
|
||||
~Plunger();
|
||||
@@ -77,6 +71,10 @@ public:
|
||||
OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void restoreState(BareNetworkString *buffer, int count) OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void onFireFlyable() OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void onDeleteFlyable() OVERRIDE;
|
||||
|
||||
}; // Plunger
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "items/rubber_ball.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/dummy_rewinder.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
|
||||
ProjectileManager *projectile_manager=0;
|
||||
@@ -49,7 +49,6 @@ void ProjectileManager::removeTextures()
|
||||
void ProjectileManager::cleanup()
|
||||
{
|
||||
m_active_projectiles.clear();
|
||||
m_deleted_projectiles.clear();
|
||||
for(HitEffects::iterator i = m_active_hit_effects.begin();
|
||||
i != m_active_hit_effects.end(); ++i)
|
||||
{
|
||||
@@ -106,7 +105,7 @@ void ProjectileManager::updateServer(int ticks)
|
||||
auto p = m_active_projectiles.begin();
|
||||
while (p != m_active_projectiles.end())
|
||||
{
|
||||
if (p->second->isUndoCreation())
|
||||
if (!p->second->hasServerState())
|
||||
{
|
||||
p++;
|
||||
continue;
|
||||
@@ -114,14 +113,15 @@ void ProjectileManager::updateServer(int ticks)
|
||||
bool can_be_deleted = p->second->updateAndDelete(ticks);
|
||||
if (can_be_deleted)
|
||||
{
|
||||
if (!p->second->hasUndoneDestruction())
|
||||
{
|
||||
HitEffect *he = p->second->getHitEffect();
|
||||
if (he)
|
||||
addHitEffect(he);
|
||||
}
|
||||
p->second->handleUndoDestruction();
|
||||
p = m_active_projectiles.erase(p);
|
||||
HitEffect* he = p->second->getHitEffect();
|
||||
if (he)
|
||||
addHitEffect(he);
|
||||
|
||||
p->second->onDeleteFlyable();
|
||||
// Flyables will be deleted by computeError in client
|
||||
if (!NetworkConfig::get()->isNetworking() ||
|
||||
NetworkConfig::get()->isServer())
|
||||
p = m_active_projectiles.erase(p);
|
||||
}
|
||||
else
|
||||
p++;
|
||||
@@ -140,9 +140,12 @@ std::shared_ptr<Flyable>
|
||||
{
|
||||
const std::string& uid = getUniqueIdentity(kart, type);
|
||||
auto it = m_active_projectiles.find(uid);
|
||||
// Flyable already created during rewind
|
||||
// Flyable has already created before and now rewinding, re-fire it
|
||||
if (it != m_active_projectiles.end())
|
||||
{
|
||||
it->second->onFireFlyable();
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::shared_ptr<Flyable> f;
|
||||
switch(type)
|
||||
@@ -162,12 +165,12 @@ std::shared_ptr<Flyable>
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
// This cannot be done in constructor because of virtual function
|
||||
f->onFireFlyable();
|
||||
m_active_projectiles[uid] = f;
|
||||
if (RewindManager::get()->isEnabled())
|
||||
{
|
||||
f->addForRewind(uid);
|
||||
f->addRewindInfoEventFunctionAfterFiring();
|
||||
}
|
||||
|
||||
return f;
|
||||
} // newProjectile
|
||||
|
||||
@@ -184,7 +187,7 @@ bool ProjectileManager::projectileIsClose(const AbstractKart * const kart,
|
||||
for (auto i = m_active_projectiles.begin(); i != m_active_projectiles.end();
|
||||
i++)
|
||||
{
|
||||
if (i->second->isUndoCreation())
|
||||
if (!i->second->hasServerState())
|
||||
continue;
|
||||
float dist2 = i->second->getXYZ().distance2(kart->getXYZ());
|
||||
if (dist2 < r2)
|
||||
@@ -209,7 +212,7 @@ int ProjectileManager::getNearbyProjectileCount(const AbstractKart * const kart,
|
||||
for (auto i = m_active_projectiles.begin(); i != m_active_projectiles.end();
|
||||
i++)
|
||||
{
|
||||
if (i->second->isUndoCreation())
|
||||
if (!i->second->hasServerState())
|
||||
continue;
|
||||
if (i->second->getType() == type)
|
||||
{
|
||||
@@ -255,6 +258,8 @@ std::string ProjectileManager::getUniqueIdentity(AbstractKart* kart,
|
||||
} // getUniqueIdentity
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/* If any flyable is not found in current game state, create it with respect to
|
||||
* its uid as below. */
|
||||
std::shared_ptr<Rewinder>
|
||||
ProjectileManager::addRewinderFromNetworkState(const std::string& uid)
|
||||
{
|
||||
@@ -269,49 +274,40 @@ std::shared_ptr<Rewinder>
|
||||
AbstractKart* kart = World::getWorld()->getKart(world_id);
|
||||
char first_id = id[0][0];
|
||||
|
||||
auto it = m_deleted_projectiles.find(uid);
|
||||
if (it != m_deleted_projectiles.end())
|
||||
{
|
||||
Log::debug("ProjectileManager", "Flyable %s locally (early) deleted,"
|
||||
" use a dummy rewinder to skip.", uid.c_str());
|
||||
return std::make_shared<DummyRewinder>();
|
||||
}
|
||||
|
||||
Log::debug("ProjectileManager",
|
||||
"Missed a firing event, add the flyable %s manually.", uid.c_str());
|
||||
std::shared_ptr<Flyable> f;
|
||||
switch (first_id)
|
||||
{
|
||||
case 'B':
|
||||
{
|
||||
auto f = std::make_shared<Bowling>(kart);
|
||||
f->addForRewind(uid);
|
||||
m_active_projectiles[uid] = f;
|
||||
return f;
|
||||
f = std::make_shared<Bowling>(kart);
|
||||
break;
|
||||
}
|
||||
case 'P':
|
||||
{
|
||||
auto f = std::make_shared<Plunger>(kart);
|
||||
f->addForRewind(uid);
|
||||
m_active_projectiles[uid] = f;
|
||||
return f;
|
||||
f = std::make_shared<Plunger>(kart);
|
||||
break;
|
||||
}
|
||||
case 'C':
|
||||
{
|
||||
auto f = std::make_shared<Cake>(kart);
|
||||
f->addForRewind(uid);
|
||||
m_active_projectiles[uid] = f;
|
||||
return f;
|
||||
f = std::make_shared<Cake>(kart);
|
||||
break;
|
||||
}
|
||||
case 'R':
|
||||
{
|
||||
auto f = std::make_shared<RubberBall>(kart);
|
||||
f->addForRewind(uid);
|
||||
m_active_projectiles[uid] = f;
|
||||
return f;
|
||||
f = std::make_shared<RubberBall>(kart);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
return nullptr;
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(f);
|
||||
f->onFireFlyable();
|
||||
f->addForRewind(uid);
|
||||
m_active_projectiles[uid] = f;
|
||||
return f;
|
||||
} // addProjectileFromNetworkState
|
||||
|
||||
|
||||
@@ -51,8 +51,6 @@ private:
|
||||
* currently moving on the track. */
|
||||
std::map<std::string, std::shared_ptr<Flyable> > m_active_projectiles;
|
||||
|
||||
std::unordered_set<std::string> m_deleted_projectiles;
|
||||
|
||||
/** All active hit effects, i.e. hit effects which are currently
|
||||
* being shown or have a sfx playing. */
|
||||
HitEffects m_active_hit_effects;
|
||||
@@ -91,9 +89,6 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
void removeByUID(const std::string& uid)
|
||||
{ m_active_projectiles.erase(uid); }
|
||||
// ------------------------------------------------------------------------
|
||||
void addDeletedUID(const std::string& uid)
|
||||
{ m_deleted_projectiles.insert(uid); }
|
||||
};
|
||||
|
||||
extern ProjectileManager *projectile_manager;
|
||||
|
||||
@@ -70,10 +70,20 @@ RubberBall::RubberBall(AbstractKart *kart)
|
||||
m_next_id++;
|
||||
m_id = m_next_id;
|
||||
|
||||
m_target = NULL;
|
||||
m_ping_sfx = SFXManager::get()->createSoundSource("ball_bounce");
|
||||
CheckManager::get()->addFlyableToCannons(this);
|
||||
} // RubberBall
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void RubberBall::onFireFlyable()
|
||||
{
|
||||
Flyable::onFireFlyable();
|
||||
// Don't let Flyable update the terrain information, since this object
|
||||
// has to do it earlier than that.
|
||||
setDoTerrainInfo(false);
|
||||
float forw_offset = 0.5f*kart->getKartLength() + m_extend.getZ()*0.5f+5.0f;
|
||||
float forw_offset =
|
||||
0.5f * m_owner->getKartLength() + m_extend.getZ() * 0.5f + 5.0f;
|
||||
|
||||
createPhysics(forw_offset, btVector3(0.0f, 0.0f, m_speed*2),
|
||||
new btSphereShape(0.5f*m_extend.getY()), -70.0f,
|
||||
@@ -84,17 +94,6 @@ RubberBall::RubberBall(AbstractKart *kart)
|
||||
setAdjustUpVelocity(false);
|
||||
m_max_lifespan = stk_config->time2Ticks(9999);
|
||||
m_target = NULL;
|
||||
m_ping_sfx = SFXManager::get()->createSoundSource("ball_bounce");
|
||||
m_owner_init_pos = m_owner->getXYZ();
|
||||
m_init_pos = getXYZ();
|
||||
additionalPhysicsProperties();
|
||||
CheckManager::get()->addFlyableToCannons(this);
|
||||
} // RubberBall
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void RubberBall::additionalPhysicsProperties()
|
||||
{
|
||||
setXYZ(m_init_pos);
|
||||
m_aiming_at_target = false;
|
||||
m_fast_ping = false;
|
||||
// At the start the ball aims at quads till it gets close enough to the
|
||||
@@ -102,8 +101,8 @@ void RubberBall::additionalPhysicsProperties()
|
||||
m_height_timer = 0.0f;
|
||||
m_interval = m_st_interval;
|
||||
m_current_max_height = m_max_height;
|
||||
// Just init the previoux coordinates with some value that's not getXYZ()
|
||||
m_previous_xyz = m_owner_init_pos;
|
||||
// Just init the previous coordinates with some value that's not getXYZ()
|
||||
m_previous_xyz = m_owner->getXYZ();
|
||||
m_previous_height = 2.0f; //
|
||||
// A negative value indicates that the timer is not active
|
||||
m_delete_ticks = -1;
|
||||
@@ -121,17 +120,15 @@ void RubberBall::additionalPhysicsProperties()
|
||||
const Vec3& normal =
|
||||
DriveGraph::get()->getNode(getCurrentGraphNode())->getNormal();
|
||||
TerrainInfo::update(getXYZ(), -normal);
|
||||
initializeControlPoints(m_owner_init_pos);
|
||||
} // additionalPhysicsProperties
|
||||
initializeControlPoints(m_owner->getXYZ());
|
||||
} // onFireFlyable
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Destructor, removes any playing sfx.
|
||||
*/
|
||||
RubberBall::~RubberBall()
|
||||
{
|
||||
if(m_ping_sfx->getStatus()==SFXBase::SFX_PLAYING)
|
||||
m_ping_sfx->stop();
|
||||
m_ping_sfx->deleteSFX();
|
||||
removePingSFX();
|
||||
CheckManager::get()->removeFlyableFromCannons(this);
|
||||
} // ~RubberBall
|
||||
|
||||
@@ -171,29 +168,6 @@ void RubberBall::setAnimation(AbstractKartAnimation *animation)
|
||||
{
|
||||
initializeControlPoints(getXYZ());
|
||||
m_height_timer = 0;
|
||||
if (RewindManager::get()->useLocalEvent())
|
||||
{
|
||||
std::shared_ptr<RubberBall> rb = getShared<RubberBall>();
|
||||
btTransform cur_trans = getTrans();
|
||||
Vec3 cur_previous_xyz = m_previous_xyz;
|
||||
RewindManager::get()->addRewindInfoEventFunction(new
|
||||
RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(),
|
||||
/*undo_function*/[rb]()
|
||||
{
|
||||
rb->m_undo_creation = true;
|
||||
rb->moveToInfinity();
|
||||
},
|
||||
/*replay_function*/[rb, cur_trans, cur_previous_xyz]()
|
||||
{
|
||||
rb->m_undo_creation = false;
|
||||
rb->m_body->setWorldTransform(cur_trans);
|
||||
rb->m_motion_state->setWorldTransform(cur_trans);
|
||||
rb->m_body->setInterpolationWorldTransform(cur_trans);
|
||||
rb->m_previous_xyz = cur_previous_xyz;
|
||||
rb->initializeControlPoints(cur_trans.getOrigin());
|
||||
rb->m_height_timer = 0;
|
||||
}));
|
||||
}
|
||||
}
|
||||
Flyable::setAnimation(animation);
|
||||
} // setAnimation
|
||||
@@ -405,6 +379,7 @@ bool RubberBall::updateAndDelete(int ticks)
|
||||
#ifdef PRINT_BALL_REMOVE_INFO
|
||||
Log::debug("[RubberBall]", "ball %d deleted.", m_id);
|
||||
#endif
|
||||
removePingSFX();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -414,7 +389,10 @@ bool RubberBall::updateAndDelete(int ticks)
|
||||
// Flyable will call update() of the animation to
|
||||
// update the ball's position.
|
||||
m_previous_xyz = getXYZ();
|
||||
return Flyable::updateAndDelete(ticks);
|
||||
bool can_be_deleted = Flyable::updateAndDelete(ticks);
|
||||
if (can_be_deleted)
|
||||
removePingSFX();
|
||||
return can_be_deleted;
|
||||
}
|
||||
|
||||
// Update normal from rewind first
|
||||
@@ -499,13 +477,19 @@ bool RubberBall::updateAndDelete(int ticks)
|
||||
m_previous_height = (getXYZ() - getHitPoint()).length();
|
||||
setXYZ(next_xyz);
|
||||
|
||||
if(checkTunneling())
|
||||
if (checkTunneling())
|
||||
{
|
||||
removePingSFX();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determine new distance along track
|
||||
TrackSector::update(next_xyz);
|
||||
|
||||
return Flyable::updateAndDelete(ticks);
|
||||
bool can_be_deleted = Flyable::updateAndDelete(ticks);
|
||||
if (can_be_deleted)
|
||||
removePingSFX();
|
||||
return can_be_deleted;
|
||||
} // updateAndDelete
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -705,7 +689,7 @@ float RubberBall::updateHeight()
|
||||
if(m_height_timer>m_interval)
|
||||
{
|
||||
m_height_timer -= m_interval;
|
||||
if (m_ping_sfx->getStatus()!=SFXBase::SFX_PLAYING &&
|
||||
if (m_ping_sfx && m_ping_sfx->getStatus()!=SFXBase::SFX_PLAYING &&
|
||||
!RewindManager::get()->isRewinding())
|
||||
{
|
||||
m_ping_sfx->setPosition(getXYZ());
|
||||
@@ -938,3 +922,14 @@ void RubberBall::restoreState(BareNetworkString *buffer, int count)
|
||||
m_aiming_at_target = ((tunnel_and_aiming >> 7) & 1) == 1;
|
||||
TrackSector::rewindTo(buffer);
|
||||
} // restoreState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void RubberBall::removePingSFX()
|
||||
{
|
||||
if (!m_ping_sfx)
|
||||
return;
|
||||
if (m_ping_sfx->getStatus() == SFXBase::SFX_PLAYING)
|
||||
m_ping_sfx->stop();
|
||||
m_ping_sfx->deleteSFX();
|
||||
m_ping_sfx = NULL;
|
||||
} // removePingSFX
|
||||
|
||||
@@ -196,9 +196,6 @@ private:
|
||||
/** A 'ping' sound effect to be played when the ball hits the ground. */
|
||||
SFXBase *m_ping_sfx;
|
||||
|
||||
/* Used by undo and redo the firing when rewind */
|
||||
Vec3 m_owner_init_pos, m_init_pos;
|
||||
|
||||
bool m_restoring_state;
|
||||
|
||||
void computeTarget();
|
||||
@@ -214,7 +211,7 @@ private:
|
||||
float getTunnelHeight(const Vec3 &next_xyz,
|
||||
const float vertical_offset) const;
|
||||
bool checkTunneling();
|
||||
virtual void additionalPhysicsProperties() OVERRIDE;
|
||||
void removePingSFX();
|
||||
|
||||
public:
|
||||
RubberBall (AbstractKart* kart);
|
||||
@@ -233,6 +230,7 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void restoreState(BareNetworkString *buffer, int count) OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void onFireFlyable() OVERRIDE;
|
||||
|
||||
}; // RubberBall
|
||||
|
||||
|
||||
@@ -47,8 +47,6 @@ RubberBand::RubberBand(Plunger *plunger, AbstractKart *kart)
|
||||
{
|
||||
m_hit_kart = NULL;
|
||||
m_attached_state = RB_TO_PLUNGER;
|
||||
updatePosition();
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
if (ProfileWorld::isNoGraphics() || !CVS->isGLSL())
|
||||
{
|
||||
@@ -81,6 +79,14 @@ RubberBand::~RubberBand()
|
||||
remove();
|
||||
} // RubberBand
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void RubberBand::reset()
|
||||
{
|
||||
m_hit_kart = NULL;
|
||||
m_attached_state = RB_TO_PLUNGER;
|
||||
updatePosition();
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Updates the position of the rubber band. It especially sets the
|
||||
* end position of the rubber band, i.e. the side attached to the plunger,
|
||||
|
||||
@@ -71,6 +71,7 @@ private:
|
||||
public:
|
||||
RubberBand(Plunger *plunger, AbstractKart *kart);
|
||||
~RubberBand();
|
||||
void reset();
|
||||
void updateGraphics(float dt);
|
||||
void update(int ticks);
|
||||
void hit(AbstractKart *kart_hit, const Vec3 *track_xyz=NULL);
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
|
||||
Moveable::Moveable()
|
||||
{
|
||||
m_body = 0;
|
||||
m_motion_state = 0;
|
||||
m_node = NULL;
|
||||
m_heading = 0;
|
||||
} // Moveable
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_string.hpp"
|
||||
#include "network/protocols/game_events_protocol.hpp"
|
||||
#include "network/rewind_info.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
#include "network/server_config.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "physics/triangle_mesh.hpp"
|
||||
@@ -488,30 +486,6 @@ void CaptureTheFlag::loseFlagForKart(int kart_id)
|
||||
else
|
||||
m_blue_flag->resetToBase();
|
||||
}
|
||||
if (NetworkConfig::get()->isNetworking() &&
|
||||
NetworkConfig::get()->isClient())
|
||||
{
|
||||
RewindManager::get()->addRewindInfoEventFunction(new
|
||||
RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(),
|
||||
[](){},
|
||||
/*replay_function*/[dropped_trans, drop_red_flag, succeed, this]()
|
||||
{
|
||||
if (drop_red_flag)
|
||||
{
|
||||
if (succeed)
|
||||
m_red_flag->dropFlagAt(dropped_trans);
|
||||
else
|
||||
m_red_flag->resetToBase();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (succeed)
|
||||
m_blue_flag->dropFlagAt(dropped_trans);
|
||||
else
|
||||
m_blue_flag->resetToBase();
|
||||
}
|
||||
}));
|
||||
}
|
||||
} // loseFlagForKart
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "karts/skidding.hpp"
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
|
||||
/** Constructor for a check cannon.
|
||||
* \param node XML node containing the parameters for this checkline.
|
||||
@@ -158,8 +157,8 @@ void CheckCannon::update(float dt)
|
||||
CheckLine::update(dt);
|
||||
for (unsigned int i = 0; i < m_all_flyables.size(); i++)
|
||||
{
|
||||
if (m_all_flyables[i]->hasUndoneDestruction() ||
|
||||
RewindManager::get()->isRewinding())
|
||||
if (!m_all_flyables[i]->hasServerState() ||
|
||||
m_all_flyables[i]->hasAnimation())
|
||||
continue;
|
||||
setIgnoreHeight(true);
|
||||
bool triggered = isTriggered(m_flyable_previous_position[i],
|
||||
@@ -176,6 +175,7 @@ void CheckCannon::update(float dt)
|
||||
//m_all_flyables[i]->setAnimation(animation);
|
||||
} // for i in all flyables
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called when the check line is triggered. This function creates a cannon
|
||||
* animation object and attaches it to the kart.
|
||||
|
||||
Reference in New Issue
Block a user