Redo swatter for network

This commit is contained in:
Benau 2019-03-02 16:41:32 +08:00
parent 17fd68e662
commit 9b8b0b7c1e
8 changed files with 296 additions and 243 deletions

View File

@ -43,6 +43,8 @@
#include "tracks/track.hpp"
#include "utils/constants.hpp"
#include <IAnimatedMeshSceneNode.h>
/** Initialises the attachment each kart has.
*/
Attachment::Attachment(AbstractKart* kart)
@ -70,7 +72,6 @@ Attachment::Attachment(AbstractKart* kart)
std::string debug_name = kart->getIdent()+" (attachment)";
m_node->setName(debug_name.c_str());
#endif
m_node->setAnimationEndCallback(this);
m_node->setParent(m_kart->getNode());
m_node->setVisible(false);
} // Attachment
@ -109,46 +110,19 @@ Attachment::~Attachment()
*/
void Attachment::set(AttachmentType type, int ticks,
AbstractKart *current_kart,
bool disable_swatter_animation,
bool set_by_rewind_parachute)
{
bool was_bomb = m_type == ATTACH_BOMB;
// Don't override currently player swatter removing bomb animation
/*Swatter* s = dynamic_cast<Swatter*>(m_plugin);
if (s && s->isRemovingBomb())
return;
bool was_bomb = (m_type == ATTACH_BOMB) && !disable_swatter_animation;
scene::ISceneNode* bomb_scene_node = NULL;
if (was_bomb && type == ATTACH_SWATTER)
{
// let's keep the bomb node, and create a new one for
// the new attachment
bomb_scene_node = m_node;
m_node = irr_driver->addAnimatedMesh(
attachment_manager->getMesh(Attachment::ATTACH_BOMB), "bomb");
#ifdef DEBUG
std::string debug_name = m_kart->getIdent() + " (attachment)";
m_node->setName(debug_name.c_str());
#endif
m_node->setAnimationEndCallback(this);
m_node->setParent(m_kart->getNode());
m_node->setVisible(false);
}*/
int16_t prev_ticks = m_ticks_left;
clear();
// If necessary create the appropriate plugin which encapsulates
// the associated behavior
switch(type)
{
case ATTACH_SWATTER :
//if (m_kart->getIdent() == "nolok")
// m_node->setMesh(attachment_manager->getMesh(ATTACH_NOLOKS_SWATTER));
//else
// m_node->setMesh(attachment_manager->getMesh(type));
//m_plugin = new Swatter(m_kart, was_bomb, bomb_scene_node, ticks);
case ATTACH_SWATTER:
m_plugin =
new Swatter(m_kart, was_bomb ? prev_ticks : -1, ticks, this);
break;
default:
break;
@ -214,14 +188,12 @@ void Attachment::clear(bool update_graphical_now)
void Attachment::saveState(BareNetworkString *buffer) const
{
// We use bit 6 to indicate if a previous owner is defined for a bomb,
// bit 7 to indicate if the attachment is swatter removing animation
// bit 7 to indicate if the attachment is a plugin
assert(ATTACH_MAX < 64);
uint8_t bit_7 = 0;
Swatter* s = dynamic_cast<Swatter*>(m_plugin);
if (s)
if (m_plugin)
{
bit_7 = s->isRemovingBomb() ? 1 : 0;
bit_7 <<= 7;
bit_7 = 1 << 7;
}
uint8_t type = m_type | (( (m_type==ATTACH_BOMB) && (m_previous_owner!=NULL) )
? (1 << 6) : 0 ) | bit_7;
@ -233,6 +205,8 @@ void Attachment::saveState(BareNetworkString *buffer) const
buffer->addUInt8(m_previous_owner->getWorldKartId());
// m_initial_speed is not saved, on restore state it will
// be set to the kart speed, which has already been restored
if (m_plugin)
m_plugin->saveState(buffer);
}
} // saveState
@ -243,19 +217,14 @@ void Attachment::saveState(BareNetworkString *buffer) const
void Attachment::rewindTo(BareNetworkString *buffer)
{
uint8_t type = buffer->getUInt8();
bool is_removing_bomb = (type >> 7 & 1) == 1;
Swatter* s = dynamic_cast<Swatter*>(m_plugin);
// If locally removing a bomb
if (s)
is_removing_bomb = s->isRemovingBomb();
bool is_plugin = (type >> 7 & 1) == 1;
// mask out bit 6 and 7
AttachmentType new_type = AttachmentType(type & 63);
type &= 127;
// If there is no attachment, clear the attachment if necessary and exit
if (new_type == ATTACH_NOTHING && !is_removing_bomb)
if (new_type == ATTACH_NOTHING)
{
if (m_type != new_type)
clear();
@ -277,9 +246,18 @@ void Attachment::rewindTo(BareNetworkString *buffer)
m_previous_owner = NULL;
}
// If playing kart animation, don't rewind to any attacment
if (is_removing_bomb)
return;
if (is_plugin)
{
if (!m_plugin)
m_plugin = new Swatter(m_kart, -1, 0, this);
m_plugin->restoreState(buffer);
}
else
{
// Remove unconfirmed plugin
delete m_plugin;
m_plugin = NULL;
}
m_type = new_type;
m_ticks_left = ticks_left;
@ -475,17 +453,10 @@ void Attachment::update(int ticks)
if (m_plugin)
{
int discard_ticks = m_plugin->updateAndTestFinished(ticks);
if (discard_ticks != -1)
if (m_plugin->updateAndTestFinished(ticks))
{
// Save it for rewinding
m_ticks_left =
discard_ticks - World::getWorld()->getTicksSinceStart();
if (m_ticks_left <= 0)
{
clear(); // also removes the plugin
return;
}
clear(); // also removes the plugin
return;
}
}
@ -555,7 +526,11 @@ void Attachment::updateGraphics(float dt)
// Add the suitable graphical effects if different attachment is set
if (m_type != m_graphical_type)
{
// Old attachement is cleared, add suitable sfx effects
// Attachement is different, reset and add suitable sfx effects
m_node->setPosition(core::vector3df(0.0f, 0.0f, 0.0f));
m_node->setRotation(core::vector3df(0.0f, 0.0f, 0.0f));
m_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f));
m_node->setLoopMode(true);
switch (m_type)
{
case ATTACH_NOTHING:
@ -605,6 +580,9 @@ void Attachment::updateGraphics(float dt)
m_graphical_type = m_type;
}
if (m_plugin)
m_plugin->updateGrahpics(dt);
if (m_type != ATTACH_NOTHING)
{
m_node->setVisible(true);
@ -644,9 +622,6 @@ void Attachment::updateGraphics(float dt)
else
m_node->setVisible(false);
if (m_plugin)
m_plugin->updateGrahpics(dt);
switch (m_type)
{
case ATTACH_BOMB:
@ -690,11 +665,3 @@ float Attachment::weightAdjust() const
? m_kart->getKartProperties()->getAnvilWeight()
: 0.0f;
} // weightAdjust
// ----------------------------------------------------------------------------
/** Inform any eventual plugin when an animation is done. */
void Attachment::OnAnimationEnd(scene::IAnimatedMeshSceneNode* node)
{
if(m_plugin)
m_plugin->onAnimationEnd();
} // OnAnimationEnd

View File

@ -19,13 +19,16 @@
#ifndef HEADER_ATTACHMENT_HPP
#define HEADER_ATTACHMENT_HPP
#include "config/stk_config.hpp"
#include "items/attachment_plugin.hpp"
#include "utils/no_copy.hpp"
#include <IAnimatedMeshSceneNode.h>
using namespace irr;
namespace irr
{
namespace scene { class IAnimatedMeshSceneNode; }
}
class AbstractKart;
class BareNetworkString;
class ItemState;
@ -44,7 +47,7 @@ class SFXBase;
* a scene node).
* \ingroup items
*/
class Attachment: public NoCopy, public scene::IAnimationEndCallBack
class Attachment: public NoCopy
{
public:
// Some loop in attachment.cpp depend on ATTACH_FIRST and ATTACH_MAX.
@ -124,7 +127,6 @@ public:
void handleCollisionWithKart(AbstractKart *other);
void set (AttachmentType type, int ticks,
AbstractKart *previous_kart=NULL,
bool disable_swatter_animation = false,
bool set_by_rewind_parachute = false);
void rewindTo(BareNetworkString *buffer);
void saveState(BareNetworkString *buffer) const;
@ -153,13 +155,6 @@ public:
/** Return the currently associated scene node (used by e.g the swatter) */
scene::IAnimatedMeshSceneNode* getNode() {return m_node;}
// ------------------------------------------------------------------------
/** Implement IAnimatedMeshSceneNode */
virtual void OnAnimationEnd(scene::IAnimatedMeshSceneNode* node);
// ------------------------------------------------------------------------
/** Nothing to undo when going back during a rewind, the full state info
* will take care of creating the right attachment. */
virtual void undo(BareNetworkString *buffer) { }
// ------------------------------------------------------------------------
void reset()
{
clear();

View File

@ -23,6 +23,7 @@
class AbstractKart;
class Attachment;
class BareNetworkString;
/**
* \ingroup items
@ -38,13 +39,15 @@ class AttachmentPlugin
{
protected:
/** Kart the attachment is attached to. */
AbstractKart *m_kart;
AbstractKart* m_kart;
Attachment* m_attachment;
public:
/** Constructor for a plugin. */
AttachmentPlugin(AbstractKart *kart)
AttachmentPlugin(AbstractKart *kart, Attachment* attachment)
{
m_kart = kart;
m_kart = kart;
m_attachment = attachment;
}
virtual ~AttachmentPlugin() {}
@ -53,13 +56,13 @@ public:
// ------------------------------------------------------------------------
/** Updates a plugin. This is called once each time frame. If the
* function returns a non-negative number, the attachment is discarded
* when world ticks >= that number. */
virtual int updateAndTestFinished(int ticks) = 0;
* function returns true, the attachment is discarded. */
virtual bool updateAndTestFinished(int ticks) = 0;
// ------------------------------------------------------------------------
/** Called when the animation of the Attachment's node is done. */
virtual void onAnimationEnd() {}
virtual void restoreState(BareNetworkString *buffer) {}
// ------------------------------------------------------------------------
virtual void saveState(BareNetworkString *buffer) const {}
}; // AttachmentPlugin
#endif

View File

@ -40,8 +40,7 @@
#include "karts/explosion_animation.hpp"
#include "karts/kart_properties.hpp"
#include "modes/capture_the_flag.hpp"
#include "network/network_config.hpp"
#include "network/rewind_info.hpp"
#include "network/network_string.hpp"
#include "network/rewind_manager.hpp"
#define SWAT_POS_OFFSET core::vector3df(0.0, 0.2f, -0.4f)
@ -50,59 +49,39 @@
#define SWAT_ANGLE_OFFSET (90.0f + 15.0f)
#define SWATTER_ANIMATION_SPEED 100.0f
// ----------------------------------------------------------------------------
/** Constructor: creates a swatter at a given attachment for a kart. If there
* was a bomb attached, it triggers the replace bomb animations.
* \param attachment The attachment instance where the swatter is attached to.
* \param kart The kart to which the swatter is attached.
* \param was_bomb True if the kart had a bomb as attachment.
* \param bomb_scene_node The scene node of the bomb (i.e. the previous
* attachment scene node).
* \param bomb_ticks Remaining bomb time in ticks, -1 if none.
* \param ticks Swatter duration.
* \param attachment class attachment from karts.
*/
Swatter::Swatter(AbstractKart *kart, bool was_bomb,
scene::ISceneNode* bomb_scene_node, int ticks)
: AttachmentPlugin(kart),
m_swatter_start_ticks(World::getWorld()->getTicksSinceStart()),
m_swatter_end_ticks(World::getWorld()->getTicksSinceStart() + ticks)
Swatter::Swatter(AbstractKart *kart, int16_t bomb_ticks, int ticks,
Attachment* attachment)
: AttachmentPlugin(kart, attachment)
{
m_animation_phase = SWATTER_AIMING;
m_discard_now = false;
m_target = NULL;
m_closest_kart = NULL;
m_bomb_scene_node = bomb_scene_node;
m_swat_bomb_frame = 0.0f;
// Setup the node
m_scene_node = kart->getAttachment()->getNode();
m_scene_node->setPosition(SWAT_POS_OFFSET);
if (was_bomb)
m_discard_ticks = World::getWorld()->getTicksSinceStart() + ticks;
m_bomb_remaining = bomb_ticks;
m_scene_node = NULL;
m_bomb_scene_node = NULL;
m_swatter_duration = stk_config->time2Ticks(
kart->getKartProperties()->getSwatterDuration());
if (m_bomb_remaining != -1)
{
m_scene_node->setMesh(attachment_manager
->getMesh(Attachment::ATTACH_SWATTER_ANIM));
m_scene_node->setRotation(core::vector3df(0.0, -180.0, 0.0));
m_scene_node->setAnimationSpeed(0.9f);
m_scene_node->setCurrentFrame(0.0f);
m_scene_node->setLoopMode(false);
// There are 40 frames in blender for swatter_anim.blender
// so 40 / 25 * 120
m_removed_bomb_ticks =
World::getWorld()->getTicksSinceStart() + 192;
m_discard_ticks =
World::getWorld()->getTicksSinceStart() +
stk_config->time2Ticks(40.0f / 25.0f);
}
else
{
m_removed_bomb_ticks = std::numeric_limits<int>::max();
m_scene_node->setAnimationSpeed(0);
}
m_swat_sound = NULL;
m_start_swat_ticks = std::numeric_limits<int>::max();
m_end_swat_ticks = std::numeric_limits<int>::max();
#ifndef SERVER_ONLY
if (kart->getIdent() == "nolok")
m_swat_sound = SFXManager::get()->createSoundSource("hammer");
else
m_swat_sound = SFXManager::get()->createSoundSource("swatter");
#endif
m_swatter_animation_ticks = 0;
m_played_swatter_animation = false;
} // Swatter
// ----------------------------------------------------------------------------
@ -127,55 +106,139 @@ Swatter::~Swatter()
void Swatter::updateGrahpics(float dt)
{
#ifndef SERVER_ONLY
if (m_removed_bomb_ticks != std::numeric_limits<int>::max())
if (m_bomb_remaining != -1)
{
m_swat_bomb_frame += dt*25.0f;
m_scene_node->setRotation(core::vector3df(0.0, -180.0, 0.0));
m_scene_node->setCurrentFrame(m_swat_bomb_frame);
if (m_swat_bomb_frame >= 32.5f && m_bomb_scene_node != NULL)
if (!m_scene_node)
{
m_bomb_scene_node->setPosition(m_bomb_scene_node
->getPosition() + core::vector3df(-dt*15.0f, 0.0f, 0.0f) );
m_bomb_scene_node->setRotation(m_bomb_scene_node
->getRotation() + core::vector3df(-dt*15.0f, 0.0f, 0.0f) );
m_scene_node = m_kart->getAttachment()->getNode();
m_scene_node->setPosition(SWAT_POS_OFFSET);
m_scene_node->setMesh(attachment_manager
->getMesh(Attachment::ATTACH_SWATTER_ANIM));
m_scene_node->setRotation(core::vector3df(0.0, -180.0, 0.0));
m_scene_node->setAnimationSpeed(0.9f);
m_scene_node->setCurrentFrame(0.0f);
m_scene_node->setLoopMode(false);
}
if (m_swat_bomb_frame >= m_scene_node->getEndFrame())
if (!m_bomb_scene_node)
{
return;
}
else if (m_swat_bomb_frame >= 35)
{
if (m_bomb_scene_node != NULL)
m_bomb_scene_node = irr_driver->addAnimatedMesh(
attachment_manager->getMesh(Attachment::ATTACH_BOMB), "bomb");
#ifdef DEBUG
std::string debug_name = m_kart->getIdent() + " (attachment)";
m_bomb_scene_node->setName(debug_name.c_str());
#endif
m_bomb_scene_node->setParent(m_kart->getNode());
float time_left = stk_config->ticks2Time(m_bomb_remaining);
if (time_left <= (m_bomb_scene_node->getEndFrame() -
m_bomb_scene_node->getStartFrame() - 1))
{
irr_driver->removeNode(m_bomb_scene_node);
m_bomb_scene_node = NULL;
m_bomb_scene_node->setCurrentFrame(
m_bomb_scene_node->getEndFrame()
- m_bomb_scene_node->getStartFrame() - 1 - time_left);
}
m_bomb_scene_node->setAnimationSpeed(0.0f);
}
float swat_bomb_frame = stk_config->ticks2Time(
World::getWorld()->getTicksSinceStart() -
(m_discard_ticks - stk_config->time2Ticks(40.0f / 25.0f)))
* 25.0f;
if (swat_bomb_frame >= (float)m_scene_node->getEndFrame())
swat_bomb_frame = (float)m_scene_node->getEndFrame();
m_scene_node->setRotation(core::vector3df(0.0, -180.0, 0.0));
m_scene_node->setCurrentFrame(swat_bomb_frame);
if (swat_bomb_frame >= 32.5f && m_bomb_scene_node != NULL)
{
m_bomb_scene_node->setPosition(
core::vector3df(-(swat_bomb_frame - 32.5f), 0.0f, 0.0f));
m_bomb_scene_node->setRotation(
core::vector3df(-(swat_bomb_frame - 32.5f), 0.0f, 0.0f));
}
if (swat_bomb_frame >= 35)
{
m_bomb_scene_node->setVisible(false);
} // bom_frame > 35
} // if removing bomb
else
{
if (!m_scene_node)
{
m_scene_node = m_kart->getAttachment()->getNode();
if (m_kart->getIdent() == "nolok")
{
m_scene_node->setMesh(attachment_manager
->getMesh(Attachment::ATTACH_NOLOKS_SWATTER));
}
else
{
m_scene_node->setMesh(attachment_manager
->getMesh(Attachment::ATTACH_SWATTER));
}
m_scene_node->setPosition(SWAT_POS_OFFSET);
m_scene_node->setLoopMode(false);
m_scene_node->setAnimationSpeed(0.0f);
}
if (!m_swat_sound)
{
if (m_kart->getIdent() == "nolok")
m_swat_sound = SFXManager::get()->createSoundSource("hammer");
else
m_swat_sound = SFXManager::get()->createSoundSource("swatter");
}
if (!m_discard_now)
{
switch (m_animation_phase)
{
case SWATTER_AIMING:
{
pointToTarget();
m_played_swatter_animation = false;
}
break;
case SWATTER_TO_TARGET:
{
if (!m_played_swatter_animation)
{
m_played_swatter_animation = true;
// Setup the animation
m_scene_node->setCurrentFrame(0.0f);
m_scene_node->setAnimationSpeed(SWATTER_ANIMATION_SPEED);
Vec3 swatter_pos =
m_kart->getTrans()(Vec3(SWAT_POS_OFFSET));
m_swat_sound->setPosition(swatter_pos);
m_swat_sound->play();
}
pointToTarget();
}
break;
case SWATTER_FROM_TARGET:
break;
}
}
}
#endif
} // updateGrahpics
// ----------------------------------------------------------------------------
/** Updates an armed swatter: it checks for any karts that are close enough
* and not invulnerable, it swats the kart.
* \param dt Time step size.
* \return World ticks to discard the swatter.
* \param ticks Time step size.
* \return True if the attachment should be discarded.
*/
int Swatter::updateAndTestFinished(int ticks)
bool Swatter::updateAndTestFinished(int ticks)
{
const int ticks_start = World::getWorld()->getTicksSinceStart();
if (m_removed_bomb_ticks != std::numeric_limits<int>::max())
{
if (ticks_start >= m_removed_bomb_ticks)
return m_removed_bomb_ticks;
return -1;
} // if removing bomb
if (World::getWorld()->getTicksSinceStart() > m_discard_ticks)
return true;
if (RewindManager::get()->isRewinding())
return -1;
// If removing bomb animation playing, it will only ends when
// m_discard_ticks > world ticks
if (m_bomb_remaining != -1)
return false;
if (!m_discard_now)
{
@ -185,13 +248,13 @@ int Swatter::updateAndTestFinished(int ticks)
{
// Avoid swatter near the start and the end lifetime of swatter
// to make sure all clients know the existence of swatter each other
if (ticks_start - m_swatter_start_ticks < 60 ||
m_swatter_end_ticks - ticks_start < 60)
return -1;
if (m_swatter_duration - m_attachment->getTicksLeft() < 60 ||
m_attachment->getTicksLeft() < 90) // ~20 and ~60 below
return false;
chooseTarget();
pointToTarget();
if(!m_target || !m_closest_kart) break;
if (!m_closest_kart)
break;
// Get the node corresponding to the joint at the center of the
// swatter (by swatter, I mean the thing hold in the hand, not
@ -212,61 +275,45 @@ int Swatter::updateAndTestFinished(int ticks)
{
// Start squashing
m_animation_phase = SWATTER_TO_TARGET;
m_start_swat_ticks = ticks_start + 20;
// Setup the animation
m_scene_node->setCurrentFrame(0.0f);
m_scene_node->setLoopMode(false);
m_scene_node->setAnimationSpeed(SWATTER_ANIMATION_SPEED);
#ifndef SERVER_ONLY
// Play swat sound
m_swat_sound->setPosition(swatter_pos);
m_swat_sound->play();
#endif
m_swatter_animation_ticks =
m_attachment->getTicksLeft() - 20;
}
}
break;
case SWATTER_TO_TARGET:
{
pointToTarget();
// Did we just finish the first part of the movement?
if (ticks_start > m_start_swat_ticks)
if (m_attachment->getTicksLeft() < m_swatter_animation_ticks &&
m_attachment->getTicksLeft() > 60)
{
m_start_swat_ticks = std::numeric_limits<int>::max();
// Squash the karts and items around and
// change the current phase
squashThingsAround();
m_animation_phase = SWATTER_FROM_TARGET;
const int end_ticks = ticks_start + 60;
if (race_manager->isBattleMode() ||
race_manager
->getMinorMode()==RaceManager::MINOR_MODE_SOCCER)
race_manager->isSoccerMode())
{
// Remove swatter from kart in arena gameplay
// after one successful hit
m_discard_now = true;
m_discard_ticks = end_ticks;
}
m_end_swat_ticks = end_ticks;
m_swatter_animation_ticks =
m_attachment->getTicksLeft() - 60;
}
}
break;
case SWATTER_FROM_TARGET:
{
if (m_attachment->getTicksLeft() < m_swatter_animation_ticks &&
m_attachment->getTicksLeft() > 0)
m_animation_phase = SWATTER_AIMING;
break;
}
}
}
if (m_discard_now)
{
return m_end_swat_ticks;
}
else if (ticks_start > m_end_swat_ticks)
{
m_animation_phase = SWATTER_AIMING;
m_end_swat_ticks = std::numeric_limits<int>::max();
return -1;
}
return -1;
return false;
} // updateAndTestFinished
// ----------------------------------------------------------------------------
@ -303,8 +350,11 @@ void Swatter::chooseTarget()
closest_kart = kart;
}
}
m_target = closest_kart; // may be NULL
m_closest_kart = closest_kart;
// Not larger than 2^5 - 1 for kart id for optimizing state saving
if (closest_kart->getWorldKartId() < 31)
m_closest_kart = closest_kart;
else
m_closest_kart = NULL;
}
// ----------------------------------------------------------------------------
@ -313,16 +363,17 @@ void Swatter::chooseTarget()
void Swatter::pointToTarget()
{
#ifndef SERVER_ONLY
if (m_kart->isGhostKart()) return;
if (m_kart->isGhostKart() || !m_scene_node)
return;
if(!m_target)
if (!m_closest_kart)
{
m_scene_node->setRotation(core::vector3df());
}
else
{
Vec3 swatter_to_target =
m_kart->getTrans().inverse()(m_target->getXYZ());
m_kart->getTrans().inverse()(m_closest_kart->getXYZ());
float dy = -swatter_to_target.getZ();
float dx = swatter_to_target.getX();
float angle = SWAT_ANGLE_OFFSET + atan2f(dy, dx) * 180 / M_PI;
@ -341,28 +392,13 @@ void Swatter::squashThingsAround()
const KartProperties *kp = m_kart->getKartProperties();
AbstractKart* closest_kart = m_closest_kart;
float duration = kp->getSwatterSquashDuration();
float slowdown = kp->getSwatterSquashSlowdown();
// The squash attempt may fail because of invulnerability, shield, etc.
// Making a bomb explode counts as a success
bool success = closest_kart->setSquash(duration, slowdown);
bool success = m_closest_kart->setSquash(duration, slowdown);
const bool has_created_explosion_animation =
success && closest_kart->getKartAnimation() != NULL;
// Locally add a event to replay the squash during rewind
if (NetworkConfig::get()->isNetworking() &&
NetworkConfig::get()->isClient() &&
closest_kart->getKartAnimation() == NULL)
{
RewindManager::get()->addRewindInfoEventFunction(new
RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(),
/*undo_function*/[](){},
/*replay_function*/[closest_kart, duration, slowdown]()
{
closest_kart->setSquash(duration, slowdown);
}));
}
success && m_closest_kart->getKartAnimation() != NULL;
if (success)
{
@ -390,7 +426,7 @@ void Swatter::squashThingsAround()
}
}
if (has_created_explosion_animation)
if (has_created_explosion_animation && !RewindManager::get()->isRewinding())
{
HitEffect *he = new Explosion(m_kart->getXYZ(), "explosion", "explosion.xml");
if(m_kart->getController()->isLocalPlayerController())
@ -400,3 +436,52 @@ void Swatter::squashThingsAround()
// TODO: squash items
} // squashThingsAround
// ----------------------------------------------------------------------------
void Swatter::restoreState(BareNetworkString* buffer)
{
int16_t prev_bomb_remaing = m_bomb_remaining;
m_bomb_remaining = buffer->getUInt16();
if (prev_bomb_remaing != m_bomb_remaining)
{
// Wrong state, clear mesh and let updateGraphics reset itself
m_scene_node = NULL;
if (m_bomb_scene_node)
{
irr_driver->removeNode(m_bomb_scene_node);
m_bomb_scene_node = NULL;
}
}
if (m_bomb_remaining == -1)
{
uint8_t combined = buffer->getUInt8();
int kart_id = combined & 31;
if (kart_id == 31)
m_closest_kart = NULL;
else
m_closest_kart = World::getWorld()->getKart(kart_id);
m_animation_phase = AnimationPhase((combined >> 5) & 3);
m_discard_now = (combined >> 7) == 1;
m_discard_ticks = buffer->getUInt32();
m_swatter_animation_ticks = buffer->getUInt16();
}
else
m_discard_ticks = buffer->getUInt32();
} // restoreState
// ----------------------------------------------------------------------------
void Swatter::saveState(BareNetworkString* buffer) const
{
buffer->addUInt16(m_bomb_remaining);
if (m_bomb_remaining == -1)
{
uint8_t combined =
m_closest_kart ? (uint8_t)m_closest_kart->getWorldKartId() : 31;
combined |= m_animation_phase << 5;
combined |= (m_discard_now ? (1 << 7) : 0);
buffer->addUInt8(combined).addUInt32(m_discard_ticks)
.addUInt16(m_swatter_animation_ticks);
}
else
buffer->addUInt32(m_discard_ticks);
} // saveState

View File

@ -31,6 +31,7 @@
using namespace irr;
class Attachment;
class AbstractKart;
class Item;
class Moveable;
@ -48,46 +49,49 @@ private:
* - going down to the target
* - going up from the target
*/
enum {SWATTER_AIMING, SWATTER_TO_TARGET, SWATTER_FROM_TARGET}
m_animation_phase;
/** True if the swatter will be discarded now. */
bool m_discard_now;
enum AnimationPhase : uint8_t
{
SWATTER_AIMING = 0,
SWATTER_TO_TARGET = 1,
SWATTER_FROM_TARGET = 2
};
AnimationPhase m_animation_phase;
/** The kart the swatter is aiming at. */
Moveable *m_target;
AbstractKart *m_closest_kart;
SFXBase *m_swat_sound;
/** Set the end ticks to complete the removing an attached bomb animation. */
int m_removed_bomb_ticks;
/** The scene node of the attachment. */
scene::IAnimatedMeshSceneNode *m_scene_node;
/** The scene node where a bomb is saved (in case that the swatter
* replaces a bomb. */
scene::ISceneNode *m_bomb_scene_node;
scene::IAnimatedMeshSceneNode *m_bomb_scene_node;
/** For some reason the built-in animation system doesn't work correctly here?? */
float m_swat_bomb_frame;
int m_discard_ticks;
int m_start_swat_ticks;
int m_swatter_duration;
int m_end_swat_ticks;
/** Set the bomb remaing ticks so we can set the timer on the removing
* bomb animation. */
int16_t m_bomb_remaining;
const int m_swatter_start_ticks;
int16_t m_swatter_animation_ticks;
const int m_swatter_end_ticks;
/** True if the swatter will be discarded now. */
bool m_discard_now;
/** True if the swatter animation has been played. */
bool m_played_swatter_animation;
public:
Swatter(AbstractKart *kart, bool was_bomb,
scene::ISceneNode* bomb_scene_node, int ticks);
Swatter(AbstractKart *kart, int16_t bomb_ticks, int ticks,
Attachment* attachment);
virtual ~Swatter();
void updateGrahpics(float dt) OVERRIDE;
int updateAndTestFinished(int ticks) OVERRIDE;
bool updateAndTestFinished(int ticks) OVERRIDE;
// ------------------------------------------------------------------------
/** Returns if the swatter is currently aiming, i.e. can be used to
@ -97,10 +101,9 @@ public:
return m_animation_phase == SWATTER_AIMING;
} // isSwatterReady
// ------------------------------------------------------------------------
bool isRemovingBomb() const
{
return m_removed_bomb_ticks != std::numeric_limits<int>::max();
}
virtual void restoreState(BareNetworkString *buffer) OVERRIDE;
// ------------------------------------------------------------------------
virtual void saveState(BareNetworkString *buffer) const OVERRIDE;
private:
/** Determine the nearest kart or item and update the current target accordingly */

View File

@ -169,7 +169,6 @@ void GhostKart::update(int ticks)
else if (attach_type != m_attachment->getType())
{
m_attachment->set(attach_type, attach_ticks, NULL,
/*disable_swatter_animation*/false,
/*set_by_rewind_parachute*/true);
}

View File

@ -354,7 +354,7 @@ void Kart::reset()
m_saved_controller = NULL;
}
m_kart_model->setAnimation(KartModel::AF_DEFAULT);
m_attachment->clear();
m_attachment->reset();
m_kart_gfx->reset();
m_skidding->reset();

View File

@ -37,6 +37,7 @@
#include "physics/btKart.hpp"
#include "utils/vec3.hpp"
#include <ISceneNode.h>
#include <string.h>
KartRewinder::KartRewinder(const std::string& ident,